Division-Bug in decimal and mpmath
Mark Bourne
nntp.mbourne at spamgourmet.com
Sun Dec 15 06:59:40 EST 2024
2QdxY4RzWzUUiLuE at potatochowder.com wrote:
> On 2024-12-14 at 12:08:29 +0000,
> Mark Bourne via Python-list <python-list at python.org> wrote:
>
>> Martin Ruppert wrote:
>>> Hi,
>>>
>>> the division 0.4/7 provides a wrong result. It should give a periodic
>>> decimal fraction with at most six digits, but it doesn't.
>>>
>>> Below is the comparison of the result of decimal, mpmath, dc and calc.
>>>
>>> 0.0571428571428571460292086417861615440675190516880580357142857 decimal: 0.4/7
>>> 0.0571428571428571460292086417861615440675190516880580357142857 mpmath: 0.4/7
>>> 0.0571428571428571428571428571428571428571428571428571428571428 dc: 0.4/7
>>> 0.0571428571428571428571428571428571428571428571428571428571429 calc: 0.4/7
>>> 0.05714285714285715 builtin: 0.4/7
>>>
>>> Both decimal and mpmath give an identical result, which is not a
>>> periodic decimal fraction with at most six digits.
>>>
>>> calc and dc provide as well an identical result, which *is* a periodic
>>> decimal fraction with six digits, so I think that's right.
>>
>> I looks like you might be running into limitations in floating-point
>> numbers. At least with decimal, calculating 4/70 instead of 0.4/7 appears
>> to give the correct result. As does:
>> ```
>> from decimal import Decimal as dec
>> z2 = dec(4) / dec(10)
>> print(z2 / dec(nen))
>> ```
>> You can also pass a string, and `dec("0.4")/dec(10)` gives the correct
>> result as well.
>>
>> Your `z` is a float, and therefore limited by the precision of a float. It
>> doesn't represent exactly 0.4, since that can't be exactly represented by a
>> float. Anything you do from then on is limited to that precision.
>>
>> I can't easily find documentation for dc and calc (links from PyPI are
>> either broken or don't exist), but I'm guessing they use some heuristics to
>> determine that the float passed in very close to 0.4 so that was probably
>> intended, rather than using the exact value represented by that float.
>
> I'm going to guess that since dc is a shell utility and calc is either
> another shell utility or the calculator in emacs, and that they both do
> their own conversion from a string to an internal representation without
> going through an IEEE float.
Oh yes. Thinking the question was about 4 different Python packages,
I'd just looked up the packages with those names on PyPI and hadn't
noticed they were separate commands being called via popen! In that
case, the string formatting of a float in the commands defaults to 6
decimal places, and `z` is rounded back to 0.4 rather than the exact
value represented by the float. From there, as you say, `dc` and `calc`
probably handle that string similarly to `decimal.Decimal` being passed
the string "0.4".
> Why couldn't we have evolved with eight fingers on each hand? ;-)
Yeah, it would have made conversions to and from binary somewhat more
intuitive...
--
Mark.
More information about the Python-list
mailing list