[java] How to resolve a Java Rounding Double issue

Seems like the subtraction is triggering some kind of issue and the resulting value is wrong.

double tempCommission = targetPremium.doubleValue()*rate.doubleValue()/100d;

78.75 = 787.5 * 10.0/100d

double netToCompany = targetPremium.doubleValue() - tempCommission;

708.75 = 787.5 - 78.75

double dCommission = request.getPremium().doubleValue() - netToCompany;

877.8499999999999 = 1586.6 - 708.75

The resulting expected value would be 877.85.

What should be done to ensure the correct calculation?

This question is related to java math rounding

The answer is


To control the precision of floating point arithmetic, you should use java.math.BigDecimal. Read The need for BigDecimal by John Zukowski for more information.

Given your example, the last line would be as following using BigDecimal.

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf("1586.6");
BigDecimal netToCompany = BigDecimal.valueOf("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

This results in the following output.

877.85 = 1586.6 - 708.75

Save the number of cents rather than dollars, and just do the format to dollars when you output it. That way you can use an integer which doesn't suffer from the precision issues.


Another example:

double d = 0;
for (int i = 1; i <= 10; i++) {
    d += 0.1;
}
System.out.println(d);    // prints 0.9999999999999999 not 1.0

Use BigDecimal instead.

EDIT:

Also, just to point out this isn't a 'Java' rounding issue. Other languages exhibit similar (though not necessarily consistent) behaviour. Java at least guarantees consistent behaviour in this regard.


Any time you do calculations with doubles, this can happen. This code would give you 877.85:

double answer = Math.round(dCommission * 100000) / 100000.0;


So far the most elegant and most efficient way to do that in Java:

double newNum = Math.floor(num * 100 + 0.5) / 100;

As the previous answers stated, this is a consequence of doing floating point arithmetic.

As a previous poster suggested, When you are doing numeric calculations, use java.math.BigDecimal.

However, there is a gotcha to using BigDecimal. When you are converting from the double value to a BigDecimal, you have a choice of using a new BigDecimal(double) constructor or the BigDecimal.valueOf(double) static factory method. Use the static factory method.

The double constructor converts the entire precision of the double to a BigDecimal while the static factory effectively converts it to a String, then converts that to a BigDecimal.

This becomes relevant when you are running into those subtle rounding errors. A number might display as .585, but internally its value is '0.58499999999999996447286321199499070644378662109375'. If you used the BigDecimal constructor, you would get the number that is NOT equal to 0.585, while the static method would give you a value equal to 0.585.

double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));

on my system gives

0.58499999999999996447286321199499070644378662109375
0.585

I would modify the example above as follows:

import java.math.BigDecimal;

