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:
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#
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:
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#
If speed is critical, use this conversion function:
DEF FN_ConvertToSingle(A#)=USR(f4)
where the routine f4 has been assembled previously as follows:
.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
Ensure there is at least a 2048-byte gap between the code and any writable data, to prevent thrashing of the instruction cache.