Float精度丢失的原因

简介: Float精度丢失的原因

代码

BigDecimal_0_1=newBigDecimal(0.1);
BigDecimalx=_0_1;
for(inti=1; i<=10; i++) {
System.out.println(i+" x 0.1 is "+x+", as double "+x.doubleValue());
x=x.add(_0_1);
}

输出

0.1000000000000000055511151231257827021181583404541015625, asdouble0.10.2000000000000000111022302462515654042363166809082031250, asdouble0.20.3000000000000000166533453693773481063544750213623046875, asdouble0.300000000000000040.4000000000000000222044604925031308084726333618164062500, asdouble0.40.5000000000000000277555756156289135105907917022705078125, asdouble0.50.6000000000000000333066907387546962127089500427246093750, asdouble0.60000000000000010.7000000000000000388578058618804789148271083831787109375, asdouble0.70000000000000010.8000000000000000444089209850062616169452667236328125000, asdouble0.80.9000000000000000499600361081320443190634250640869140625, asdouble0.91.0000000000000000555111512312578270211815834045410156250, asdouble1.0

原因

Most answers here address this question in very dry, technical terms. I'd like to address this in terms that normal human beings can understand.

Imagine that you are trying to slice up pizzas. You have a robotic pizza cutter that can cut pizza slices exactly in half. It can halve a whole pizza, or it can halve an existing slice, but in any case, the halving is always exact.

That pizza cutter has very fine movements, and if you start with a whole pizza, then halve that, and continue halving the smallest slice each time, you can do the halving 53 times before the slice is too small for even its high-precision abilities. At that point, you can no longer halve that very thin slice, but must either include or exclude it as is.

Now, how would you piece all the slices in such a way that would add up to one-tenth (0.1) or one-fifth (0.2) of a pizza? Really think about it, and try working it out. You can even try to use a real pizza, if you have a mythical precision pizza cutter at hand. :-)


Most experienced programmers, of course, know the real answer, which is that there is no way to piece together an exact tenth or fifth of the pizza using those slices, no matter how finely you slice them. You can do a pretty good approximation, and if you add up the approximation of 0.1 with the approximation of 0.2, you get a pretty good approximation of 0.3, but it's still just that, an approximation.

For double-precision numbers (which is the precision that allows you to halve your pizza 53 times), the numbers immediately less and greater than 0.1 are 0.09999999999999999167332731531132594682276248931884765625 and 0.1000000000000000055511151231257827021181583404541015625. The latter is quite a bit closer to 0.1 than the former, so a numeric parser will, given an input of 0.1, favour the latter.

(The difference between those two numbers is the "smallest slice" that we must decide to either include, which introduces an upward bias, or exclude, which introduces a downward bias. The technical term for that smallest slice is an ulp.)

In the case of 0.2, the numbers are all the same, just scaled up by a factor of 2. Again, we favour the value that's slightly higher than 0.2.

Notice that in both cases, the approximations for 0.1 and 0.2 have a slight upward bias. If we add enough of these biases in, they will push the number further and further away from what we want, and in fact, in the case of 0.1 + 0.2, the bias is high enough that the resulting number is no longer the closest number to 0.3.

In particular, 0.1 + 0.2 is really 0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125 = 0.3000000000000000444089209850062616169452667236328125, whereas the number closest to 0.3 is actually 0.299999999999999988897769753748434595763683319091796875.

总结

这也解释通了0.1可以精确输出,0.3也可以精确输出 ,而0.1+0.1+0.1输出 0.30000000000000004;因为0.1 + 0.2实际上是0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125 = 0.3000000000000000444089209850062616169452667236328125,而最接近0.3的数字实际上是0.299999999999999988897769753748434595763683319091796875。

@Testpublicvoidtest() {
doublea=0.1;
doubleb=0.3;
System.out.println("a:"+a);
System.out.println("b:"+b);
System.out.println("a+a+a:"+(a+a+a));
    }
a:0.1b:0.3a+a+a:0.30000000000000004
目录
相关文章
float与double精度丢失问题
float与double精度丢失问题
116 0
|
存储 Python
python float精度处理
python float精度处理
381 0
|
存储 算法 Java
Java float和double精度范围大小(二进制存储角度剖析)
要想理解float和double的取值范围和计算精度,必须先了解小数是如何在计算机中存储的: 下面举例说明:如何将十进制数78.375转换成32位长的IEEE单精度格式。
484 0
Java float和double精度范围大小(二进制存储角度剖析)
|
存储 程序员 Python
【小思考】Python的float转换精度损失所想到的
首先,为啥会要讨论这个问题。 我得为昨天拖了小组后腿深表歉意。其实程序逻辑很快就理通了的,但自己总是会因为各种各样的小问题束缚手脚,看接下来这个图片: 稍微有数据敏感性的同学就能看出,中间这么一大堆又是0000又是999还是这么多位的小数,一看就是异常数据。
5359 0
|
Java API
Java中如何解决double和float精度不准的问题
我们知道浮点数是无法在计算机中准确表示的,例如0.1在计算机中只是表示成了一个近似值,因此,对付点数的运算时结果具有不可预知性。 在进行数字运算时,如果有double或float类型的浮点数参与计算,偶尔会出现计算不准确的情况。
1173 0
Java使用BigDecimal保留double、float运算精度、保留指定位数有效数字、四舍五入
工具类 package ……; import java.math.BigDecimal; /** * Created by kongqw on 2015/12/10.
1040 0
|
存储 C# Java
C#中float的取值范围和精度
原文:C#中float的取值范围和精度 float类型的表现形式: 默认情况下,赋值运算符右侧的实数被视为 double。 因此,应使用后缀 f 或 F 初始化浮点型变量,如以下示例中所示: float x = 3.5F; 如果在以上声明中不使用后缀,则会因为您尝试将一个 double值存储到 float 变量中而发生编译错误。
1917 0
|
存储 Java
Java中float,double为什么会丢失精度。
Effective Java Item 48: Avoid float and double if exact answers are required  对于精确计算不提倡使用float,double,因为会丢失精度,这是为什么呢? 让我细细说来 1. 什么是浮点数? 表示一个数字如100.2,可以是Fixed point也就是100.2,也可以是Floating point(也就
2239 0
|
6月前
|
存储 Java
百度搜索:蓝易云【Java语言之float、double内存存储方式】
由于使用IEEE 754标准进行存储,float和double类型可以表示非常大或非常小的浮点数,并且具有一定的精度。然而,由于浮点数的特性,它们在进行精确计算时可能会存在舍入误差。在编写Java程序时,需要注意使
96 0
|
27天前
|
存储 C语言
使用 sizeof 操作符计算int, float, double 和 char四种变量字节大小
【10月更文挑战第13天】使用 sizeof 操作符计算int, float, double 和 char四种变量字节大小。
72 1