Old Man Yells At Cloud

Chris Angelico rosuav at gmail.com
Sun Sep 17 14:59:30 EDT 2017


On Mon, Sep 18, 2017 at 4:35 AM, Steve D'Aprano
<steve+python at pearwood.info> wrote:
>> So why doesn't it return a fractions.Fraction instead? That way, you
>> still get "one half" instead of zero, but it's guaranteed to be
>> accurate. And having 1/3 be a literal meaning "one third" would avoid
>> all the problems of "1/3 + 1/3 + 1/3 != 3/3". What is the
>> justification for int/int => float and not rational?
>
> (1) Guido doesn't like fractions for the built-in maths operators, because of
> his experience with ABC where quite simple calculations would end up with
> bloody enormous fractions with millions of digits in both the numerator and
> denominator, running slower and slower, for a number where the actual precision
> was maybe three or four decimal places.

Okay, that's reasonable. A counter-argument is that if you want
reduced accuracy to improve performance, you can always ask for it (by
casting to float), but I do see the disadvantage of slow rationals by
default.

> (2) Fractions didn't exist in the standard library when true division was
> introduced.

Really? When was true division added? I thought the fractions module
had been there for several 2.x versions.

> (3) Fractions are slow to work with. They were even slower until a few years ago
> when Python got a C accelerated version. Floats are much faster.

Yes, they are. And byte strings are probably faster to work with than
Unicode text. Python doesn't use performance as a primary definition
of semantics.

> (4) For many purposes, the arbitrary precision of fractions is *spurious*
> precision. Like the old saw says:
>
> "Measure with micrometer, mark with chalk, cut with axe."
>
> You're taking physical quantities which are typically measured to a precision of
> three or four decimal places, if not less, then doing calculations on them to a
> precision of potentially millions of decimal places. There may be a few places
> where that is justified, but as the default behaviour, its spurious precision
> and such overkill as to be ludicrous.

And printing "one eleventh" to a dozen decimal places is just as
spurious. Or when you do arithmetic of any kind on decimals. It's not
a problem unique to rationals. But I agree, sometimes you'll have more
precision than you want.

> (5) Most people are used to dealing with floating point numbers, from other
> languages, from calculators, from school maths. Floats are quirky but familiar.
>
> (6) Fractions are surprising and hard to deal with. Quickly now, without using a
> calculator or Python, how big is this number?
>
> 2523720122311461/140737488355328
>
> Is it more or less than 50?
>
> Which would you rather see, the above fraction or its decimal equivalent,
> 17.93211?

If int/int yielded rational, you would have two ways you could work:

1) Fractions: 2523720122311461/140737488355328
2) Floats: 2523720122311461.0/140737488355328

And if you want to know if it's more or less than 50, you could simply compare:

>>> f = fractions.Fraction('2523720122311461/140737488355328')
>>> f
Fraction(2523720122311461, 140737488355328)
>>> f < 50
True
>>> f > 50
False

Sure, it's harder to eyeball. But comparisons are certainly possible.

Basically, you trade one set of weirdnesses for another.

ChrisA



More information about the Python-list mailing list