当前位置:   article > 正文

Java double和float精度损失问题_java中 double转float精度缺失多少

java中 double转float精度缺失多少

问题

一般,我们会用float和double来存储有小数的数据,可能还会用两个浮点型数据进行计算,在某些情况下,float和double会出现精度损失,导致存储的数据或者计算结果出现误差。

举个例子

public class Test {

	public static void main(String[] args) {
		double a = 0.11;
		double b = 2.32;
		System.out.println(a + b);
		System.out.println(0.11 + 2.32);
		
		float c = 0.11f;
		float d = 2.32f;
		System.out.println(c + d);
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

执行结果如下:

2.4299999999999997
2.4299999999999997
2.4299998
  • 1
  • 2
  • 3

这个结果并不是我们预期的2.43。很明显,精度损失了,虽然仅比原来小了0.00000000000003,但是如果是我们银行卡里的金额,那可就出大问题了。
经过测试,还发现以下两种情况:

  1. 如果把上面的2.32换成2.02,double类型计算得到正确结果,而float类型依然计算错误:
2.13
2.13
2.1299999
  • 1
  • 2
  • 3
  1. 如果把2.32换成1.02,居然反过来了,float类型计算正确,double类型计算错误:
1.1300000000000001
1.1300000000000001
1.13
  • 1
  • 2
  • 3

气人啊!

原因

计算机用0和1来表示数据,并没有小数,浮点型数据采用IEEE754标准,浮点型数据如何存储可以参考这篇文章
《Effective Java》中写道:

float 和 double 类型主要用于科学计算和工程计算。它们执行二进制浮点运算,该算法经过精心设
计,能够在很大范围内快速提供精确的近似值。但是,它们不能提供准确的结果,也不应该在需要精确
结果的地方使用。float 和 double 类型特别不适合进行货币计算,因为不可能将 0.1(或 10 的任意负次
幂)精确地表示为 float 或 double。

所有的编程语言中应该都有这个问题,而不仅仅是Java。

解决方法

那么,如何解决这个问题呢?
用java.math.BigDecimal,并且根据《阿里Java开发规范》,应该使用BigDecimal(“0.01”)这种方式创建对象,而不能用BigDecimal(0.01)这种方式。

12.【强制】禁止使用构造方法 BigDecimal(double)的方式把 double 值转化为 BigDecimal 对象。
说明:BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
如:BigDecimal g = new BigDecimal(0.1F); 实际的存储值为:0.10000000149
正例:优先推荐入参为 String 的构造方法,或使用 BigDecimal 的 valueOf 方法,此方法内部其实执行了
Double 的 toString,而 Double 的 toString 按 double 的实际能表达的精度对尾数进行了截断。
BigDecimal recommend1 = new BigDecimal(“0.1”);
BigDecimal recommend2 = BigDecimal.valueOf(0.1)

另外,在数据库中,也应该使用decimal,而不是float和double。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/209434
推荐阅读
相关标签
  

闽ICP备14008679号