I have a question regarding floating point arithmetic in java and its precision. I did do my research on here and via google and come across some solutions but am having difficulties implementing them in my design. So in Java I am making use of the BigDecimal class in getting my calculations accurate. Note that the variables are double and the values can have a precision up to 8 decimal places to the right when doing calculations. The result (precision) to display is known and thats what I'll be storing as the current value. Also, all values come in dynamically (through a method). The argument passed should be the currentValue + the step size.
public void newValue(float value) {
//Clip to valid range, can't go over minimum/max value
value = Math.max(minimumValue, Math.min(maximumValue, value));
// TODO Implement better Floating Point Arithmetic precision
MathContext mcI = new MathContext(0, RoundingMode.HALF_UP);
MathContext mcF = new MathContext(8, RoundingMode.HALF_UP);
BigDecimal valueBD = new BigDecimal(value, mcF);
BigDecimal minimumBD = new BigDecimal(minimumValue, mcF);
BigDecimal stepBD = new BigDecimal(step, mcF);
BigDecimal currentValueBD = new BigDecimal(currentValue, mcF);
BigDecimal totalStepsBD = valueBD.subtract(minimumBD, mcF);
//Ensure value is divisible by stepsize
totalStepsBD = totalStepsBD.divide(stepBD, mcI);
valueBD = stepBD.multiply(totalStepsBD, mcF);
valueBD = valueBD.add(minimumBD, mcF);
// arithmetic without using BigDecimal (old)
//int totalSteps = (int) ((value- minimumValue)/ step);
//value = totalSteps * step + minimumValue;
if(!(valueBD.equals(currentValueBD))) {
valueBD = valueBD.setScale(displayPrecision, RoundingMode.HALF_UP);
currentValue = valueBD.floatValue();
dispatch();
}
}
Now, it works with some values but not all. Especially when I mess with the step size. So if step = 0.1 it was fine. If I made it 0.005, I'd get an AirthmeticException - non terminating decimal expansion on the step where
totalStepsBD = totalStepsBD.divide(stepBD, mcI);
When .005 is set for the step variable, after making a BigDeciaml (stepBD) it comes out to .0049999999... Not sure if that helps but if you have any ideas please let me know. Thank you.
Pass a String step
(and a String value
) to the BigDecimal
constructor. You can't precisely represent 0.005
as a double
(or a float
).
BigDecimal stepBD = new BigDecimal("0.005"); // <-- works as a `String`.
Edit
Or as noted below, use BigDecimal.valueOf(double)
BigDecimal stepBD = BigDecimal.valueOf(0.005);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With