Floating point and RealFrac

Daniel Fischer daniel.is.fischer at googlemail.com
Sun May 15 23:41:47 CEST 2011

Looking at the old bug list again, there are a couple of tickets I might be 
able to do something about. Since library submissions are somewhat painful, 
though, and I'm not bitten by the issues, I'd like to know if there's 
general interest to do something about them.

Feature request: add primops word2Double#, double2Word#, word2Float#, 

Well, I don't know how to create primops, but I could twiddle a few bits in 
C to produce a hopefully faster conversion than we have now.

a fast 'fraction' function for Double


fraction x = snd (properFraction x :: (Integer, TYPE_OF_x))

, when compiled with optimisations, is not as slow as it used to be, it's 
still not very fast. A binding to modf/modff or some bit-twiddling in C 
should be faster. If there's demand for this, should a `fraction' function 
be added to RealFrac, should standalone functions fractionFloat and 
fractionDouble be added to GHC.Float with rewrite rules 
snd (properFraction x) -> fractionTYPE x

realToFrac misbehaves on NaNs, -0.0 and infinities (for Float -> Double)
when the rewrite rule doesn't fire.

As long as the realToFrac conversion [without rewrite rules] goes through 
Rational, this is basically unfixable.

So a real fix would necessitate a language change.
Some ideas have been shortly discussed in
and replies.

The most reasonable candidates IMO are
- a dedicated floating point conversion, with
  * a type alias FloatMax for the largest (real + infinities + NaNs) 
Floating point type, currently Double
  * methods toFloatMax and fromFloatMax  added to RealFloat
  * the conversion function
      floatConvert :: (RealFloat a, RealFloat b) => a -> b

- adding a type specifically for conversions between different number types 
that caters for special values, something along the lines of

data NumRep
    = NegativeZero
    | Infinity Bool   -- to indicate sign
    | NaN    -- possibly with a parameter to encode different NaNs
    | BinExp Integer Int   -- m*2^e
    | Rat Rational
    | Entire Integer   -- ?

and let realToFrac convert via this type.
The BinExp constructor would allow a more efficient conversion between 
base-2 floating point types than fromRational . toRational can be.
If such a type would also be used for the Read instances, instead of 
Rational, adding a constructor for base-10 representations would be useful 
(cf. http://hackage.haskell.org/trac/ghc/ticket/3897 ) [and Rational could 
be freed from the invalid values 0:%0, ±1:%0].

Both candidates would be major undertakings and have their downsides.

I can live with the current state of affairs, what bugs me most about it is 
the open ticket.

More information about the Libraries mailing list