I have three values:
UInt64 a, b, c, d;
I need to determine if: (a*b) <=> (c*d). Naturally, just doing the
multiplication and comparing would tell me the result. However, the
values could potentially overflow. For example, if:
a = UInt64.MaxValue;
b = 2;
c = UInt64.MaxValue / 3;
d = 4;
I still need to be able to conclude ab > cd. I can determine if
wrapping will occur on multiplication by doing:
if (a <= 1 || b <= 1)
{
return false;
}
return ((UInt64.MaxValue / a) < b);
But it still doesn't help me determine ab > cd. Anybody have any
thoughts on how I could determine this? Thanks.
Well, you want to split them up a bit, into 32 bit chunks, and check
these. First some theory. Say, n = 2^32, then
a = a0 + a1*n
b = b0 + a2*n
c = c0 + c1*n
d = d0 + d1*n
(a0 + a1*n)*(b0 + b1*n) - (c0 + c1*n)*(d0 + d1*n) > 0
a0*b0 + a0*b1*n + a1*b0*n + a1*b1*n*n >
c0*d0 + c0*d1*n + c1*d0*n + c1*d1*n^2 > 0
a0*b0 + (a0*b1 + a1*b0)*n + a1*b1*n*n >
c0*d0 + (c0*d1 + C1*d0)*n + c1*d1*n*n
Now you do how you always compare numbers, like 321 > 175. You first
compare the highest digits. If they are not equal, you have your
answer. If they are equal, you compare the second digits, and so on,
and so forth.
Here you do the same. if a1*b1 > c1*d1, then the result is true. If
a1*b1 < c1*d1, then the result is false. And if both are equal, you
turn to comparing the next "digit", i.e. you compare
a0*b1 + a1*b0 with c0*d1 + c1*d0, etc.etc.
UInt64 a0 = a & 0xFFFFFFFF;
UInt64 a1 = a >> 32;
UInt64 b0 = b & 0xFFFFFFFF;
UInt64 b1 = b >> 32;
UInt64 c0 = c & 0xFFFFFFFF;
UInt64 c1 = c >> 32;
UInt64 d0 = d & 0xFFFFFFFF;
UInt64 d1 = d >> 32;
UInt64 x00 = a0*b0;
UInt64 x01 = c0*d0;
// this one may overflow, so split them up even more:
int x10 = (a0*b1) & 1 + (a1*b0) & 1; // lower bit
int x11 = (c0*d1) & 1 + (c1*d0) & 1; // lower bit
UInt64 x20 = a0*b1/2 + a1*b0/2; // top 63 bits
UInt64 x21 = c0*d1/2 + c1*d0/2; // top 63 bits
if (x10 = 2)
{
x20++;
x10 = 0;
}
if (x11 = 2)
{
x21++;
x11 = 0;
}
Byte x20 =
UInt64 x30 = a1*b1;
UInt64 x31 = c1*d1;
Now if the higher parts are compared, the lower bits don't matter,
except if the higher parts are equal. So you can do:
if (x30 > x31)
return true;
else if (x30 < x31)
return false;
else if (x20 > x21)
return true;
else if (x20 < x21)
return false;
else if (x10 > x11)
return true;
else if (x10 < x11)
return false;
else if (x00 > x01)
return true;
else
return false;
FWIW, this will not overflow. Each part, x00 - x31, is in the UInt64
range.
--
Rudy Velthuis
http://rvelthuis.de
"The whole problem with the world is that fools and fanatics are
always so certain of themselves, but wiser people so full of
doubts." -- Bertrand Russell