I have two fractions I like to compare. They are stored like this:
struct fraction {
int64_t numerator;
int64_t denominator;
};
Currently, I compare them like this:
bool fraction_le(struct fraction a, struct fraction b)
{
return a.numerator * b.denominator < b.numerator * a.denominator;
}
That works fine, except that (64 bit value) * (64 bit value) = (128 bit value)
, which means it will overflow for numerators and denominators that are too far away from zero.
How can I make the comparison always works, even for absurd fractions?
Oh, and by the way: fractions are always stored simplified, and only the numerator can be negative. Maybe that input constraint makes some algorithm possible...
Why not just compare them directly as floating point numbers?
If you are using GCC, you can use __int128.
I didn't understand the code in Kos's answer so this might be just duplicating it.
As other people have mentioned there are some easy special cases e.g.
b/c > -e/f
and-b/c > -e/f
ife/f > b/c
. So we are left with the case of positive fractions.Convert these to mixed numbers i.e.
a b/c
andd e/f
. The trivial case hasa != d
so we assumea == d
. We then want to compareb/c
withe/f
with b < c, e < f. Wellb/c > e/f
iff/e > c/b
. These are both greater than one so you can repeat the mixed number test until the whole number parts differ.Alright, so only your numerators are signed.
Special cases:
If the a.numerator is negative and the b.numerator is positive, then b is greater than a. If the b.numerator is negative and the a.numerator is positive, then a is greater than b.
Otherwise:
Both your numerators have the same sign (+/-). Add some logic-code or bit manipulation to remove it, and use multiplication with uint64_t to compare them. Remember that if both numerators are negative, then the result of the comparison must be negated.
Here's how Boost implements it. The code is well-commented.
Case intrigued me, so here is an implementation of Neil's answer, possibly with bugs :)