Floating point arithmetic not producing exact results
This question already has an answer here:
If you need exact decimal values, you should use java.math.BigDecimal
. Then read "What Every Computer Scientist Should Know About Floating-Point Arithmetic" for the background of why you're getting those results.
(I have a .NET-centric article which you may find easier to read - and certainly shorter. The differences between Java and .NET are mostly irrelevant for the purposes of understanding this issue.)
Floating point numbers use binary fractions and not decimal fractions. That is, you're used to decimal fractions made up of a tenths digit, a hundredths digit, a thousandths digit, etc. d1/10 + d2/100 + d3/1000 ... But floating point numbers are in binary, so they have a half digit, a quarter digit, an eighth digit, etc. d1/2 + d2/4 + d3/8 ...
Many decimal fractions cannot be expressed exactly in any finite number of binary digits. For example, 1/2 is no problem: in decimal it's .5, in binary it's .1. 3/4 is decimal .75, binary .11. But 1/10 is a clean .1 in decimal, but in binary it's .0001100110011... with the "0011" repeating forever. As the computer can store only a finite number of digits, at some point this has to get chopped off, so the answer is not precise. When we convert back to decimal on output, we get a strange-looking number.
As Jon Skeet says, if you need exact decimal fractions, use BigDecimal. If performance is an issue, you could roll your own decimal fractions. Like, if you know you always want exactly 3 decimal places and that the numbers will not be more than a million or so, you could simply use int's with an assumed 3 decimal places, making adjustments as necessary when you do arithmetic and writing an output format function to insert the decimal point in the right place. But 99% of the time performance isn't a big enough issue to be worth the trouble.
Floating-point numbers are imprecise, especially since they work in binary fractions (1/2, 1/4, 1/8, 1/16, 1/32, ...) instead of decimal fractions (1/10, 1/100, 1/1000, ...). Just define what you feel is "close enough" and use something like Math.abs(ab) < 0.000001
.
上一篇: JavaScript添加十进制数字问题
下一篇: 浮点算法不能产生精确的结果