BigDecimal premium = new BigDecimal("1586.6");
BigDecimal netToCompany = new BigDecimal("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

This way you avoid the pitfalls of using string to begin with. Another alternative:

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf(158660, 2);
BigDecimal netToCompany = BigDecimal.valueOf(70875, 2);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

I think these options are better than using doubles. In webapps numbers start out as strings anyways.


Better yet use JScience as BigDecimal is fairly limited (e.g., no sqrt function)

double dCommission = 1586.6 - 708.75;
System.out.println(dCommission);
> 877.8499999999999

Real dCommissionR = Real.valueOf(1586.6 - 708.75);
System.out.println(dCommissionR);
> 877.850000000000

This is a fun issue.

The idea behind Timons reply is you specify an epsilon which represents the smallest precision a legal double can be. If you know in your application that you will never need precision below 0.00000001 then what he suggests is sufficient to get a more precise result very close to the truth. Useful in applications where they know up front their maximum precision (for in instance finance for currency precisions, etc)

However the fundamental problem with trying to round it off is that when you divide by a factor to rescale it you actually introduce another possibility for precision problems. Any manipulation of doubles can introduce imprecision problems with varying frequency. Especially if you're trying to round at a very significant digit (so your operands are < 0) for instance if you run the following with Timons code:

System.out.println(round((1515476.0) * 0.00001) / 0.00001);

Will result in 1499999.9999999998 where the goal here is to round at the units of 500000 (i.e we want 1500000)

In fact the only way to be completely sure you've eliminated the imprecision is to go through a BigDecimal to scale off. e.g.

System.out.println(BigDecimal.valueOf(1515476.0).setScale(-5, RoundingMode.HALF_UP).doubleValue());

Using a mix of the epsilon strategy and the BigDecimal strategy will give you fine control over your precision. The idea being the epsilon gets you very close and then the BigDecimal will eliminate any imprecision caused by rescaling afterwards. Though using BigDecimal will reduce the expected performance of your application.

It has been pointed out to me that the final step of using BigDecimal to rescale it isn't always necessary for some uses cases when you can determine that there's no input value that the final division can reintroduce an error. Currently I don't know how to properly determine this so if anyone knows how then I'd be delighted to hear about it.


See responses to this question. Essentially what you are seeing is a natural consequence of using floating point arithmetic.

You could pick some arbitrary precision (significant digits of your inputs?) and round your result to it, if you feel comfortable doing that.


Any time you do calculations with doubles, this can happen. This code would give you 877.85:

double answer = Math.round(dCommission * 100000) / 100000.0;


double rounded = Math.rint(toround * 100) / 100;

Although you should not use doubles for precise calculations the following trick helped me if you are rounding the results anyway.

public static int round(Double i) {
    return (int) Math.round(i + ((i > 0.0) ? 0.00000001 : -0.00000001));
}

Example:

    Double foo = 0.0;
    for (int i = 1; i <= 150; i++) {
        foo += 0.00010;
    }
    System.out.println(foo);
    System.out.println(Math.round(foo * 100.0) / 100.0);
    System.out.println(round(foo*100.0) / 100.0);

Which prints:

0.014999999999999965
0.01
0.02

More info: http://en.wikipedia.org/wiki/Double_precision


Another example:

double d = 0;
for (int i = 1; i <= 10; i++) {
    d += 0.1;
}
System.out.println(d);    // prints 0.9999999999999999 not 1.0

Use BigDecimal instead.

EDIT:

Also, just to point out this isn't a 'Java' rounding issue. Other languages exhibit similar (though not necessarily consistent) behaviour. Java at least guarantees consistent behaviour in this regard.


I would modify the example above as follows:

import java.math.BigDecimal;

BigDecimal premium = new BigDecimal("1586.6");
BigDecimal netToCompany = new BigDecimal("708.75");
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

This way you avoid the pitfalls of using string to begin with. Another alternative:

import java.math.BigDecimal;

BigDecimal premium = BigDecimal.valueOf(158660, 2);
BigDecimal netToCompany = BigDecimal.valueOf(70875, 2);
BigDecimal commission = premium.subtract(netToCompany);
System.out.println(commission + " = " + premium + " - " + netToCompany);

I think these options are better than using doubles. In webapps numbers start out as strings anyways.


double rounded = Math.rint(toround * 100) / 100;

As the previous answers stated, this is a consequence of doing floating point arithmetic.

As a previous poster suggested, When you are doing numeric calculations, use java.math.BigDecimal.

However, there is a gotcha to using BigDecimal. When you are converting from the double value to a BigDecimal, you have a choice of using a new BigDecimal(double) constructor or the BigDecimal.valueOf(double) static factory method. Use the static factory method.

The double constructor converts the entire precision of the double to a BigDecimal while the static factory effectively converts it to a String, then converts that to a BigDecimal.

This becomes relevant when you are running into those subtle rounding errors. A number might display as .585, but internally its value is '0.58499999999999996447286321199499070644378662109375'. If you used the BigDecimal constructor, you would get the number that is NOT equal to 0.585, while the static method would give you a value equal to 0.585.

double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));

on my system gives

0.58499999999999996447286321199499070644378662109375
0.585

So far the most elegant and most efficient way to do that in Java:

double newNum = Math.floor(num * 100 + 0.5) / 100;

Save the number of cents rather than dollars, and just do the format to dollars when you output it. That way you can use an integer which doesn't suffer from the precision issues.


It's quite simple.

Use the %.2f operator for output. Problem solved!

For example:

int a = 877.8499999999999;
System.out.printf("Formatted Output is: %.2f", a);

The above code results in a print output of: 877.85

The %.2f operator defines that only TWO decimal places should be used.


See responses to this question. Essentially what you are seeing is a natural consequence of using floating point arithmetic.

You could pick some arbitrary precision (significant digits of your inputs?) and round your result to it, if you feel comfortable doing that.


Another example:

double d = 0;
for (int i = 1; i <= 10; i++) {
    d += 0.1;
}
System.out.println(d);    // prints 0.9999999999999999 not 1.0

Use BigDecimal instead.

EDIT:

Also, just to point out this isn't a 'Java' rounding issue. Other languages exhibit similar (though not necessarily consistent) behaviour. Java at least guarantees consistent behaviour in this regard.


This is a fun issue.

The idea behind Timons reply is you specify an epsilon which represents the smallest precision a legal double can be. If you know in your application that you will never need precision below 0.00000001 then what he suggests is sufficient to get a more precise result very close to the truth. Useful in applications where they know up front their maximum precision (for in instance finance for currency precisions, etc)

However the fundamental problem with trying to round it off is that when you divide by a factor to rescale it you actually introduce another possibility for precision problems. Any manipulation of doubles can introduce imprecision problems with varying frequency. Especially if you're trying to round at a very significant digit (so your operands are < 0) for instance if you run the following with Timons code:

System.out.println(round((1515476.0) * 0.00001) / 0.00001);

Will result in 1499999.9999999998 where the goal here is to round at the units of 500000 (i.e we want 1500000)

In fact the only way to be completely sure you've eliminated the imprecision is to go through a BigDecimal to scale off. e.g.

System.out.println(BigDecimal.valueOf(1515476.0).setScale(-5, RoundingMode.HALF_UP).doubleValue());

Using a mix of the epsilon strategy and the BigDecimal strategy will give you fine control over your precision. The idea being the epsilon gets you very close and then the BigDecimal will eliminate any imprecision caused by rescaling afterwards. Though using BigDecimal will reduce the expected performance of your application.

