=====Using 16-bit floating point values=====
//by Richard Russell, August 2007//\\ \\ //BBC BASIC for Windows// stores floating point numbers in 40-bit and 64-bit resolutions and has no built-in support for 16-bit (half precision) floating point numbers. [[http://en.wikipedia.org/wiki/Half_precision|Half precision]] floats are sometimes used in graphics applications, including OpenGL and Direct3D, because they are an efficient method of representing luminance and chrominance levels with a high dynamic range.\\ \\ The following three functions may be used to perform the necessary conversions:\\ \\
* **FN_ConvertToHalf** converts a number to a half-precision floating point value
* **FN_ConvertToHalfRounded** converts a number to half precision with rounding
* **FN_ConvertFromHalf** converts a number from a half-precision floating point value
\\ The difference between **FN_ConvertToHalf** and **FN_ConvertToHalfRounded** is that the former truncates towards zero, but is slightly faster, whereas the latter generates the half-precision number which is nearest to the supplied value, but is slightly slower. Use **FN_ConvertToHalf** if you know that the value can be converted exactly into half precision (for example it was returned from **FN_ConvertFromHalf**) or if you are not too concerned about accuracy. Use **FN_ConvertToHalfRounded** otherwise.\\ \\
DEF FN_ConvertFromHalf(A%)
LOCAL A#
IF (A% AND &7C00) = 0 THEN = SGN(A% << 16) * (A% AND &3FF) * 2^-24
!(^A#+4) = ((A% AND &8000) << 16) + ((A% AND &7FFF) << 10) + &3F000000
= A#
DEF FN_ConvertToHalf(A#)
LOCAL A%
IF ABSA# < 2^-14 THEN = (A# < 0 AND &8000) OR (ABSA# / 2^-24)
A# /= 65536.0# : A% = !(^A#+4)
= ((A% >> 16) AND &8000) + ((A% >> 10) AND &7FFF)
DEF FN_ConvertToHalfRounded(A#)
LOCAL A%
IF ABSA# < 2^-14 THEN = (A# < 0 AND &8000) OR (ABSA# / 2^-24 + 0.5)
A# /= 65536.0# : A% = !(^A#+4)
= ((A% >> 16) AND &8000) + ((A% >> 10) AND &7FFF) + ((A% >> 9) AND 1)
Note that **FN_ConvertToHalf** and **FN_ConvertToHalfRounded** perform //no range checking// to ensure that the value you pass can be represented as a valid half-precision number. If this is important you can add a check as follows:\\ \\
DEF FN_ConvertToHalf(A#)
LOCAL A%
IF ABSA# >= 2^16 THEN ERROR 20, "Number too big"
IF ABSA# < 2^-14 THEN = (A# < 0 AND &8000) OR (ABSA# / 2^-24)
A# /= 65536.0# : A% = !(^A#+4)
= ((A% >> 16) AND &8000) + ((A% >> 10) AND &7FFF)
DEF FN_ConvertToHalfRounded(A#)
LOCAL A%
IF ABSA# >= &FFF0 THEN ERROR 20, "Number too big"
IF ABSA# < 2^-14 THEN = (A# < 0 AND &8000) OR (ABSA# / 2^-24 + 0.5)
A# /= 65536.0# : A% = !(^A#+4)
= ((A% >> 16) AND &8000) + ((A% >> 10) AND &7FFF) + ((A% >> 9) AND 1)
In all cases the 16-bit half-precision value is passed in the least-significant 16-bits of a 32-bit integer.