0

I am currently porting some codes from Windows to Linux (Ubuntu) from a MS VS2008 compiler to GCC.

The problem is that the following code has different results:

double            d = 19.53125;
std::cout.precision(4);
std::cout.setf(std::ios::fixed);

std::cout << d << std::endl;

Windows output: 19.5313
Linux output: 19.5312

If I set the precision to 5 the output is the same.

I expect that 19.53125 will be rounded up to 19.5313.

Any suggestions how I can get the desired rounding behavior?

Note: Windows code runs native on Windows 10 laptop and the Linux code runs inside a 64-bit Ubuntu 18.04 LTS VM.

uncletall
  • 6,609
  • 1
  • 27
  • 52
  • 1
    Read http://floating-point-gui.de/ – Basile Starynkevitch Oct 09 '20 at 03:11
  • 1
    "how I can get the desired rounding behavior?" --> you have not stated which output is preferred. – chux - Reinstate Monica Oct 09 '20 at 04:33
  • I expect that .5 is rounded up and not down. – uncletall Oct 09 '20 at 04:51
  • I would suspect that the rounding routines use the locale. Is linux using "C" local while windows is retrieving the local from the current encironment? Note: Just a guess. – Martin York Oct 09 '20 at 04:56
  • I suspect this answers the question: https://stackoverflow.com/q/24120888/14065 Basically C++ << operator uses std::locale of the stream. This uses the numeric facet which uses num_put. The default num_put specifies the behavior is the same as printf using the %f formater. The third answer https://stackoverflow.com/a/24120966/14065 to the linked question says its implementation defined how that rounds and quotes the standard. – Martin York Oct 09 '20 at 05:17
  • `Any suggestions how I can get the desired rounding behavior?`: Multiply by `100'000` and convert to integer. Check the last digit if it is less than 5 subtract other wise add `10 - lastDigit`. Finally divide by 10. Now manually print the number putting the decimal point in the correct position. :-) – Martin York Oct 09 '20 at 05:23

2 Answers2

1

Bankers Rounding is an algorithm for rounding quantities to integers, in which numbers which are equidistant from the two nearest integers are rounded to the nearest even integer. Thus, 0.5 rounds down to 0; 1.5 rounds up to 2.

GCC C++ standard library applies the Bankers Rounding. 19.53125 -> 19.5312, since 2 is the nearest even digit.

Additional info regarding C, but C++ respects C rounding: C++ Rounding behavior consistency for ties with sprintf

273K
  • 29,503
  • 10
  • 41
  • 64
  • I tried that, in that case 19.53135 should become 19.5314 but it also rounds down to 19.5313. – uncletall Oct 09 '20 at 05:26
  • It's because of the actual value stored in double is 19.5313**4**918212890625. Double can't contain the exact value 19.53135. – 273K Oct 09 '20 at 05:46
  • I can understand that, but why does the debugger show the nice number and not the long number? – uncletall Oct 09 '20 at 05:49
  • 1
    Try `(gdb) printf "%1.20f\n", d` to see 20 digits after the point. – 273K Oct 09 '20 at 05:53
  • Looks like I counted the number as float, your digits are correct for double. In any case you get 4 in place of the 5. – 273K Oct 09 '20 at 06:09
0

This has been an eye opener for me. Thanks for all the links. As I have not been able to find a way to influence the rounding behavior in the printf functions I don't see another solution then to use the math round function.

The below solution still works for me:

double         d = 19.53125;
int precision  p = 4;
double         factor = pow(10.0, p);
std::cout.precision(p);
std::cout.setf(std::ios::fixed);

std::cout << round(d * factor) / factor << std::endl;

Windows output: 19.5313
Linux output: 19.5313

Links:

  1. https://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/
  2. Why printf round floating point numbers?
uncletall
  • 6,609
  • 1
  • 27
  • 52