Using+32-bit+floating+point+values

//by Jon Ripley, August 2006//

//BBC BASIC for Windows// stores floating point numbers in 40-bit and 64-bit resolutions and has no built-in support for 32-bit (single precision) floating point numbers. When using the Windows API and functions in third party DLLs it is sometimes necessary to use 32-bit floating point numbers. To ensure that single precision numbers are correctly passed to **SYS** calls they must be stored in integer variables which are also 32-bits wide.

The following two functions are required to perform the necessary conversions:


 * **FN_ConvertToSingle** converts a number to a single precision floating point value
 * **FN_ConvertFromSingle** converts a number from a single precision floating point value

code format="bb4w" DEF FN_ConvertToSingle(A#) LOCAL A%,P% PRIVATE F%     IF F%=0 THEN DIM P% 10 [OPT 2 .F%       mov esi,[ebp+2]   ; esi = pointer to A#        mov edi,[ebp+7]   ; edi = pointer to A%        fld qword [esi]   ; load indirect 64 bit real from esi fstp dword [edi] ; store indirect 32 bit real to edi ret ]     ENDIF A#*=1.0# CALL F%,A#,A% =A%

DEF FN_ConvertFromSingle(A%) LOCAL A#,P% PRIVATE F%     IF F%=0 THEN DIM P% 10 [OPT 2 .F%       mov esi,[ebp+2]   ; esi = pointer to A%        mov edi,[ebp+7]   ; edi = pointer to A#        fld dword [esi]   ; load indirect 32 bit real from esi fstp qword [edi] ; store indirect 64 bit real to edi ret ]     ENDIF CALL F%,A%,A# =A# code


 * Note:** **FN_ConvertToSingle** is the same routine as **FN_f4** from the supplied //D3DLIB// library, but the assembly language has been commented and the name has been changed for clarity.

//by Richard Russell, November 2006//

The above routines use assembly language code to perform the conversion. An alternative is to use Windows API functions as follows:

code format="bb4w" DEF FN_ConvertToSingle(A#) LOCAL A%     PRIVATE F%      IF F% = 0 THEN SYS "LoadLibrary", "OLEAUT32.DLL" TO F%       SYS "GetProcAddress", F%, "VarR4FromR8" TO F%      ENDIF A#*=1.0# SYS F%,!^A#,!(^A#+4),^A% =A% DEF FN_ConvertFromSingle(A%) LOCAL A#     PRIVATE F%      IF F% = 0 THEN SYS "LoadLibrary", "OLEAUT32.DLL" TO F%       SYS "GetProcAddress", F%, "VarR8FromR4" TO F%      ENDIF SYS F%,A%,^A# =A# code If speed is critical, use this conversion function: code format="bb4w" DEF FN_ConvertToSingle(A#)=USR(f4) code where the routine **f4** has been assembled previously as follows: code format="asm" .f4       mov   ecx,[^A#+4] test ecx,&FFFFFF00 jnz  f4d movzx ecx,cl jecxz f4i mov  edx,[^A#] add  ecx,895 rol  edx,1 shld ecx,edx,21 shl  edx,20 btr  edx,20 rcr  ecx,1 mov  [^A#],edx mov  [^A#+4],ecx .f4d push eax fld  qword [^A#] fstp dword [esp] pop  eax ret ;       .f4i push eax fild dword [^A#] fstp dword [esp] pop  eax ret code Ensure there is at least a 2048-byte gap between the code and any writable data, to prevent thrashing of the instruction cache.