Reading the documentation

Steve D'Aprano steve+python at pearwood.info
Fri Aug 25 02:03:12 EDT 2017


On Fri, 25 Aug 2017 03:22 pm, Chris Angelico wrote:

>> py> from decimal import Decimal
>> py> sum([1/13]*13)
>> 0.9999999999999998
>> py> sum([Decimal(1)/Decimal(13)]*13)
>> Decimal('0.9999999999999999999999999997')
> 
> Now do the same exercise with pencil and paper. What's 1/13?

Easy: 0.(076923) where the brackets surround the digits which repeat.

I'm not so good at division in binary, but I *think* it should be:

0b0.(000100111011)

where, again, the repeating bits are in brackets.


[...]
> Two sevenths is 0.285714285714. 

No it isn't. The decimal is repeating, so its actually 0.(285714). By truncating
it to only a finite number of decimal places, you introduce some rounding
error.


> Add seven of those together, and 
> you'll get 0.999999999999. If you want to call it "2/7", you can use
> fractions.Fraction, but if you treat it as a decimal fraction, it's
> going to be rounded, just as it will be in a binary fraction (or a
> float). That's what I mean about the confusion - that there are
> numbers that you can write accurately as decimal fractions, but as
> binary fractions, they repeat.

And there are numbers which repeat in decimal but not binary, and numbers which
repeat in both, and numbers which don't repeat in either.

And even among those that don't repeat, sometimes you need more precision than
float (or Decimal) gives, and so there's still rounding error.

Fortunately often the rounding errors cancel rather than reinforce, which is why
floats are so accurate most of the time for the sorts of numbers we mostly care
about.




-- 
Steve
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list