Bay Six Software Forum Index Bay Six Software
Beyond the Basics
 FAQFAQ   SearchSearch   UsergroupsUsergroups   RegisterRegister 

ULong may be used as a "float" device
By Brent D. Thorn

Liberty BASIC 4 provides us with some great facilities for calling external code written in another language, such as C, if the non-LB code is compiled to a standard DLL. LB can pass these functions 16- and 32-bit integers (signed or unsigned), 64-bit (double-precision) real numbers, pointers to the same, and strings and structs.

The Problem

Where LB fails us is in calls using a 32-bit (single-precision) real number. C-derived languages call this a "float". While the Windows API uses very few FP data types, many third-party DLLs use them, and some use them a lot.

Some inexperienced LB-ers, upon encountering "float", simply regard it as a synonym for "double" and translate it into their LB code as such. Inexplicably, sometimes this works, but much more often the program fails--sometimes spectacularly.

The Solution

The "oleaut32" DLL that ships with Windows provides many functions for converting one data type to another. Two of these functions--"VarR4FromR8" and "VarR8FromR4"--look like they will fill the bill. The former converts a double to a float, and the latter converts it back to double.

The reader is probably scratching his or her head right now. "If LB doesn't have a single-precision type, how does a function that returns that type help?," you might ask.

As stated above, a float is 32 bits (4 bytes) in width. This is the same size as a "long" or "ulong" in LB. We can "pretend" these types are the same and use ulong in our LB code wherever a float is required, then use the conversion functions to give LB a type it can use.

The conversion functions are wrapped in two easy-to-use LB functions below.
Function toFloat( R8 )
'-- Converts a 64-bit Double to a 32-bit number.
    Struct local1, R4 As ULong
    CallDLL #oleaut32, "VarR4FromR8", _
        R8 As Double, local1 As Struct, _
        ret As Long
    toFloat = local1.R4.struct
End Function

Function fromFloat( R4 )
'-- Converts a 32-bit number to a 64-bit Double.
    Struct local1, R8 As Double
    CallDLL #oleaut32, "VarR8FromR4", _
        R4 As ULong, local1 As Struct, _
        ret As Long
    fromFloat = local1.R8.struct
End Function

Step by Step

  1. Copy the wrapper functions and paste them to the end of your LB code.
  2. In your initialization code, open "oleaut32.dll" as #oleaut32.
  3. In your shutdown code, close #oleaut32.
  4. Anywhere a float is needed (function call or struct), use a ulong.
  5. In a CallDLL, make sure you are passing a variable because a numeric literal won't work.
  6. When a float needs to be passed to a function or assigned to a struct element, convert the value to pseudo-float/ulong by wrapping the value in a call to toFloat.
  7. When a function returns a float or modifies a struct with float, convert the value to true floating-point by wrapping the value in a call to fromFloat.

Simple Example

The following code demonstrates the conversion process. It calculates the value of pi, which is a type double. Then it converts it to an integer containing the same bits a float would. Finally, the value is converted to a double, but retains the same precision as a float.
    Open "oleaut32" For DLL As #oleaut32

    dblPI = 4 * Atn(1)
    lngPI = toFloat(dblPI)
    sngPI = fromFloat(lngPI)

    Print "dblPI = ";dblPI
    Print "lngPI = ";DecHex$(lngPI)
    Print "sngPI = ";sngPI

    Close #oleaut32


Powered by phpBB © 2001, 2005 phpBB Group