Am 20.09.2009 06:17, schrieb Marc-Andre Lafortune:
> Sorry to be late to the party on this one.

I°«m late as well ;)

> It is important to remember that a Float is always an approximation.

No. It is an approximation only for:

 conversion from most decimal numbers, especially floats, and
 calculations that drop digits.

You can do exact math in a limited range of operations, and the question 
should be whether the approximation approach should overrule this exact 
math range of use, especially considering that conversion back to 
decimal _could_ be done precisely, however, sometimes requiring a bunch 
of digits.

> 1.0 has to be understood as 1.0 +/- EPSILON, where the EPSILON is platform
> dependent. 1.0 is not more equal to 1 than to 1 + EPSILON/2. Indeed, there
> is no way to distinguish either when they are stored as floats.

If what°«s stored in the Float _is_ your precise result, you certainly 
would not ask for precision reduction just because it _could_ have been 
the result of an imprecise calculation.

> To believe that Float#to_s loses data is wrong.

I think there should be both a Float#to_s and Float#to_nearest_s. The 
first would be precise, the second would output the °»shortest°… decimal 
representation within °řEPSILON/2.

> If r.to_s returns "1.2", it implies that 1.2 is one of the values in the
> range of possible values for that floating number. It could have been
> 1.2000...0006. Or something else. There is no way to know, so #to_s chooses,
> wisely, to return the simplest value in the range.

This is based on the assumption that no-one would ever care about 
Float°«s precision.

> There are many rationals that would be encoded as floats the same way. There
> is no magic way to know that the "exact" value was exactly 12/10 or
> 5404319552844595/4503599627370496, or anything in between. All have the same
> representation as a float. There is no reason to believe that the missing
>(binary) decimals that couldn't be written in space allowed where all 0.
> Actually, there is reason to believe that they were _probably_ non zero,
> because fractions that can not be expressed with a finite number of terms in
> their expansion in a given base all have a recurring expansion. I.e. if the
> significand does not end with a whole bunch of zeros (rational has finite
> expansion) then it probably ends with an infinite pattern (say 011011011 in
> binary, or 333333 in decimal).
>
> For any given float, there is one and only one rational with the smallest
> denominator that falls in the range of its possible values. It is currently
> given by Number#rationalize, and I really do not understand why #to_r would
> return anything else.
>
> I cannot see any purpose to any other fraction. Moreover, the current algorithm,
> which returns the middle of the range of possibilities, is platform dependent
> since the range of possibilities is platform dependent. That makes it even less
> helpful.

> Is there an example where one would want 0.1.to_r to be
> 3602879701896397/36028797018963968 ?

If the binary/Float°«s representation of 
3602879701896397/36028797018963968 is the real result of the 
calculation? How do you know?

> Do we really think that 0.1.to_r to be 3602879701896397/36028797018963968
> corresponds to the principle of least surprise?

False assumption here. Using floats for exact decimal math already 
violates POLS. Don°«t blame the messenger, i.e. the converter back to 
decimal, the only part of the game that could _always_ be precise.

> Note that I'm writing that fraction but with a different native double
> encoding, the fraction would be different.

Sure. Great to have different levels of precision/imprecision from the 
computers.

And portability is not always the issue, otherwise there would have 
never been different native floating point precisions.

 Matthias