Learn the fundamentals of Angular 2, a JavaScript framework for developing dynamic single page applications.

Hi,

Is there a C/C++ equivalent function for rounding half-even? I need**identical **function to Java's BigDecimal.setScale(int scale, **BigDecimal.ROUND_HALF_EVEN**);

So 20.225 = 20.22

20.235 = 20.24

Thanks.

Is there a C/C++ equivalent function for rounding half-even? I need

So 20.225 = 20.22

20.235 = 20.24

Thanks.

Experts Exchange Solution brought to you by

Enjoy your complimentary solution view.

Get every solution instantly with Premium.
Start your 7-day free trial.

I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trialThis works! Whoever thought of this method is genius. Thanks for picking the answer (there were many). Can you explain the method? I did not fully understand. Also, I get compiler warning assigning double to float.

for double you may use this:

```
double bround2dec(double d)
{
// save sign
int sgn = (d < 0.)? -1 : 1;
double dabs = d * sgn;
// convert to 64 bit integer and factor 1000
long long ll1000 = (long long)(dabs * 1000);
// get last digit
int rc = (int) ll1000%10;
// if the first decimal digit which decides whether to round up or down is not 5
// we simply can round by adding 5 and cut by doing integer rounding
if (rc != 5)
return ((ll1000 + 5)/1000.) * sgn;
// if coming here we extract the digit which was subject of being rounded
int rr = (int) ((ll1000-rc)/10)%10;
// if the digit is odd we round up else we round down
return ((rr+1)%2 == 0)? ((ll1000 + 5)/1000.) * sgn : ((ll1000-5)/1000.) * sgn;
}
// you can use it like
#include <sstream>
#include <iostream>
#include <string>
....
double d1 = 20.225;// 225.885;
double d2 = 20.235;// -0.065;
std::ostringstream oss;
// std::ios::fixed means that the number of decimal digits in the fraction given by the setprecison was fixed
// otherwise the precision means the number of significant digits of the decimal number
oss << d1 << " was rounded to " << std::setiosflags( std::ios::fixed ) << std::setprecision(2) << bround2dec(d1) << " "
<< d2 << " was rounded to " << std::setiosflags( std::ios::fixed ) << std::setprecision(2) << bround2dec(d2);
std::string s = oss.str();
```

Sara

Can you explain the method?the explanation was given in the link phoffric has posted:

The float data type can represent all whole numbers, but no fractions, within the range 8388608.0f to 16777216.0f. Any float numbers which are larger than 8388607.5f are whole numbers, and no rounding will be necessary. Adding 8388608.0f to any non-negative float which is smaller than that will yield a whole number which will be rounded according to the current rounding mode (typically round-half-to-even). Subtracting 8388608.0f will then yield a properly-rounded version of the original (assuming it was in a suitable range).

in other words: (positive) integers stored in a float variable are in a special range of the float internal coding. if you add 8388608.0f to any arbitrary float that you want to round properly at the integer boundary (note: test1 was multiplied with 100) you would move the float number into the integer range area and therefore it was rounded correctly by using the standard half-to-even round algorithm. if you finally subtract the 8388608.0f you will get the original float back but rounded.

Sara

the quoted text is in the final part of this lengthy thread posted by a member called 'supercat'.

you can find it easily by searching for "8388608.0f"

Sara

David's code:

Testing -20.125

-20.12

Testing -701.252

-701.25

Your code:

-20.125 was rounded to -20.12 -701.25 was rounded to

Is it because my system is 32 bit?

Is it because my system is 32 bit?

no, bitness shouldn't make any difference (beside that the 8388608.0f is valid for 32-bit float only).

-701.252 must be rounded to .701.25 because the 3rd digit after decimal point is not a '5'.

the return of my function is

((ll1000 + 5)/1000.) * sgn;

what is (701252 + 5)/1000. * (-1)

