Quite simply, i need to use the type double for a foreign function argument. When I do the following:
(coerce .2 'double-float)
it returns on Allegro 8.1 running under windows vista 32 bit
0.22200000286102295d0
Why is the new number different??? What's going on
Coercing to double-float
Re: Coercing to double-float
Don't forget that floating point numbers are just rational approximations, you can't get around issues of precision.
Your implementation may not have the exact same representations as mine, but it doesn't matter. Fundamentally he issue is this:
i.e., the double-float representation of 2/10 is not divisible by the single-float representation of 2/10. But look at your coerced version:
In order to coerce your .2 to double float, youscale the significand to the new representation, and adjust the exponent as needed. You don't have the real number ".2" around to return to. This has nothing to do with lisp per se, it's in the nature of floating point representations.
Hope that makes sense.
Code: Select all
CL-USER> (integer-decode-float .2d0)
7205759403792794
-55
1
CL-USER> (integer-decode-float .2)
13421773
-26
1
Code: Select all
CL-USER> (/ 7205759403792794 13421773)
7205759403792794/13421773
Code: Select all
CL-USER> (integer-decode-float (coerce .2 'double-float))
7205759511166976
-55
1
CL-USER> (/ 7205759511166976 13421773)
536870912
Hope that makes sense.
Re: Coercing to double-float
0.2 and 0.222 are distinctly different numbers in any common floating-point representation. The behavior you show is quite unusual; it is not normal rounding due to type conversion (and double-floats can store all single-floats without loss). On my machine, SBCL, CCL, CLISP, and ECL all give 0.20000000298023224d0.
Not exactly sure what you're seeing, but agree that its worth investigating. What does (* 0.2 1d0) give?
Not exactly sure what you're seeing, but agree that its worth investigating. What does (* 0.2 1d0) give?
Re: Coercing to double-float
Sorry. (coerce .2 'double-float) produces
0.20000000298023224d0
(* .2 1d0) produces 0.20000000298023224d0
(* .2d0 .1d0) produces
0.020000000000000004d0
I think I will just stick to the float version of the c library. Thanks for the explanation!
0.20000000298023224d0
(* .2 1d0) produces 0.20000000298023224d0
(* .2d0 .1d0) produces
0.020000000000000004d0
I think I will just stick to the float version of the c library. Thanks for the explanation!
Re: Coercing to double-float
Huh, strange that I completely missed your typo earlier, reading it as the above behavior (as you've corrected it)Harnon wrote:Sorry. (coerce .2 'double-float) produces
0.20000000298023224d0
(* .2 1d0) produces 0.20000000298023224d0
(* .2d0 .1d0) produces
0.020000000000000004d0
I think I will just stick to the float version of the c library. Thanks for the explanation!
This behavior is the expected one, as noted.
Is not particularly useful in this actual situation. The issue isn't whether or not you can represent 2/10 in both representations, but how you choose to map the smaller representation to the larger one, which obviously cannot be done bijectively. In this context there is nothing special about "0.2d0" compared to "0.20000000298023224d0", they both map to 0.2 in single precision.(and double-floats can store all single-floats without loss)
All you can really hope for is consistency, which you have:
Code: Select all
CL-USER> (float .2 1d0)
0.20000000298023224d0
CL-USER> (float (float .2 1d0) 1.0)
0.2
CL-USER> (float .2d0 1.0)
0.2