
quark:
I have two questions about using the Double data type and the operations in the Floating typeclass on a computer that uses IEEE floating point numbers.
I notice that the Floating class only provides "log" (presumably log base 'e') and "logBase" (which, in the latest source that I see for GHC is defined as "log y / log x"). However, in C, the "math.h" library provides specific "log2" and "log10" functions, for extra precision. A test on IEEE computers (x86 and x86-64), shows that for a range of 64-bit "double" values, the answers in C do differ (in the last bit) if you use "log2(x)" and "log10(x)" versus "log (x) / log(2)" and "log(x) / log(10)".
You could consider binding directly to the C functions, if needed, {-# OPTIONS -fffi -#include "math.h" #-} import Foreign.C.Types foreign import ccall unsafe "math.h log10" c_log10 :: CDouble -> CDouble log10 :: Double -> Double log10 x = realToFrac (c_log10 (realToFrac x)) main = mapM_ (print . log10) [1..10] Also, is there any difference if you compile with -fvia-C or -fexcess-precision (or both)?
My second question is how to get at the IEEE bit representation for a Double. I am already checking "isIEEE n" in my source code (and "floatRadix n == 2"). So I know that I am operating on hardware that implements floating point numbers by the IEEE standard. I would like to get at the 64 bits of a Double. Again, I can convert to a CDouble and use the FFI to wrap a C function which casts the "double" to a 64-bit number and returns it. But I'm wondering if there's not a better way to do this natively in Haskell/GHC (perhaps some crazy use of the Storable typeclass?). Or if someone has already tackled this problem with FFI, that would be interesting to know.
The FFI is a good way. You can just bind to any C code linked with your code. There's some similar code for messing with doubles and longs in the mersenne-random package you might be able to use for inspiration: http://code.haskell.org/~dons/code/mersenne-random/ -- Don