I have a problem for the managemente of decimal number in java (JDK 1.4).
I have two double numbers first and second (as output of formatted String). I do a sum between fist and second and I receive a number with more decimal digits!
final double first=198.4;//value extract by unmodifiable format method
final double second=44701.2;//value extract by unmodifiable format method
final double firstDifference= first+second; //I receive 44899.598 instead of 44899.6
final double calculatedDifference=44900.1; // comparison value for the flow
final double error=firstDifference-calculatedDifference;// I receive -0.50390605 instead 0.5
if(Math.abs(error)<=0.5d)){
//I must enter in this branch but the error not allows the correct flow!!!
}
/***
* the flow of program is uncorrect and there's a very visible bug in business view
*/
I prefer not growing the threshold value (0.5d) because I'm not safe with similar situation (when I started coding, the specs was talking about 0.1d as comparison value). If it's the only solution, the value of 0.9d is safest value for this problem?
How I can resolve this situation? I thinked that this problem derive by the use of double variables, but with the float I have the same problem.
Some idea (having some tested code line, if possible ;))?
You can get rounding error, but I don't see it here.
final double first=198.4;//value extract by unmodifiable format method
final double second=44701.2;//value extract by unmodifiable format method
final double firstDifference= first+second; //I receive 44899.6
final double calculatedDifference=44900.1; // comparison value for the flow
final double error=firstDifference-calculatedDifference;// I receive -0.5
if(Math.abs(error)<=0.5d){
// this branch is entered.
System.out.println(error);
}
prints
-0.5
There are two ways to handle this more generally. You can define a rounding error such as
private static final double ERROR = 1e-9;
if(Math.abs(error)<=0.5d + ERROR){
OR use rounding
final double firstDifference= round(first+second, 1); // call a function to round to one decimal place.
OR use integers with fixed precision
final int first=1984;// 198.4 * 10
final int second=447012; // 44701.2 * 10
final int firstDifference= first+second; //I receive 448996
final int calculatedDifference=449001; // comparison value for the flow
final int error=firstDifference-calculatedDifference;// I receive -5
if(Math.abs(error)<=5){
// this branch is entered.
System.out.println(error);
}
OR You can use BigDecimal. This is often the preferred solution for many developers, but a last option IMHO. ;)
This error will depend slightly on your version of Java (and I see you are using a slightly old one). However, regardless of Java version, for best results when you are particularly worried about decimal accuracy in java, you should use the BigDecimal
class for your values.
This is what financial applications use for handling currency, and also what many industrial Java applications use when precision is essential.
EDIT: I see many valid comments that this solution comes with a slight performance hit (also depends on the number of operations you are doing in the first place). And really, if this is the only single place that you encounter an issue and you dont care about precision after it, then ya, go for a workaround. But if this happens frequently and in more than one place, or if you think you might be expanding your application in the future, I would use the safer BigDecimal
.
Double items store number in powers of 2. It is not possible to accurately represent a lot of numbers in terms of powers of 2 and so you get rounding issues. The same problem when using floats.
If you want to reduce these, use the Decimal type for the numbers, this should prove to be more accurate.
For doubles and floats, you must use the < comparator to check if 2 numbers are close enough to be considered equal.
See this for more details -> What is the most effective way for float and double comparison?
I've tested and on my machine everything is correct (tested in java 1.6). If I were you I would test strictfp modifier to method which has above operations:
public static strictfp void main(String[] args)
The problem can be connected with java version, OS, CPU you're using
I agree with Peter, I don't see that happening either. However, if it keeps happening to you and if the number of decimals is known and fixed in your usecase anyway, using "int" might be a solution, that's even faster than floating point operations. For the views you would then have to convert to floating points, of course.
来源:https://stackoverflow.com/questions/5423545/sum-of-decimal-number-in-java