From: "Matthias Wächter" Date: 2010-04-18T15:17:00+09:00 Subject: [ruby-core:29596] Re: [Feature #1408] 0.1.to_r not equal to (1/10) 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