
Jon Fairbairn comments //Steffen Mazanek//:
Prelude> 0.1::Rational 13421773 % 134217728 Prelude> 13421773/134217728 0.1
I do not know how this fraction is calculated, but it does not fit my expectations :-)
Remember that internally arithmetic is binary, and that 0.1 can't be expressed exactly as a floating point number. I think that's the explanation.
Ok, ok, it is no bug...
No, I think it is a bug: 0.1 ought to be equivalent to fromRational (1%10), but Hugs isn't intended for numerical work. GHCi gets the right answer.
This is less a bug than a Nessie monster which haunts Hugs some centuries already, and on Internet the issue has been discussed at least 4 times. The old, experimental Gofer Prelude numeric functions were sometimes abominable, since Mark Jones concentrated on other things, and nobody really complained, people were busy with other stuff as well. But I can't understand why this continues until now. The obvious technique to convert floats to rationals is the continued fraction expansion which gives the simplified answer fast. I don't understand the remark that the internal arithmetic is binary. Sure, it is, so what? Why Ross Paterson underlies this as well? He concludes:
The real fix would be to keep the literals as Rationals, but this would be too expensive in the Hugs setting.
Andrew Bromage says some words about errors and representation. I think that the problem can (perhaps should) be dealt with at a higher level. What's wrong with conversion functions like those below. First, convert a float to a lazy list of coeffs. of a regular continued fraction: tocfrac x = let n = floor x y = x-fromInteger n in n : if y==0.0 then [] else tocfrac (recip y) and then reconstruct using Euler sequences as described in Knuth or perhaps an optimized method, the one I cite is not very efficient. It gives a list of (N,D) -- *all* rational approximants of the original float. continuant l@(_:ql) = zip (tail (euseq l)) (euseq ql) where euseq [] = [] euseq (x:q) = eus 1 x q eus p0 p1 (a:cq) = p0 : eus p1 (a*p1+p0) cq eus p0 p1 [] = [p0,p1] Now, test it: pp=3.141592653589793 r=take 10 (continuant (tocfrac pp)) You should get [(3,1),(22,7),(333,106),(355,113),(103993,33102),(104348,33215), ... etc;, anyway all that is already inexact... For 0.1 one gets [(0,1),(1,10)] Jerzy Karczmarczuk