[Tutor] Fraction - differing interpretations for number and string

Dave Angel davea at davea.name
Thu Apr 16 14:15:40 CEST 2015


On 04/16/2015 08:11 AM, Dave Angel wrote:
> On 04/16/2015 01:03 AM, Jim Mooney wrote:
>> Why does Fraction interpret a number and string so differently? They come
>> out the same, but it seems rather odd
>>
>>>>> from fractions import Fraction
>>>>> Fraction(1.64)
>> Fraction(7385903388887613, 4503599627370496)
>>>>> Fraction("1.64")
>> Fraction(41, 25)
>>>>> 41/25
>> 1.64
>>>>> 7385903388887613 / 4503599627370496
>> 1.64
>>
>
> When a number isn't an exact integer (and sometimes when the integer is
> large enough), some common computer number formats cannot store the
> number exactly.  Naturally we know about transcendentals, which cannot
> be stored exactly in any base.  PI and E and the square-root of two are
> three well known examples.
>
> But even rational numbers cannot be stored exactly unless they happen to
> match the base you're using to store them.  For example, 1/3 cannot be
> stored exactly in any common base.

By "common" I mean 2, 8, 10, or 16.  Obviously if someone implemented a 
base 3 floating point package, the number would be simply  0.1

>  In decimal, it'd be a repeating set
> of 3's.  And whenever you stopped putting down threes, you've made an
> approximation.
>      0.3333333333
>
> Python defaults to using a float type, which is a binary floating point
> representation that uses the special hardware available in most recent
> computers.  And in fact, when you use a literal number in your source,
> it's converted to a float by the compiler, not stored as the digits you
> typed.
>
> The number you specified in decimal, 1.64, is never going to be stored
> in a finite number of binary bits, in a float.
>
>  >>> from fractions import Fraction
>  >>> from decimal import Decimal
>
>  >>> y = 1.64
> Conversion to float appens at compile time, so the value given to y is
> already approximate.
>     roughly equivalent to the following
>  >>> y = float("1.64")
>
>  >>> Fraction(y)
> Fraction(7385903388887613, 4503599627370496)
>
> If you converted it in string form instead to Decimal, then the number
> you entered would be saved exactly.
>
>  >>> x = Decimal("1.64")
> This value is stored exactly.
>
>  >>> x
> Decimal('1.64')
>
>  >>> Fraction(x)
> Fraction(41, 25)
>
>
> Sometimes it's convenient to do the conversion in our head, as it were.
> Since 1.64 is shorthand for  164/100, we can just pass those integers to
> Fraction, and get an exact answer again.
>
>  >>> Fraction(164, 100)
> Fraction(41, 25)
>
>
> Nothing about this says that Decimal is necessarily better than float.
> It appears better because we enter values in decimal form and to use
> float, those have to be converted, and there's frequently a loss during
> conversion.  But Decimal is slower and takes more space, so most current
> languages use binary floating point instead.
>
> I implemented the math on a machine 40 years ago where all user
> arithmetic was done in decimal floating point.  i thought it was a good
> idea at the time because of a principle I called "least surprise." There
> were roundoff errors, but only in places where you'd get the same ones
> doing it by hand.
>
> History has decided differently.  When the IEEE committee first met,
> Intel already had its 8087 implemented, and many decisions were based on
> what that chip could do and couldn't do.  So that standard became the
> default standard that future implementations would use, whatever company.
>


-- 
DaveA


More information about the Tutor mailing list