简体   繁体   English

如何获得最佳的准确结果?

[英]How can I get the best accurate result?

Given: 鉴于:

unsigned int a, b, c, d;

I want: 我想要:

d = a * b / c;

and (a *b ) may overflow; 并且(a * b)可能溢出; also (b/c) may equal zero and give less accuracy. (b / c)也可能等于零,并且准确性较低。

Maybe a cast to 64-bits would get things to work, but I want to know the best way to get the most accurate result in d. 也许强制转换为64位可以使事情正常进行,但是我想知道在d中获得最准确结果的最佳方法。

Is there any good solution? 有什么好的解决办法吗?

I would either: 我会:

  • Cast to 64 bits, if that will work for your ranges of a, b, and c. 强制转换为64位(如果适用于您的a,b和c范围)。
  • Use an infinite precision library like GMP 使用像GMP这样的无限精度库
  • Cast to a float or double and back, if you find those results acceptable. 如果发现这些结果可以接受,则转换为floatdouble float并返回。

For best accuracy/precision you'll want to do your multiplies before your divides. 为了获得最佳的准确性/精度,您需要在除法之前进行乘法。 As you imply, you'll want to use something with twice as many bits as an int: 就像您暗示的那样,您将需要使用比int两倍多的位:

int64_t d = (int64_t) a * (int64_t) b;
d /= c;

You don't need both casts, but they arguably make it a bit clearer. 您不需要两个强制转换,但可以说它们使内容更加清晰。

Note that if c is small enough, then d can still be bigger than an int. 请注意,如果c足够小,则d仍可以大于int。 That may or may not be an issue for you. 这可能对您来说不是问题。 If you're sure it isn't you can cast down to an int at the end. 如果您确定不是,则可以在末尾强制转换为int。

使用浮点数或双精度数,在浮点运算中, 允许除以零 ,结果将为正无穷大

You can always do an explicit check for overflow on a * b: 您始终可以对* b上的溢出进行显式检查:

long long e = (long long) a * (long long) b;
if (e <= INT_MAX) {
    d = e / c;
} else {
    d = a * (b / c);
}

Of course this only works for non-negative a, b, c. 当然,这仅适用于非负a,b,c。 If they can be negative you'll also have to check against INT_MIN. 如果它们可以是负数,则还必须对照INT_MIN。

[Update] You could also check which of a and b is larger and thus loses less precision when divided by c: [更新]您还可以检查a和b中的哪一个较大,从而除以c会降低精度:

if (a >= b) {
    d = a / c * b;
} else {
    d = a * (b / c);
}

For your problem as stated, I'd do d = (long long)a * b / c; 对于您所说的问题,我会做d = (long long)a * b / c;

No sense in going to float when you only need more bits. 当您只需要更多位时,就没有float意义。 No need to redeclare or cast everything. 无需重新声明或投射所有内容。 Casting a is enough to promote b and c to larger size in the expression. 强制转换a足以在表达式中将bc提升为更大的尺寸。

I'd do something along the lines of the following: 我会按照以下方式做一些事情:

if(c){
    d = (long long)a * b;
    d /= c;
}
else{
    // some error code because div by 0 is not allowed
}

Why not use a float or double ? 为什么不使用floatdouble float A float (on intel chips) is a 32-bit floating-point number, so you wouldn't necessarily need 64 bits for the operation? float (在Intel芯片上)是一个32位浮点数,因此您不一定需要64位操作吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM