I was doing leetcode when I had to do some arithmetic with rational numbers (both numerator and denominator integers).
I needed to count slopes in a list. In python
collections.Counter( [ x/y if y != 0 else "inf" for (x,y) in points ] )
did the job, and I passed all the tests with it. ((edit: they've pointed out in the comments that in that exercise numbers were much smaller, not general 32 bit integers))
I wonder if this is correct, that is, python correctly recognizes if a/b == c/d as rationals, for a,b,c,d 32 bit integers. I am also interested the case for c , and any additional facts that may be useful (footguns, best practices, theory behind it if not too long etc).
Also this question seems frequent and useful, but I don't really find anything about it (give me the duplicates!), maybe I am missing some important keywords?
CodePudding user response:
It's not safe, and I've seen at least one LeetCode problem where you'd fail with that (maybe Max Points on a Line). Example:
a = 94911150
b = 94911151
c = 94911151
d = 94911152
print(a/b == c/d)
print(a/b)
print(c/d)
Both a/b
and c/d
are the same float
value even though the slopes actually differ (Try it online!):
True
0.9999999894638303
0.9999999894638303
You could use fractions.Fraction(x, y)
or the tuple (x//g, y//g)
after g = math.gcd(d, y)
( if I remember correctly, this is more lightweight/efficient than the Fraction
class).
CodePudding user response:
Assuming you don't want to allow for the effects of integer division, check the equivalent ad == bc
instead.
This is more numerically stable. In C you can write
1LL * a * d == 1LL * b * c
to prevent overflow.