0

I'm having trouble with rounding floats. I'm solving a task where you need to round your result to two decimal points. But I can't do it when the third decimal point is 5 because it's stored incorrectly.

For example: My result is equal to 1.005 and that should be rounded to 1.01. But C++ rounds it to 1.00 because the original float is stored as 1.0049999... and not 1.005.

I've already tried always adding a very small float to the result but there are some other test cases which are then rounded up but should be rounded down.

I know how floating-point works and that it is often not completely accurate. I'm just wondering whether anyone has found a way around this specific problem.

Hinko Pih Pih
  • 201
  • 1
  • 8
  • 1
    Nothing that you do can change the fact that 1.0049999.should be rounded down to 1.00. You just have to accept that floating point arithmetic is not perfectly accurate. – john Jul 13 '19 at 20:10
  • 3
    Possible duplicate of [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) –  Jul 13 '19 at 20:11
  • 1
    Some recommended reading: [Sometimes Floating Point Math is Perfect](https://randomascii.wordpress.com/2017/06/19/sometimes-floating-point-math-is-perfect/) and [What Every Computer Scientist Should Know About Floating-Point Arithmetic](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). – Jesper Juhl Jul 13 '19 at 20:14
  • How do you compute the number that you want to round? Since the code you have is producing a number that is not exactly 1.005 but you want it to produce exactly 1.005, then the solution is to change that code to use another format that can represent exactly 1.005, not to attempt to make a routine that returns a correctly rounded result given an incorrect input. – Eric Postpischil Jul 13 '19 at 20:54
  • Note that you can't represent 1.005 exactly using a binary format, no matter how much precision you have. – Nelfeal Jul 13 '19 at 21:10
  • @Nelfeal What format should I use then? – Hinko Pih Pih Jul 13 '19 at 21:16
  • 1
    @HinkoPihPih Well, you said in another comment that you're only allowed "regular C++ libraries"; if you mean the standard library, then you're out of luck. Otherwise, just search for a decimal library. I'm sure you can even find some header-only ones. – Nelfeal Jul 13 '19 at 21:24

2 Answers2

1

When you say "my result is equal to 1.005", you are assuming some count of true decimal digits. This can be 1.005 (three digits of fractional part), 1.0050 (four digits), 1.005000, and so on.

So, you should first round, using some usual rounding, to that count of digits. It is simpler to do this in integers: for example, with 6 fractional digits, it means some usual round(), rint(), etc. after multiplication by 1,000,000. With this step, you are getting exact decimal number. After this, you are able to make the required final rounding to what you need.

In your example, this will round 1,004,999.99... to 1,005,000. Then, divide by 10000 and round again.

(Notice that there are suggestions to make this rounding in yet specific way. The General Decimal Arithmetic specification and IBM arithmetic manuals suggest this rounding is done in the way that exact fractional part 0.5 shall be rounded away from zero unless least significant result bit becomes 0 or 5, in that case it is rounded toward zero. But, if you have no such rounding available, a general away-from-zero is also suitable.)

If you are implementing arithmetic for money accounting, it is reasonable to avoid floating point at all and use fixed-point arithmetic (emulated with integers, if needed). This is better because you the methods I've described for rounding are inevitably containing conversion to integers (and back), so, it's cheaper to use such integers directly. You will get inexact operation checking as well (by cost of explicit integer overflow).

Netch
  • 4,171
  • 1
  • 19
  • 31
0

If you can use a library like boost with its Multiprecision support.
Another option would be to use a long double, maybe that's precise enough for you.

Rick Pat
  • 789
  • 5
  • 14