[Openmcl-devel] Floating point precision

Brian Mastenbrook brian at mastenbrook.net
Sat Jan 17 18:39:45 PST 2009

On Jan 17, 2009, at 8:18 PM, Sudhir Shenoy wrote:

> Yes, this is true for currency related calculations (interest, tax,
> etc.) and most accounting packages use BCD arithmetic as a result.
> What I am doing, however, is valuation of complex instruments (options
> and other derivatives) where you need double floats because, mostly,
> you are working with probability distributions and other irrational
> numbers such as natural logarithms. Inputs to the program from the
> external world can be coerced to double-float by default but I was
> unaware that conversions from integers or rationals to float would
> always use single-float instead of double as per the standard. I now
> have to go through the code and ensure that all constants are affixed
> with 'd0' even where they are exact integers because of the danger of
> intermediate results losing precision if these constants are passed to
> math functions ...

Makes sense. Sorry for the noise; an alarming number of programmers  
I've talked to in the past don't know *not* to use binary floats for  
currency calcuations.

> It is a pity that there is no analogue to *read-default-float-format*
> to specify this conversion rule. I guess that when the standard was
> written, floating point calculations were deemed to be expensive and
> the coming of cheap and fast floating point processors wasn't foreseen
> (or maybe all scientific computation at the time used FORTRAN
> anyhow :-).
> Would it be a good idea to introduce a special variable in the CCL
> package, e.g. *float-substitute-target*, that would default to  
> 'single-
> float but could be set to 'double-float if required (and introduce a
> conditional in all places that an int->float conversion is performed)?

It is possible to do something like this in user code. Create a new  
package (say, DOUBLE-LISP) that imports all symbols from COMMON-LISP  
but the numeric operations (given in a list in the spec at http://www.lispworks.com/documentation/HyperSpec/Body/12_aa.htm) 
, and exports all symbols that the COMMON-LISP package exports. For  
each of the numeric operations (at least the ones that take and  
necessarily return float arguments), create a dummy wrapper that  
coerces any rational arguments to double-float before calling the real  
CL function. As you've already noted, you should set *read-default- 
float-format* so that single floats never enter your program.

Then, simply use DOUBLE-LISP instead of COMMON-LISP in your user code.

I hate to suggest this on a CCL mailing list, but may want to consider  
using CLISP, which has long floats with user-specified precision.  
Additionally there is a user switch to change the float contagion mode  
to one which (in my opinion) is significantly saner. In ANSI CL, the  
result of an operation involving a single-float and double-float is  
specified to be a double-float, but this simply tricks the user into  
believing that more significant information is available in the result  
than is really there. In the optional CLISP mode, contagion is from  
most-specific to least-specific, so that the result never claims to be  
more accurate than it really is.

Unfortunately I don't believe the optional mode affects the rule of  
float substitutability, which is what is causing e.g. (sqrt 1/3) to  
return a single-float. For that, you would still need a custom  
package. (Aha, I see that Raffael Cavallaro has beaten me to the bunch  
as I'm typing this!)

Brian Mastenbrook
brian at mastenbrook.net

More information about the Openmcl-devel mailing list