开发者

multiplication of double with integer precision

开发者 https://www.devze.com 2023-03-06 21:42 出处:网络
I have a double of 开发者_如何学C3.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?

I have a double of 开发者_如何学C3.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?

Thanks


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.

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.


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


You could use two integers and multiply the fractional part by multiplier / 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.


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.

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).

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


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.

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 round rounds 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.

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 int or 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消