0

I have an app which is reading data from PostGresql DB. The column is defined as real. In the java code I am reading the value of this column as BigDecimal. What is happening, the value of this column in DB is 0.18. When I read this data, the java output is showing as 0.180000007. If I define the column as Float in java, I am getting the value as 0.18. I am not doing any monetary calculations in my app. Can someone explain me why BigDecimal is showing so many digits after decimal?

Please refer to the code below, I am trying to understand why BigDecimal is giving so many digits after the decimal:

public class BigDecimalTest {

public static void main(String[] args){
    float float_val = 0.18f;
    BigDecimal output = new BigDecimal(float_val);
    System.out.println("BigDecimal output is: "+ output);

    System.out.println("Float output is: "+float_val);
}

}

Output:

BigDecimal output is: 0.180000007152557373046875
Float output is: 0.18
user3379502
  • 223
  • 4
  • 22
  • 4
    You should read the JavaDoc of the BigDecimal constructor you are using. It clearly states: **"The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (...). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding. "** – OH GOD SPIDERS Oct 30 '20 at 14:39
  • 2
    Yout float has btw exactly the same value. it just prints it different. See also [Is floating point math broken](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – OH GOD SPIDERS Oct 30 '20 at 14:41

2 Answers2

1

Take a look in this article below about some common pitfalls of BigDecimal:

  • The double constructor
  • The static valueOf(double) method
  • The equals(bigDecimal) method
  • The round(mathContext) method

https://blogs.oracle.com/javamagazine/four-common-pitfalls-of-the-bigdecimal-class-and-how-to-avoid-them

0

It's possible you do have some 'smudge' at the far end of the float but you are not actually displayng it. But to precisely answer your question as to why this happens:

Floating point representations are imprecise but have great dynamic range {-very small number ... +very large number}.

The imprecision can wind up as errors in many ways such as converting to some other representation such as BigDecimal that doesn't have a large dyanamic range but is very precise.

So a lot of numbers in floating point can't precisely be represented as-is in BigDecimal without some error. BigDecimal refers to this in the constructor I believe.

Although you didn't ask I will make a suggestion: if you want a float then use java double/float with PostgreSQL double precision/real. If you want precision then use BigDecimal with PostgreSQL decimal/numeric. You get less impedance matching that way. Mixing the types will get you some unexpected results.

There are a lot of guides on floating point and they can get complicated: https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html

But you want to really understand floating point representations if you need to perform calculations.

sagneta
  • 1,546
  • 18
  • 26