C++ double 与整数精度的乘法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6041295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 19:23:20  来源:igfitidea点击:

multiplication of double with integer precision

c++

提问by leslieg

I have a double of 3.4. However, when I multiply it with 100, it gives 339 instead of 340. It seems to be caused by the precision of double. How could I get around this?

我有一个 3.4 的两倍。但是,当我乘以 100 时,它给出了 339 而不是 340。这似乎是由 double 的精度引起的。我怎么能解决这个问题?

Thanks

谢谢

回答by Jan Hudec

First what is going on:

首先是怎么回事:

  1. 3.4 can't be represented exactly as binary fraction. So the implementation chooses closest binary fraction that is representable. I am not sure whether it always rounds towards zero or not, but in your case the represented number is indeed smaller.
  2. The conversion to integer truncates, that is uses the closest integer with smaller absolute value.
  3. Since both conversions are biased in the same direction, you can always get a rounding error.
  1. 3.4 不能完全表示为二进制小数。因此,实现选择最接近的可表示的二进制分数。我不确定它是否总是向零四舍五入,但在您的情况下,表示的数字确实较小。
  2. 转换为整数会截断,即使用最接近的绝对值较小的整数。
  3. 由于两种转换都偏向同一方向,因此您总是会得到舍入误差。

Now you need to know what you want, but probably you want to use symmetrical rounding, i.e. find the closest integer be it smaller or larger. This can be implemented as

现在你需要知道你想要什么,但可能你想使用对称舍入,即找到最接近的整数,无论​​是小还是大。这可以实现为

#include <cmath>
int round(double x) { std::floor(x + 0.5); } // floor is provided, round not

or

或者

int round(double x) { return x < 0 ? x - 0.5 : x + 0.5; }

I am not completely sure it's indeed rounding towards zero, so please verify the later if you use it.

我不完全确定它确实向零四舍五入,所以如果你使用它,请稍后验证。

回答by Bj?rn Pollex

If you need full precision, you might want to use something like Boost.Rational.

如果您需要全精度,您可能需要使用类似Boost.Rational.

回答by Jay

You could use two integers and multiply the fractional part by multiplier / 10.

您可以使用两个整数并将小数部分乘以乘数 / 10。

E.g

例如

int d[2] = {3,4};
int n = (d[0] * 100) + (d[1] * 10);

If you really want all that precision either side of the decimal point. Really does depend on the application.

如果你真的想要小数点两边的所有精度。确实取决于应用程序。

回答by Lindydancer

Floating-point values are seldom exact. Unfortunately, when casting a floating-point value to an integer in C, the value is rounded towards zero. This mean that if you have 339.999999, the result of the cast will be 339.

浮点值很少是精确的。不幸的是,在 C 中将浮点值转换为整数时,该值会向零舍入。这意味着如果您有 339.999999,则转换的结果将是 339。

To overcome this, you could add (or subtract) "0.5" from the value. In this case 339.99999 + 0.5 => 340.499999 => 340 (when converted to an int).

为了克服这个问题,您可以从值中添加(或减去)“0.5”。在这种情况下,339.99999 + 0.5 => 340.499999 => 340(转换为 int 时)。

Alternatively, you could use one of the many conversion functions provided by the standard library.

或者,您可以使用标准库提供的众多转换函数之一。

回答by James Kanze

You don't have a double with the value of 3.4, since 3.4 isn't representable as a double (at least on the common machines, and most of the exotics as well). What you have is some value very close to 3.4. After multiplication, you have some value very close to 340. But certainly not 399.

您没有值为 3.4 的双精度数,因为 3.4 不能表示为双精度数(至少在普通机器上,以及大多数外来机器上)。你所拥有的是一些非常接近 3.4 的值。乘法后,您的值非常接近 340。但肯定不是 399。

Where are you seeing the 399? I'm guessing that you're simply casting to int, using static_cast, because this operation truncates toward zero. Other operations would likely do what you want: outputting in fixed format with 0 positions after the decimal, for example, rounds (in an implementation defined manner, but all of the implementations I know use round to even by default); the function roundrounds to nearest, rounding away from zero in halfway cases (but your results will not be anywhere near a halfway case). This is the rounding used in commercial applications.

你在哪里看到的399?我猜你只是简单地强制转换为int,使用static_cast,因为这个操作会向零截断。其他操作可能会做你想做的:以小数点后 0 位的固定格式输出,例如,舍入(以实现定义的方式,但我知道的所有实现默认使用舍入到偶数);该函数round四舍五入到最接近的值,在中途情况下从零舍入(但您的结果不会接近中途情况)。这是商业应用中使用的舍入。

The real question is what are you doing that requires an exact integral value. Depending on the application, it may be more appropriate to use intor long, scaling the actual values as necessary (i.e. storing 100 times the actual value, or whatever), or some sort of decimal arithmetic package, rather than to use double.

真正的问题是你在做什么需要一个精确的整数值。根据应用程序,使用int或可能更合适long,根据需要缩放实际值(即存储实际值的 100 倍,或其他),或某种十进制算术包,而不是使用double