java和js等数据精度丢失问题

大概所有学过计算机的同学都应该具备这样的基本常识:

1、0.1+0.2 不一定等于0.3(1-0.99同理不一定等于0.01)

2、1/2不一定等于0.5

3、1/3 *3不一定等于1

4、log2+log5也不一定等于1

可是,我其实也经常忘记掉。。大概教java的刘骥老师看到我这个问题,也被气死了吧。

这是java计算的结果:

java和js等数据精度丢失问题_第1张图片

这是python计算的结果:

java和js等数据精度丢失问题_第2张图片

这是JS计算结果:

java和js等数据精度丢失问题_第3张图片

那原因到底是什么呢?问题又该如何解决?

首先应该明确的是,只要两个数字的加减乘除,只要不是int类型,那么都有可能存在精度丢失的问题(这里暂且不说当两个不同类型的数进行基本运算符操作时,精度小的数值类型首先会向精度大的数值类型进行转换,最后进行计算的问题。)

原因简化如下:因为不管是float还是double类型,他们的精度都是有限的,假如超过了他们所能表示的范围,那么就会产生误差,其结果只能是接近而不是等于我们想要的结果。(因为计算机最后都是二进制表示的,(好的,这是一句废话。)

下面举个例子:上述的0.3为什么不能正确显示出来。

比如整数11,二进制是这样表示的:

11/2=5+1  -->1

5/2=2+1   -->1

2/2=1+0   -->0

1/2=0+1   -->1

所以11的二进制表示为:1011.

然后我们来看下0.3的二进制:

0.3*2=0.6    -->0

0.6*2=1+0.2  -->1

0.2*2=0.4    -->0

0.4*2=0.8    -->0

0.8*2=1+0.6  -->1

你会发现这样会不断循环下去。。。。所以这时候就不能很精确的表示了,也就出现的精度丢失的问题。就如同十进制系统中能不能准确表示出1/3一样,大概就是这样。

所以一般大家都建议使用java.math.BigDecimal。能够完全自己控制精度,结果也准确。但是需要注意的是,“直接使用字符串来构造BigDecimal是绝对没有精度损失的,如果用double或者把double转化成string来构造BigDecimal依然会有精度损失,所以我觉得这种解决方法就是在数据库中就把浮点数用string来表示存放,涉及到运算直接用string构造double,否则肯定会有精度损失。” 不过BigDecimal也有缺点,就是效率不如double。

如下,就是我们想要的结果:

java和js等数据精度丢失问题_第4张图片

后端处理好了之后,我们会发现前端也会有这样的问题。

就比如我们碰到的这个问题。我们所见的不一定就是所得。所以前后端对于这个数据都需要做一定的处理,不然你会发现。明明输入的数据很正常,但是所得到的结果却往往不如意。

java和js等数据精度丢失问题_第5张图片

后来大概是先前端使用tofixed()函数四舍五入保留了4位小数,然后给后端,后端再处理。

但是,总感觉使用这个tofix哪里肯定还是会出问题的。。。没在深究了。。。

你可能感兴趣的:(java和js等数据精度丢失问题)