比较没有溢出的分数

时间:2012-11-11 18:36:39

标签: c++ overflow fractions

我用C ++编写代码。我得到2个分数,a / b和c / d,其中a,b,c,d是int。有没有人知道如何在没有溢出的情况下执行a / b> c / d。例如,如果我将a,b,c,d设置为小于2147483647的4个最大素数。我如何确定a / b> c / d是否为真。我不允许使用除int之外的任何其他类型(即我无法转换为long long或double)。

5 个答案:

答案 0 :(得分:7)

这是一种适用于正整数的方法:

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);
}

这个想法是,如果整数除法更小或更大,那么你知道答案。如果整数除法给出相同的结果,那将是棘手的。在这种情况下,您可以使用余数,并查看%b / b&gt; C%d / d。但是,我们知道a%b / b> c%d / d,如果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);
}

答案 1 :(得分:4)

您可以执行标准算法(将a * d与b * c进行比较),但使用64位乘法以外的其他方法进行乘法运算。就像将数字划分为16位块并使用标准的大整数乘法例程来计算结果。

答案 2 :(得分:0)

您可以使用学校长除法来获得被除数和商,并继续递归分割,如下面的伪代码:

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

答案 3 :(得分:0)

就像这样执行std int division:http://en.wikipedia.org/wiki/Division_algorithm(参见带余数的整数除法(unsigned))。 Div int by int不会溢出,你得到商和提醒。现在,如果Q1> Q2或Q1&lt; Q2很明显,如果Q1 == Q2,则比较R1 / b和R2 / d。

E.g。取复数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位部分分离并重载运算符+ - * /&gt;&gt;&lt;&lt;。

答案 4 :(得分:0)

(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
    }

}