-1

Into a Java application I have a unit test that contains the following situation:

BigDecimal rendimentoLordoProvvisiorioExpected = new BigDecimal(2.85000);
BigDecimal rendimentoLordoProvvisiorioDB = null;

rendimentoLordoProvvisiorioDB = pucManager.getRendimentoLordoProvvisorio(date);

assertTrue(rendimentoLordoProvvisiorioExpected.compareTo(rendimentoLordoProvvisiorioDB) == 0);

the value of the rendimentoLordoProvvisiorioExpected variable is manually setted to 2.85000 and the obtained value rendimentoLordoProvvisiorioDB is 2.85000.

The problem is that when I do this comparision into the assertTrue() JUnit function

assertTrue(rendimentoLordoProvvisiorioExpected.compareTo(rendimentoLordoProvvisiorioDB) == 0);

it fail because the rendimentoLordoProvvisiorioExpected seems to be 2.850000000000000088817841970012523233890533447265625 and not 2.85000 (as setted).

Why? How can I modify the previous code to set the rendimentoLordoProvvisiorioExpected to the expected value 2.85000?

AndreaNobili
  • 40,955
  • 107
  • 324
  • 596
  • 3
    You initialize `rendimentoLordoProvvisiorioExpected` using a double which is not precise. Try initializing it with a String instead. – hotzst Aug 30 '16 at 08:50
  • 1
    I wonder why you didn't even read what the JavaDoc of [`BigDecimal(double)`](https://docs.oracle.com/javase/8/docs/api/java/math/BigDecimal.html#BigDecimal-double-). It tells you that `double` is not precise what you should use instead. – Tom Aug 30 '16 at 09:02

2 Answers2

6

Use BigDecimal rendimentoLordoProvvisiorioExpected = new BigDecimal("2.85000"); instead of BigDecimal rendimentoLordoProvvisiorioExpected = new BigDecimal(2.85000); What you did was build a BigDecimal from a double, and doubles are not precise.

uoyilmaz
  • 3,035
  • 14
  • 25
  • What do you mean that double are note precise? It is an approximation or what? – AndreaNobili Aug 30 '16 at 08:51
  • 1
    @AndreaNobili Research .... http://stackoverflow.com/questions/588004/is-floating-point-math-broken – Tom Aug 30 '16 at 09:00
  • Because you are calling the BigDecimal constructor with a double. Doubles are floating point numbers. That's why you should use a string. – vz0 Aug 30 '16 at 09:12
  • Exactly. Tom's link explains it in detail. – uoyilmaz Aug 30 '16 at 09:12
  • Well... if it were so obvious that he is calling BigDecimal ctor with a double he wouldn't have made this question in the first place. It is clear that OP is missing this link, and is missing the issues with floating point. – vz0 Aug 30 '16 at 09:21
  • No one said it was obvious. – uoyilmaz Aug 30 '16 at 10:12
4

Because you are initializing the BigDecimal with a floating point value, by calling the constructor with a double. Doubles are floating point numbers. Use a String:

BigDecimal rendimentoLordoProvvisiorioExpected = new BigDecimal("2.85000");

You should read the documentation of BigDecimal regarding calling the double version of the constructor.

When you use a BigDecimal, you are converting a base two floating point to a base 10 floating point number. There is no perfect base two floating point representation of the number 2.85, the best approximation seems to be a number close to:

>>> decimal.Decimal(2.85)
Decimal('2.850000000000000088817841970012523233890533447265625')

You should read more about floating point, for example What Every Programmer Should Know About Floating-Point Arithmetic.

vz0
  • 32,345
  • 7
  • 44
  • 77