简体   繁体   中英

Java Floating Point Precision Issue

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM