3

I've already looked at this asnwer.

I was a little confused by the behaviour of BigDecimal.valueOf(float). Here's the example:

System.out.println(BigDecimal.valueOf(20.2f)); //prints 20.200000762939453

Therefore

float f = BigDecimal.valueOf(20.2f)
            .setScale(2, RoundingMode.UP)
            .floatValue();
System.out.println(f); //prints 20.21

Which is defenitely not the behaviour I expected. Is there a way to round up float correctly avoiding such errors?

Community
  • 1
  • 1
stella
  • 2,546
  • 2
  • 18
  • 33
  • Take a look at [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken). Finite precision floating point numbers inherently can't represent some values. It's somewhat similar to how 1/3 can't be represented exactly in base 10. Here `20.2f != 20.2`. – Zong May 29 '16 at 06:17
  • @ZongZhengLi Very interesting. So I we deal with floating-point arithmetic and want to keep the exact precision, should we perform ROUND_EVEN any time we perform an arithmetic operations on them? – stella May 29 '16 at 06:28
  • What is the expected output? It looks correct to me, 20.200000762939453 rounded up to 2 decimal places is 20.21. You could try setting the scale to a larger number with round even and then set to 2 with round up – samgak May 29 '16 at 06:56

1 Answers1

5

For the description of float and how it utilizes the allocated bits see How many significant digits have floats and doubles in java?

BigDecimal works fine and -- as expected -- keeps all digits it received, but it can't guess the precision of the given argument. Therefore:

    float f = 20.20f;
    System.out.println("Float: "+f);
    System.out.println("BigDecimal.valueOf: "+BigDecimal.valueOf(f));
    System.out.println("BigDecimal from value: "+new BigDecimal(f, MathContext.DECIMAL32));
    System.out.println("BigDecimal from string: "+new BigDecimal(""+f));;

Prints:

Float: 20.2
BigDecimal.valueOf: 20.200000762939453
BigDecimal from value: 20.20000
BigDecimal from string: 20.2
Community
  • 1
  • 1
Andrey Lebedenko
  • 1,850
  • 17
  • 24