*
The moose likes Beginning Java and the fly likes Rounding Error in a calculateLitresPer100Km method - read on for more details Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "Rounding Error in a calculateLitresPer100Km method - read on for more details" Watch "Rounding Error in a calculateLitresPer100Km method - read on for more details" New topic
Author

Rounding Error in a calculateLitresPer100Km method - read on for more details

Vadim Konkov
Greenhorn

Joined: Sep 30, 2008
Posts: 8
Hi, I'm just looking for some help on how to fix the rounding error in the following method:



In the JUnitTest scenario, kilometers is 123.4 and litres is 10.5 - JUnitTest expects 8.502024291497976E-4 but gets 8.502024291497975

All variables used in above code are doubles.

I am thinking there is some sort of easy solution to this that I'm overlooking. The rest of my code does not affect this method whatsoever.

Thanks for looking and any potential help.
Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 2982
    
    9
Have you looked at the JavaDoc API for the assertEquals() method you're using? (At least I assume you're using one, though it's not entirely clear what you're doing here.) Make sure you get the right types of the parameters - they're both doubles, right? The docs should give you a hint about what to do instead.


Vadim Konkov
Greenhorn

Joined: Sep 30, 2008
Posts: 8
Thanks for the reply but that won't work for me. Here is the whole code if it will help make the problem clearer. Also the JUnitTest cases would substitute a double value for the kilometers and litres, and than expects a certain answer for the litresPer100Km to test if it is coded properly.

Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 2982
    
    9
I think we need to see what you're doing in the test code. I'm pretty sure that there is an assertEquals() method that will help you, if you look carefully.
Tom Johnson
Ranch Hand

Joined: May 11, 2005
Posts: 142
Please please please change your code to use BigDecimal or you will be chasing errors like this for a long long time. See my post here for issues I was having.

If you change to use BigDecimal, you can specify both the scale (number of decimal places) of the operations and also the mode of rounding e.g, BigDecimal.ROUND_HALF_UP. This will cleanup these errors for you. Note, always use the BigDecimal constructor that takes a String, not a double as this one leads to imprecise values.


<a href="http://faq.javaranch.com/java/UseCodeTags" target="_blank" rel="nofollow">Use Code Tags!!</a>
Mike Simmons
Ranch Hand

Joined: Mar 05, 2008
Posts: 2982
    
    9
I disagree. Tom, you were dealing with numbers representing money, which is something people expect to be reduced to a nice simple two digits after the decimal point. Ten dollars divided three ways gives each person $3.33, while the programmer figures out how to pocket the roundoff error and make millions. (C.F. Office Space and Superman III.) But look at the quantities he's dealing with in the code above. They're real numbers, meaning not integers. And not "decimal" values which are really integers divided by a power of ten. They've got lots of digits, and while it's usually unlikely that more than the first three or four are actually of interest to anyone, there's also no reason to throw away accuracy prematurely - e.g. by rounding 10/3 to 3.33, when 3.33333333333333333 is more accurate. In other words, these are the sorts of calculations where programmers should use double, or occasionally float - floating point primitives, in both cases.

Calculations with primitives offer several advantages in Java. For starters, they're easier to read, since you don't have to write things like x.add(y.multiply(z)) when you can write x + y * z. (And that was a minimal example.) They're also significantly faster and less memory-intensive, if those concerns are actually pertinent. (In this day and age, they usually aren't, unless you're doing a lot of math.) And they don't round off values needlessly just to provide a false sense of security for people who don't want to see a lot of decimal places. If, after doing the math, you want to simplify the results for people who want to see results like 3.14 rather than 3.14159265, well you can do that with DecimalFormat, or with a format string like "%5.2f". and you can do that without pointlessly losing data from the actual calculations. Displaying simplified data is a presentation issue - don't mangle your data for it.

And lastly, if you want to write tests verifying the accuracy of results using double, you need to look at the actual API for the test framework you're using. Expecting "exact" equality of calculations is a fool's errand to begin with, so the tester needs to adjust expectations. But JUnit does handle this sort of thing in their API. Hint: the signatures to look for are

or

 
wood burning stoves
 
subject: Rounding Error in a calculateLitresPer100Km method - read on for more details
 
Similar Threads
Rounding of doubles for infinitely long numbers
Junit test: cannot find test Method although that it is already defined in the test class
error: package junit.framework does not exist
Code Error
converting a double value