what is (701257/1000. * (-1)

what is 701.257 * (-1)

what is - 701.26 rounded to 2 decimals.

so, there is a bug in my code which is the division by 1000. (and not 1000) what makes the result a double instead of an integer.

if you change

```
return ((ll1000 + 5)/1000.) * sgn;
```

by

```
return ((ll1000 + 5)/1000) * sgn;
```

it should work correctly.

Sara

>> the explanation was given in the link phoffric has posted:

Please provide the EE link where you are quoting me.

That does not work either. The output is 701.00.

-20.125 was rounded to -20.12 -701.252 was rounded to -701.00

and compiler warning:

warning C4244: 'return' : conversion from '__int64' to 'double', possible loss of data

because: return ((ll1000 + 5)/1000) * sgn; is _int64.

I tweaked to: return ((ll1000

The output is: -20.125 was rounded to -20.12 -701.252 was rounded to -701.25.

With +ve value: -20.125 was rounded to -20.12

The true test of rounding half-even:

20.145 was rounded to 20.14 20.135 was rounded to 20.14

But this does not hit above code.

Final test with David's output:

Testing -701.252

-701.25

Testing 701.252

701.25

-701.252 was rounded to -701.25 701.252 was rounded to 701.25

which matches.

Finally, instead of cout, how do you store your output in a double variable with precision 2?

I was trying so hard remembering where/when I may have made the statement.

Aha, OK, well in the future, try not to take my name in vain. :)

That does not work either.

the corrected code is

```
#include <limits.h>
double bround(double d)
{
// save the sign info
int sgn = (d < 0.)? -1 : 1;
// make it positive
double dabs = d * sgn;
// convert to 64-bit integer
// note a 64-bit integer has a range from -2^63 to 2^63
// while a double is from approximately -1.8 × 10^308 to 1.8 × 10^308
// if that is an issue you may not use the bround function
if (d < (double)(LLONG_MIN/1000) || d > (double)(LLONG_MAX/1000))
{
return d;
}
// convert to 64-bit integer with 3 fractional digits
long long ll1000 = (long long)(dabs * 1000);
// extract last digit
int rc = (int) ll1000%10;
// if not 5 we can do a 'normal rounding' ...
if (rc != 5)
{
// ... by adding 5 to the long long and do an integer division by 10
// so for 0 to 4 we get a maximum of 9 and therefore round down and
// for 6 to 9 we pass the next 10 boundary and round up
// by dividing with 100. we get a double with 2 decimals
return ((ll1000 + 5)/10)/100. * sgn;
}
// extract the forelast digit
int rr = (int) ((ll1000-rc)/10)%10;
// check if even or odd by using modulo 2
// and either add 5 for odd digits or subtract 5 for even digits
// what both means to round to the nearest even integer
return ((rr+1)%2 == 0)? ((ll1000 + 5)/10)/100. * sgn : ((ll1000-5)/10)/100. * sgn;
}
```

Finally, instead of cout, how do you store your output in a double variable with precision 2?

decimal precision is an output feature. a double has two binary components the mantissa and the exponent. with that you can't fix it to 2 decimal places. for nearly all cases (beside of multiples of 2 numbers) a double is either a small amount less or a small amount greater than the a decimal number rounded to 2 decimal places. if you look at the doubles returned by the bround function with the debugger, you will see that the doubles either display like 20.23500000000000... or like -225.229999999999... . the ... digits displayed after 16 significant digits in general are different to the '0' or '9' sequence left from it. that is because a double only has a precision of 16 decimals (approximately 15.95 decimal digits (log10(2^53)) and 53 bits is the length of the mantissa in bits, see https://en.wikipedia.org/wiki/Double-precision_floating-point_format).

so, the only ways to store exactly with precision 2 is either to store strings or to store integers by multiplying the double with 100.

note, a double has 8 bytes, a 32-bit integer 4 bytes and a char buffer would take number of digits + 1 for the decimal point + 1 for the terminating zero character, e. g. "20.24" would need a buffer of 6 bytes.

Sara

I modified your code and now it works for me for large values (which did not work in float method)

```
double bround2dec(double d)
{
// save sign
int sgn = (d < 0.)? -1 : 1;
double dabs = d * sgn;
char buffer[32];
double retVal =0.00;
// convert to 64 bit integer and factor 1000 - This could be an in parameter depending on scale
long long ll1000 = (long long)(dabs * 1000);
// get last digit
long long rc = (long long) ll1000%10;
// if last digit is 5 and before it is even, subtract 5, else add 5
// so 20.905 = 20.90 and 20.915 = 20.92
if (rc == 5)
{
if((ll1000-5)/10%10%2 == 0)
retVal = (ll1000 -5)/1000.* sgn;
else
retVal = (ll1000+5)/1000.* sgn;
}
else
retVal = dabs* sgn;
sprintf(buffer, "%0.2f", retVal);
return atof(buffer);
}
```

I tested out in my app and seems to work for large numbersDo you see any issues?

Sara

C++

From novice to tech pro — start learning today.

Experts Exchange Solution brought to you by

Enjoy your complimentary solution view.

Get every solution instantly with Premium.
Start your 7-day free trial.

Open in new window

Testing 20.225

20.22

Testing 20.235

20.24

https://stackoverflow.com/questions/32746523/ieee-754-compliant-round-half-to-even