It has been pointed out to me that the final step of using BigDecimal to rescale it isn't always necessary for some uses cases when you can determine that there's no input value that the final division can reintroduce an error. Currently I don't know how to properly determine this so if anyone knows how then I'd be delighted to hear about it.


Although you should not use doubles for precise calculations the following trick helped me if you are rounding the results anyway.

public static int round(Double i) {
    return (int) Math.round(i + ((i > 0.0) ? 0.00000001 : -0.00000001));
}

Example:

    Double foo = 0.0;
    for (int i = 1; i <= 150; i++) {
        foo += 0.00010;
    }
    System.out.println(foo);
    System.out.println(Math.round(foo * 100.0) / 100.0);
    System.out.println(round(foo*100.0) / 100.0);

Which prints:

0.014999999999999965
0.01
0.02

More info: http://en.wikipedia.org/wiki/Double_precision


See responses to this question. Essentially what you are seeing is a natural consequence of using floating point arithmetic.

You could pick some arbitrary precision (significant digits of your inputs?) and round your result to it, if you feel comfortable doing that.


Any time you do calculations with doubles, this can happen. This code would give you 877.85:

double answer = Math.round(dCommission * 100000) / 100000.0;


Better yet use JScience as BigDecimal is fairly limited (e.g., no sqrt function)

double dCommission = 1586.6 - 708.75;
System.out.println(dCommission);
> 877.8499999999999

Real dCommissionR = Real.valueOf(1586.6 - 708.75);
System.out.println(dCommissionR);
> 877.850000000000

As the previous answers stated, this is a consequence of doing floating point arithmetic.

As a previous poster suggested, When you are doing numeric calculations, use java.math.BigDecimal.

However, there is a gotcha to using BigDecimal. When you are converting from the double value to a BigDecimal, you have a choice of using a new BigDecimal(double) constructor or the BigDecimal.valueOf(double) static factory method. Use the static factory method.

The double constructor converts the entire precision of the double to a BigDecimal while the static factory effectively converts it to a String, then converts that to a BigDecimal.

This becomes relevant when you are running into those subtle rounding errors. A number might display as .585, but internally its value is '0.58499999999999996447286321199499070644378662109375'. If you used the BigDecimal constructor, you would get the number that is NOT equal to 0.585, while the static method would give you a value equal to 0.585.

double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));

on my system gives

0.58499999999999996447286321199499070644378662109375
0.585

See responses to this question. Essentially what you are seeing is a natural consequence of using floating point arithmetic.

You could pick some arbitrary precision (significant digits of your inputs?) and round your result to it, if you feel comfortable doing that.


It's quite simple.

Use the %.2f operator for output. Problem solved!

For example:

int a = 877.8499999999999;
System.out.printf("Formatted Output is: %.2f", a);

The above code results in a print output of: 877.85

The %.2f operator defines that only TWO decimal places should be used.


Save the number of cents rather than dollars, and just do the format to dollars when you output it. That way you can use an integer which doesn't suffer from the precision issues.


As the previous answers stated, this is a consequence of doing floating point arithmetic.

As a previous poster suggested, When you are doing numeric calculations, use java.math.BigDecimal.

However, there is a gotcha to using BigDecimal. When you are converting from the double value to a BigDecimal, you have a choice of using a new BigDecimal(double) constructor or the BigDecimal.valueOf(double) static factory method. Use the static factory method.

The double constructor converts the entire precision of the double to a BigDecimal while the static factory effectively converts it to a String, then converts that to a BigDecimal.

This becomes relevant when you are running into those subtle rounding errors. A number might display as .585, but internally its value is '0.58499999999999996447286321199499070644378662109375'. If you used the BigDecimal constructor, you would get the number that is NOT equal to 0.585, while the static method would give you a value equal to 0.585.

double value = 0.585;
System.out.println(new BigDecimal(value));
System.out.println(BigDecimal.valueOf(value));

on my system gives

0.58499999999999996447286321199499070644378662109375
0.585

Any time you do calculations with doubles, this can happen. This code would give you 877.85:

double answer = Math.round(dCommission * 100000) / 100000.0;


Save the number of cents rather than dollars, and just do the format to dollars when you output it. That way you can use an integer which doesn't suffer from the precision issues.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to math

How to do perspective fixing? How to pad a string with leading zeros in Python 3 How can I use "e" (Euler's number) and power operation in python 2.7 numpy max vs amax vs maximum Efficiently getting all divisors of a given number Using atan2 to find angle between two vectors How to calculate percentage when old value is ZERO Finding square root without using sqrt function? Exponentiation in Python - should I prefer ** operator instead of math.pow and math.sqrt? How do I get the total number of unique pairs of a set in the database?

Examples related to rounding

How to round a numpy array? How to pad a string with leading zeros in Python 3 Python - round up to the nearest ten How to round a Double to the nearest Int in swift? Using Math.round to round to one decimal place? How to round to 2 decimals with Python? Rounding to 2 decimal places in SQL Rounding to two decimal places in Python 2.7? Round a floating-point number down to the nearest integer? Rounding BigDecimal to *always* have two decimal places