我正在用 C++ 编码。我得到 2 个分数,a/b 和 c/d,其中 a、b、c、d 是整数。有谁知道没有溢出的 a/b>c/d 方法。例如,如果我将 a、b、c、d 设置为小于 2147483647 的 4 个最大素数。我将如何确定 a/b>c/d 是否为真。我不允许使用除 int 以外的任何其他类型(即,我无法转换为 long long 或 double)。
5 回答
这是一种适用于正整数的方法:
bool greaterPositiveFraction(int a,int b,int c,int d);
bool greaterOrEqualPositiveFraction(int a,int b,int c,int d)
{
if (b == 0) return true;
if (d == 0) return false;
if (a/b > c/d) return true;
if (a/b < c/d) return false;
return !greaterPositiveFraction(b,a%b,d,c%d);
}
bool greaterPositiveFraction(int a,int b,int c,int d)
{
if (d == 0) return false;
if (b == 0) return true;
if (a/b > c/d) return true;
if (a/b < c/d) return false;
return !greaterOrEqualFraction(b,a%b,d,c%d);
}
这个想法是,如果整数除法更小或更大,那么你就知道答案了。如果整数除法给出相同的结果,这只是棘手的。在这种情况下,您可以只使用余数,并查看 a%b/b > c%d/d 是否。但是,我们知道 a%b/b > c%d/d if b/(a%b) < d/(c%d),所以我们可以把问题转过来再试一次。
带有余数的负值的整数除法有点混乱,但这些情况可以很容易地处理:
bool greaterFraction(int a,int b,int c,int d)
{
if (b<0) { b = -b; a = -a; }
if (d<0) { d = -d; c = -c; }
if (a<0 && c<0) return greaterPositiveFraction(-c,d,-a,b);
if (a<0) return false;
if (c<0) return true;
return greaterPositiveFraction(a,b,c,d);
}
您可以使用标准算法(将 a*d 与 b*c 进行比较),但使用 64 位乘法以外的方法进行乘法运算。就像将您的数字分成 16 位块并使用标准的大整数乘法例程来计算结果。
您可以使用学校长除法来获得被除数和商,并像下面的伪代码一样继续递归除法:
bool compare(a,b,c,d)
a/b = n + r/b
c/d = m + q/d
if (n == m)
if (r == 0 && q == 0) return false
if (r == 0) return false
if (q == 0) return true
if (a < b && c < d)
if (c/a == d/b && c%a == 0 && d%b == 0) return false
return !compare(b,r,d,q) //flip it to continue
if (n > m) return true //a/b > c/d
else if (n < m) return false //a/b < c/d
else return compare(r,b,q,d) //need to continue comparing
只需像这里一样进行 std int 除法:http ://en.wikipedia.org/wiki/Division_algorithm (请参阅带余数的整数除法(无符号))。Div int by int 不会溢出,你会得到商和提醒。现在如果 Q1 > Q2 或 Q1 < Q2 很清楚,如果 Q1==Q2 那么你比较 R1/b 和 R2/d。
例如,采用复杂的 Q1==Q2 情况,25/12 和 44/21,Q1=2 和 R2=1,Q2=2 和 R2=2,因此 Q1==Q2,您现在需要比较 1/12 和 2/ 21. 现在你做一个 12*21 的公约数,但你不需要将它们相乘,你只需要比较 1*21 和 2*12。即你比较 (1*21)/(12*21) 和 (2*12)/(12*21) 但由于除数相同,这意味着只比较 1*21 和 2*12。
嗯,但是 1*21 和 2*12 都可以溢出(如果不是 12 而是 maxint)。好吧,无论如何,也许它会给出一些想法。
要获得更好的解决方案,只需实现您自己的 128 位(或 N 位)整数类。这并不难做到,也许半天。您只需将高低 64 位部分分开并重载运算符 +-*/>><<。
(a/b > c/d) 可以部分写成在许多情况下避免算术运算,然后在其余情况下避免算术上溢和下溢。请注意,最后一个案例留给读者作为练习。
bool fractioncompare(int a, int b, int c, int d) {
bool cd_negative = (c < 0 && d > 0) || (c > 0 && d < 0);
bool ab_negative = (a < 0 && b > 0) || (a > 0 && b < 0);
// if c/d negative and a/b positive then a/b is larger
if(cd_negative && !ab_negative) return true;
// if c/d postive and a/b negative then a/b is not larger
if((!cd_negative && ab_negative) return false;
bool both_negative = cd_negative && ab_negative;
// limited cases were a/b > c/d can be determined without needing to
// do arithmetic calculations (so no risk of overflow / underflow)
if(a > c && b < d) return !both_negative;
if(a < c && b > d) return both_negative;
int ab = a/b;
int cd = c/d;
bool no_trunc = a % b && c % d;
if(no_trunc) return ab > cd;
// No risk of overflow with divide and skipping the equal case avoids
//truncation issues
if(ab > cd) return true;
if(ab < cd) return false;
// truncation may mean ab and cd aren't actually equal so do some
// comparisons on differences to determine the result
if(!both_negative)
{
// use subtraction only to avoid overflow
if(ab == 0) return (b-(b-a) > d-(d-c));
else return (b-(b-a) < d-(d-c));
}
else
{
// TODO subtract values with same sign and add with
// different signs and compare appropriately to determine result
}
}