Eric Barnhill wrote:Hi,
I'm pretty inexperienced with code strategy so I just wondered if this was a good one. For something like rounding, in which in my experience a few steps are needed to get around Java arithmetic issues, is a static method that takes the necessary few steps a good way to handle the difficulty.
Could you say a bit more about what you mean by, "Java arithmetic issues"? At line 7 of your code, your output is 10 because Math.round(value * 1000) returns a long (when value is a double). Dividing a long by another long (in this case, 1000), yields an integer result, (in this case, 10). However, if you change the divisor in line 7 from a long to a double, which you can do with the insertion of a decimal point, thus:
the long returned by Math.round is coerced into a double. When one double is divided by another, the result is also a double. In this case, the output of the program becomes this:
Now, Java doubles do a pretty good job of faking real numbers (better than floats), but even they have their limits. Consider this:
I get this output:
If doubles were pure real numbers, that should have been 1.0. But no finite state machine can represent all real numbers. Which means, even all the way back to your initial input, the very first numeric value stored in your "value" variable may not have been (and probably wasn't) exactly 10.79865. In an extreme case, you could input a
string with three decimal places, multiply it by 1000, divide it back again, and discover that the inherent rounding of doubles themselves had thrown your last digit off by one.
I don't have a string at hand that can show you this (and Java's ability to cope with this issue may well be subtler than I know), but consider these lines of code:
Output ought to be 0.0, right? Nope, it's this:
Which is pretty close to zero, but it wouldn't return true if you coded this:
All of which means that, if you need accuracy to some number of decimal places (greater than zero, that is), that you can absolutely rely on,
don't represent your value at any point in your calculations as a double (or a float, of course). From that very first assignment to such a variable, you are losing
some amount of precision (there are exceptional cases where a double can store a real number with absolute precision, but there are an
infinite number of real numbers that it
cannot store with infinite precision). Instead, either find a way to represent your data entirely in an integer format (for example, if you are sure you only ever need three decimal places, you could do all your calculations in integers scaled by 1,000), or use one of the classes designed for this (like BigDecimal, I would guess, though I never use it, myself).
HTH