posted 4 years ago

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.

So my code is

Run using

Output obviously is

Just wondering if my idea of a static method is a good way to handle this situation? In my package, I would just stick it in a class of static utility methods. Thanks for any feedback!

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.

So my code is

Run using

Output obviously is

Just wondering if my idea of a static method is a good way to handle this situation? In my package, I would just stick it in a class of static utility methods. Thanks for any feedback!

posted 4 years ago

I like the abstraction provided by your threeStepRound function, but I would use a BigDecimal instead of primitives arithmetic.

Campbell Ritchie

Marshal

Posts: 55761

163

posted 4 years ago

Agree.

Agree that is a function and can therefore be a static method. In fact that sort of thing should probably be in a utility class.You can overload that method to take

Agree that is a function and can therefore be a static method. In fact that sort of thing should probably be in a utility class.You can overload that method to take

`float`s. Note you will get all sorts of imprecision with floating‑point arithmetic, which is why Bill Clar recommends decimal arithmetic. The output of this code:-…will__not__show any signs of rounding. It will most probably start with 1234567890, though. The second value of d might be different from the original value.
Campbell Ritchie

Marshal

Posts: 55761

163

posted 4 years ago

But you are right that rounding would introduce new imprecision.

That does not constitute real rounding; you are not altering the value, but simply the way it is displayed.Jayesh A Lalwani wrote:. . . I would never round numbers until they have to be displayed, and then I would just do it in the Formatter

But you are right that rounding would introduce new imprecision.

posted 4 years ago

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,

HTH

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

"Il y a peu de choses qui me soient impossibles..."