New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fractions.gcd failure #65911
Comments
The Greatest Common Divisor (gcd) algorithm sometimes breaks because the modulo operation does not always return a strict integer number, but one very, very close to one. This is enough to drive the algorithm astray from that point on. Example:
Which is corret, but:
when the answer should be 1. The fix seems simple, just cast the mod() operation in the algorithm: while b:
a, b = b, int(a%b)
return a |
Actually probably int(round(a%b)) would be better. |
I will correct myself one more time (hopefully the last): while b:
a, b = b, round(a % b, 10)
return a a b fractions.gcd proposed_algorithm |
The gcd function is documented as taking two integer arguments: "Return the greatest common divisor of the integers a and b." I'm -0 on generalizing it, and also -0 on burning cycles to enforce the restriction to integer arguments. It's just silly ;-) |
Agreed with Tim. Oddly enough[1], remembering that with binary floating-point numbers, what you see is not what you get[2], it turns out that 8.881784197001252e-16 (= Fraction(1, 1125899906842624)) is in fact *exactly* the right answer, in that it's a generator for the additive subgroup of the rationals generated by 2.7 (= Fraction(3039929748475085, 1125899906842624)) and 107.3 (=Fraction(7550566250263347, 70368744177664)). [1] Actually not so odd, given that % is a perfectly exact operation when applied to two positive finite floats. |
@pacosta, if Mark's answer is too abstract, here's a complete session showing that the result you got for gcd(2.7, 107.3) is in fact exactly correct: >>> import fractions
>>> f1 = fractions.Fraction(2.7)
>>> f2 = fractions.Fraction(107.3)
>>> f1
Fraction(3039929748475085, 1125899906842624) # the true value of "2.7"
>>> f2
Fraction(7550566250263347, 70368744177664) # the true value of "107.3"
>>> fractions.gcd(f1, f2) # computed exactly with rational arithmetic
Fraction(1, 1125899906842624)
>>> float(_)
8.881784197001252e-16 But this will be surprising to most people, and probably useless to all people. For that reason, passing non-integers to gcd() is simply a Bad Idea ;-) |
Understood and agreed. My bad too for not reading the documentation more carefully. Thank you for the detailed explanation. Pablo
|
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: