Showing posts with label Computer. Show all posts
Showing posts with label Computer. Show all posts

Sunday, February 15, 2009

Floating point numbers and mysterious roundups...

I'm sure not many Java programmers would've ended up in this situation... Ever tried inserting a floating point number into a database ending up in arbitrary roundups? If so, you know what I'm talking about...

Let's say we need to get the price of some commodity from an input source and insert it into a table. Assuming that the variable is f and it's value is 44.55 (just an example), wouldn't you be surprised to see 44.6 in the database when the code snippet looks something like this?

PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setFloat(f);
System.out.println(f);
pstmt.executeUpdate();

The out.println would print exactly what you expect it to: 44.55; but chances are that this number is rounded off to 44.6 in the database... Simple problem but might sound mysterious too.

Java's float and double classes take the mathematical constant e as their base and hence not every decimal (base 10) floating point number can be represented with the same accuracy in float or double. The spec says floating point numbers are for those values that are fundamentally inaccurate to begin with, like readings of an experiment which can't be precise to 2 decimals and even if it is not precise to 2 decimals chances are that the results aren't altered drastically.

Coming back to our original problem, what is the solution?
The solution is NOT to use floating point or double datatypes.

So what datatype should I use?
BigDecimal.

What on world is that?
That is the decimal that you and I understand - to the base 10.

How to use it?
Pretty straightforward like any other wrapper classes.

PreparedStatement pstmt = con.prepareStatement(query);
pstmt.setBigDecimal(bigDecimal);
pstmt.executeUpdate();

This would solve your problem. Remember, BigDecimal has a lot of overloaded constructors and the simplest I could think of is to use new BigDecimal("12.34"); -- don't forget the quotes. :)