I made a small post about
Inexact rounding up or down with decimal digits.
But it is also possible to run into the same bug when rounding floating point numbers to the next number with
restricted decimal digits. A really common example is the price calculation. You have the price 1.99
for example and the tax is maybe 19%. The resulting price with tax would be 2.3681
. So you will
need to round the price with two decimal digits to 2.37
.
A similar scenario as in the mentioned post from above. I will assume that we want to round the number
0.145
with two decimal digits. The expected result should be 0.15
, cause we round half up.
Here some naive implementations that I have done myself in the past and that are pretty often used in some common programming languages.
The naive Java implementation looks like this.
public static double naiveRound2Digits(double number) {
return Math.round(number * 100) / 100.0;
}
The output of the following call is 0.14
instead of 0.15
.
System.out.println(naiveRound2Digits(0.145));
The same naive function in JavaScript.
function naiveRound2Digits( number ) {
return Math.round( number * 100 ) / 100;
};
The same wrong result 0.14
.
console.log( naiveRound2Digits( 0.145 ) );
The naive implementation in Python.
def naiveRound2Digits( number ):
return round( number * 100 ) / 100;
Again the wrong result 0.14
.
print naiveRound2Digits( 0.145 );
Same procedure as in the other post that I mentioned above, I will give a last naive example in the programming langiage C just to make clear this problem has nothing incommon with the choice of the programming language.
double naiveRound2Digits(double number) {
return round(number * 100) / 100;
}
Here the same wrong result 0.140000
.
printf("%f\n", naiveRound2Digits(0.145));
All naive implementations have the same procedure with the following three steps.
100
100
Our example input 0.145
has the following behavior.
0.145 * 100 = 14.499999999999998
Step 1 has one small error of 0.000000000000002
that is normal for floating point numbers, but step 2
is increasing our error now. Instead of rounding up on the half, we are rounding down.
I wil show now some better implementations for all four programming languages that are mentioned above.
The implementation in Java.
public static double round2Digits(double number) {
return Math.round(Math.round(number * 1000) / 10.0) / 100.0;
}
With the right result 0.15
.
System.out.println(round2Digits(0.145));
The implementation in JavaScript.
function round2Digits( number ) {
return Math.round( Math.round( number * 1000 ) / 10 ) / 100;
};
As expected the right result 0.15
.
console.log( round2Digits( 0.145 ) );
The implementation in Python.
def round2Digits( number ):
return round( round( number * 1000 ) / 10 ) / 100;
The same right result 0.15
.
print round2Digits( 0.145 );
The implementation in C.
double round2Digits(double number) {
return round(round(number * 1000) / 10) / 100;
}
Again the same exact result 0.150000
.
printf("%f\n", round2Digits(0.145));
The inexact claculation or rounding from above is really a problem has is known and common for floating point numbers. Here are the steps from the more exact soltions.
1000
10
100