When can I use floating point types in Java for cash settlement?

I found out that I cannot use floating point types ( float / double in Java) to do money calculations (and any other calculations when I need accurate results). I have to use decimal number types ( BigDecimal in Java).

Now I understand when I can use floating point types. Do they provide any guarantees of accuracy? Suppose I would like to calculate some formula with an accuracy of 0.001 . How do I know if I can use floating point types for this calculation or not?

+4
source share
5 answers

You can use floating point types in Java or other languages ​​when you can demonstrate that the results are acceptable for your application.

Using BigDecimal alone does not solve this problem. For example, suppose a bank account contains 87.34 US dollars, and you must add interest within one month, taking into account the annual interest rate of 2.37%. First, BigDecimal will not correctly calculate the monthly interest rate because you have to divide 2.37% by 12, and 2.37 / 12 (or .0237 / 12) are not exactly represented in decimal. Secondly, even if BigDecimal correctly calculated the monthly interest rate and correctly calculated the interest for $ 87.34, you probably still have to round this amount to a certain number of cents before adding it to the balance sheet. The rules for this rounding may be specified in some legal document and may not correspond to how BigDecimal does rounding.

Both decimal floating point numbers and binary floating point values ​​are able to calculate many results accurately, much more accurately than the .001 precision that you suggest in your example. Both of them can also create significant errors when used in different ways.

Therefore, to use a floating point, you must understand what values ​​types can represent, what errors occur in floating point operations, what operations you will perform, and what your application requires. Often you can avoid floating point errors by carefully processing the operations. For example, you can work with currencies by scaling amounts to integer values ​​(use 8734 to represent $ 87.34 instead of 87.34 to represent 87.34). As another example, you can demonstrate that the accumulated error of several operations is less than half a percent, and therefore you can perform operations and round the final result to the nearest value, and this will be correct, because the error has never been large enough so that the final answer is wrong.

+7
source

I found out that I cannot use floating point types (float / double in Java) to calculate cash

You cannot use double to accurately represent money worth more than $ 70 trillion. For values ​​less than this, you can use double or long without errors (provided that you use the appropriate rounding)

IMHO using double easier to work with if you understand the need for rounding.

However, many believe that his error is subject to esp, because you do not know who might need to maintain the code. Using BigDecimal will ensure proper rounding and give you several options for how this works.

Many people think that even 0.1 does not represent exactly, and BigDecimal can display the exact representation (and why you should be careful with how you convert to BigDecimal)

 System.out.println(new BigDecimal(0.1)); 

prints

 0.1000000000000000055511151231257827021181583404541015625 

Many use inefficiently

 new BigDecimal(Double.toString(0.1)) 

or the like, which works, but ironically, it’s as accurate as the toString method, which they are trying to avoid.

A more efficient way to do this:

 BigDecimal.valueOf(0.1) 

This avoids the need to create a string.

Libraries supporting double will correctly display this number, but once you do the calculation, the default round may not be enough.

 System.out.println(0.1 * 3); 

prints

 0.30000000000000004 

In this situation, you must say what accuracy you expect. Say you have a dollar and cents that you can use

 System.out.printf("%.2f%n", 0.1 * 3); // round output to two decimal places 

prints

 0.30 

To find where you can no longer add 0.01

 for (double d = 1; d < Long.MAX_VALUE; d *= 2) { long l = Double.doubleToLongBits(d); double d1 = Double.longBitsToDouble(l + 1); if (d1 - d > 0.01) { System.out.println("Cannot represent " + d + " plus 0.01"); double d_1 = Double.longBitsToDouble(l - 1); if (d - d_1 < 0.01) System.out.println("Can represent " + d + " minus 0.01"); break; } } 

prints

 Cannot represent 7.0368744177664E13 plus 0.01 Can represent 7.0368744177664E13 minus 0.01 
+2
source

Suppose I would like to calculate some formula with an accuracy of 0.001. How do I know if I can use floating point types for this calculation or not?

Floating-point types are base-2, not base-10. 1 / (10 ^ n) cannot be represented exactly in binary floating-point numbers, since 1/3 cannot be exactly indicated in decimal value. Floating-point numbers are useful for scientific-type calculations, where the values ​​can be large or small, and the measurement uncertainty overshadows the accuracy limits of a computer. Floating-point operations are pretty fast, on hardware that supports it, while other non-integer types are not so fast.

Floating-point numbers are so called because the number of digits on each side of the fractional point will vary depending on the number. Floating-point numbers are essentially represented as +/- 1.a * 2^b , where a and b are base-2 numbers. This is akin to the decimal basis of Scientific Notation 1.a * 10^b . For more information on the IEEE 754 floating point, see the Wikipedia article.

+1
source

This video just appeared about this topic:

http://www.youtube.com/watch?v=PZRI1IfStY0

This is a great and simple description of the description of the problem with floating point operations. They also mention the issue of cash settlement with floating point numbers.

+1
source

Floating-point types are hardware dependent, so there is no guarantee of overall accuracy. You can use them when the result does not have to be "perfect."

See: http://en.wikipedia.org/wiki/Pentium_FDIV_bug

From wikipedia: ( http://en.wikipedia.org/wiki/Floating_point )

~ 7.2 decimal places for float

~ 15.9 deciamls for double

This means that no matter where the period is, there will always be a limited number of exact digits in the number.

-1
source

All Articles