=====Passing floating-point values to DLLs=====
//by Richard Russell, July 2009//\\ \\ The majority of functions that you are likely to want to call using [[http://www.bbcbasic.co.uk/bbcwin/manual/bbcwin7.html#sys|SYS]] (typically Windows API functions, or functions in third-party DLLs) will require only **integer** or **string** parameters; you can specify those straightforwardly in the **SYS** statement.\\ \\ Occasionally, however, you may need to pass a floating-point parameter to such a function. Unfortunately you cannot usually do that simply by including the appropriate variable or constant in the **SYS** statement; this article describes what you need to do instead.\\ \\ There are two main ways of passing floating-point parameters: **by reference** or **by value**. In the first case you pass a **pointer** to the floating-point value (the memory address at which it is stored), and in the second case you pass the **value** itself. There are also (principally) two different types of floating-point value that the function may require: a 32-bit **float** value or a 64-bit **double** value.\\ \\ You must first ascertain from the documentation of the function whether the parameter is to be passed **by reference** or **by value**, and whether the parameter needs to be a **float** or a **double**; this is vitally important!\\ \\ Below are listed the methods you must adopt in each of the four possible circumstances:\\ \\
==== 64-bit doubles passed by reference ====
\\ This is the simplest case to deal with in BB4W. Suppose you want to pass the variable **fpv**:
fpv# = fpv * 1.0#
SYS "FunctionName", ^fpv#
Here the value is converted (if necessary) to a 64-bit float (by multiplying it by **1.0#**) and then stored in the 64-bit variable **fpv#**. The parameter supplied in the SYS call is the address of the variable (**^fpv#**).\\ \\ Rather than a scalar value, you may need to pass an **array** of values (arrays are invariably passed by reference). You can do that in a similar way, for example to pass the array **fpv#()**:
fpv#() *= 1.0#
SYS "FunctionName", ^fpv#(0)
Here it is assumed that the array was originally declared with 64-bit elements (i.e. either in ***FLOAT 64** mode or by explicitly specifying a **#** suffix).\\ \\ If your array uses suffices starting at **1** rather than 0 then you will need to pass the address of the base element:
fpv#() *= 1.0#
SYS "FunctionName", ^fpv#(1)
==== 64-bit doubles passed by value ====
\\ Since each parameter of the **SYS** statement is passed as a 32-bit value, a 64-bit floating-point value must be passed as **two** parameters. Suppose you want to pass the variable **fpv**:
SYS "FunctionName", FN_dl(fpv), FN_dh(fpv)
The 'helper functions' **FN_dl** and **FN_dh** are listed [[/Passing%20floating-point%20values%20to%20DLLs#helpers|below]]. If you prefer to use 'inline' code rather than call the helper functions you can do that as follows:
fpv# = fpv * 1.0#
SYS "FunctionName", !^fpv#, !(^fpv#+4)
==== 32-bit floats passed by reference ====
\\ BBC BASIC for Windows doesn't have a native 32-bit float type, so a conversion is required. Suppose you want to pass the variable **fpv** by reference:
temp% = FN_f4(fpv)
SYS "FunctionName", ^temp%
Here the temporary variable **temp%** is loaded with the 32-bit float, and then its address is passed as the parameter.\\ \\
==== 32-bit floats passed by value ====
\\ This is similar to the previous case, except that the temporary variable is not required. So to pass the variable **fpv** by value:
SYS "FunctionName", FN_f4(fpv)
The 'helper function' **FN_f4** is listed [[/Passing%20floating-point%20values%20to%20DLLs#helpers|below]].\\ \\
==== Helper functions ====
\\ Here are the functions used in the above examples:
REM Convert to 64-bit double (low 4 bytes)
DEF FN_dl(A#)
A# *= 1.0#
= !^A#
REM Convert to 64-bit double (high 4 bytes)
DEF FN_dh(A#)
A# *= 1.0#
= !(^A#+4)
REM Convert to 32-bit float
DEF FN_f4(a#)LOCALP%:P%=^a#:IFABSa#<1E-38 THEN=FALSE
=P%!4 AND NOT&7FFFFFFFOR(P%!4-&38000000<<3 OR!P%>>29 AND7)+(!P%>>28 AND1)