天天记录 - Java 精确计算避免使用float和double
2013-01-07 22:15
309 查看
一 问题描述
float和double类型不能用于精确计算,其主要目的是为了科学计算和工程计算,它们执行二进制浮点原酸,目的是为了广泛的数值范围上提供较为精确的快速近似计算而精心设计的。但是如果设计钱币之类的计算需要很精确,所以这种情况不能使用float和double,因为要让其精确表示0.1 或者 10的任何负数次方值是不可能的。
二 眼见为实,举例证明:
三 举一个现实中会遇到的情况:
一个实际的例子,口袋里面有10元钱,买0.9元的商品十个 , 收银员需要找零1元。计算如下:
结果竟然输出的是1.0000002而非1,可能很多人会认为这也无所谓啊,毕竟仅偏差了0.0000002,但问题是如果前提是进行了1亿笔交易呢?难道你愿意仅仅因为使用了计算机计算这些数据,而损失一部分钱吗?
四 解决办法
1. 使用int 和 long类型,如果小数点以后的值可以忽略不计可以只用这两种类型
2. 对计算结果进行四舍五入
3. 使用BigDecimal类型进行浮点运算
先来看一段代码
原本按我个人的理解 10 + 0.99999 = 10.99999 然后转为int类型会进行四舍五入 值为11,而实际结果为10
更深入的分析可以查看
如何解决float和double误差问题呢?可以使用Java中提供的java.math.BigDecimal,不过此类型是不可变的,每次计算都必须新创建一个对象,不适合大量计算
再来看一个舍入误差会出现的问题
解决办法,使用BigDecimal
参考资料:
1. Java 理论与实践: 您的小数点到哪里去了?
2. 《Effective Java》 第2版 第48条 如果需要精确的答案,请避免使用float和double
float和double类型不能用于精确计算,其主要目的是为了科学计算和工程计算,它们执行二进制浮点原酸,目的是为了广泛的数值范围上提供较为精确的快速近似计算而精心设计的。但是如果设计钱币之类的计算需要很精确,所以这种情况不能使用float和double,因为要让其精确表示0.1 或者 10的任何负数次方值是不可能的。
二 眼见为实,举例证明:
// float与double 无法精确表示0.1 或者 10的负次方 System.out.println( 0.15 - 0.05 ); // 0.09999999999999999 System.out.println( 2.08f - 3.7f );// -1.6200001
三 举一个现实中会遇到的情况:
一个实际的例子,口袋里面有10元钱,买0.9元的商品十个 , 收银员需要找零1元。计算如下:
10 - 0.9 * 10 = 1代码实现:
float myMoney = 10.00f; float price = 0.9f; for (int i = 0; i < 10; i++) { myMoney -= price; } System.out.println( myMoney ); // 1.0000002
结果竟然输出的是1.0000002而非1,可能很多人会认为这也无所谓啊,毕竟仅偏差了0.0000002,但问题是如果前提是进行了1亿笔交易呢?难道你愿意仅仅因为使用了计算机计算这些数据,而损失一部分钱吗?
四 解决办法
1. 使用int 和 long类型,如果小数点以后的值可以忽略不计可以只用这两种类型
2. 对计算结果进行四舍五入
3. 使用BigDecimal类型进行浮点运算
先来看一段代码
int intValue = 10; float floatValue = 0.99999f; int count1 = (int) (intValue + floatValue); System.out.println("10 + 0.99999 = " + count1); // output 10 int count2 = (int) (intValue - floatValue); System.out.println("10 - 0.99999 = " + count2); // output 9
原本按我个人的理解 10 + 0.99999 = 10.99999 然后转为int类型会进行四舍五入 值为11,而实际结果为10
更深入的分析可以查看
如何解决float和double误差问题呢?可以使用Java中提供的java.math.BigDecimal,不过此类型是不可变的,每次计算都必须新创建一个对象,不适合大量计算
再来看一个舍入误差会出现的问题
// 10.1 + 0.99*10 = 20 float f1 = 10.1f; float f2 = 0.99f; for (int i = 0; i < 10; i++) { f1 += f2; } System.out.println(f1); // 19.999998
解决办法,使用BigDecimal
BigDecimal count = new BigDecimal("10.1"); for (int i = 0; i < 10; i++) { count = count.add(new BigDecimal("1")); } System.out.println(count.intValue()); // 20
参考资料:
1. Java 理论与实践: 您的小数点到哪里去了?
2. 《Effective Java》 第2版 第48条 如果需要精确的答案,请避免使用float和double
相关文章推荐
- Java:Effective Java 学习笔记(第48条:如果需要精确的答案,请避免使用float和double)
- Java浮点数float,bigdecimal和double精确计算的精度误差问题总结
- 不要在精确计算中使用float和double类型
- Java浮点数float和double精确计算的精度误差问题总结
- Java 精确计算-double-float-String
- Java精确计算,用BigDecimal来处理int、double、float等之间的计算
- 在对于精确计算的要求下请不要使用float和double
- Java中用浮点型数据Float和Double进行精确计算时的精度问题
- java中不能使用float和double来表示货币等精确的值,而是用
- Java中用浮点型数据Float和Double进行精确计算时的精度问题
- Java浮点数float,bigdecimal和double精确计算的精度误差问题总结
- 如果需要精确答案,请避免使用float和double
- 精确运算避免使用float和double
- 精确运算避免使用float和double
- 如果要求精确的答案,请避免使用float和double
- Java中浮点型数据Float和Double进行精确计算的问题
- 如果要求精确的答案,请避免使用float和double
- 如果要求精确的答案,请避免使用float和double
- 14、Java中用浮点型数据Float和Double进行精确计算时的精度问题