关于BigDecimal精度影响计算结果的问题
2017-01-03 20:55
411 查看
因为double本身有数值范围的限制,在处理金钱等需要高精度的数据时,我们会考虑使用BigDecimal。但是在使用BigDecimal时,有很多需要我们注意的细节。本文主要针对精度问题来进行说明。
我们可能都知道BigDecimal是有精度的,通过以下几个setScale()重载方法,可以对精度进行设置。
通过scale()方法可以获取精度,很奇怪,不是getScale()。
上述的设置和获取不是我要说的重点,我想说的是默认精度是多少,我之前自然而然的以为BigDecimal能够满足金钱的高精度计算,它确实可以,但是默认精度问题可能会让你掉进大坑。
先举例,看看一下BigDecimal的精度各是多少:
下面是打印结果,对照看后面的注释部分。
根据上面的打印结果来进行分析:
1) 对于整型,精度就是0
2) 对于double型
小数点后面是0的话,精度就是0;
小数点后面不是0,则取决于整数位的位数,整数位越多,精度越小;当整数位接近15位时,精度就趋于0,再多1位数据可能开始溢出(具体情况取决于double类型的数值表示)。
3) 对于字符串类型的构造函数,小数点后面有几位,精度就是几位,而且几乎没有位数限制(试了40位都没有问题)
尽量使用字符串来构建BigDecimal对象,这样不会受到到double本身取值范围限制的影响。
或者可以在初始化BigDecimal对象后,显示为设置一次精度。
另外,BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,在运算时(包括setScale)千万要保存操作后的值。往往我们会使用连续调用,最后保存一次值。
BigDecimal API
http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
Java.math.BigDecimal.scale()方法实例
http://www.yiibai.com/java/math/bigdecimal_scale.html
Java BigDecimal详解
http://blog.csdn.net/jackiehff/article/details/8582449
谢谢!
http://www.alanzeng.cn/2017/01/bigdecimal-sacle/
设置和获取Scale精度
我们可能都知道BigDecimal是有精度的,通过以下几个setScale()重载方法,可以对精度进行设置。BigDecimal | setScale(int newScale)Returns a BigDecimal whose scale is the specified value, and whose value is numerically equal to this BigDecimal's. |
BigDecimal | setScale(int newScale, int roundingMode)Returns a BigDecimal whose scale is the specified value, and whose unscaled value is determined by multiplying or dividing this BigDecimal's unscaled value by the appropriate power of ten to maintain its overall value. |
BigDecimal | setScale(int newScale, RoundingMode roundingMode)Returns a BigDecimal whose scale is the specified value, and whose unscaled value is determined by multiplying or dividing this BigDecimal's unscaled value by the appropriate power of ten to maintain its overall value. |
通过scale()方法可以获取精度,很奇怪,不是getScale()。
int | scale()Returns the scale of this BigDecimal. |
默认精度是多少
上述的设置和获取不是我要说的重点,我想说的是默认精度是多少,我之前自然而然的以为BigDecimal能够满足金钱的高精度计算,它确实可以,但是默认精度问题可能会让你掉进大坑。先举例,看看一下BigDecimal的精度各是多少:
System.out.println(new BigDecimal(1).scale()); System.out.println(new BigDecimal(1.0).scale()); System.out.println(new BigDecimal(1.00).scale()); System.out.println(new BigDecimal(1.1).scale()); System.out.println(new BigDecimal(1.11).scale()); System.out.println(new BigDecimal(1.1111).scale()); System.out.println(new BigDecimal(11.1).scale()); System.out.println(new BigDecimal(111.1).scale()); System.out.println(new BigDecimal(1111.1).scale()); System.out.println(new BigDecimal(11111.1).scale()); System.out.println(new BigDecimal("1").scale()); System.out.println(new BigDecimal("1.0").scale()); System.out.println(new BigDecimal("1.00").scale()); System.out.println(new BigDecimal("1.1").scale()); System.out.println(new BigDecimal("1.11").scale()); System.out.println(new BigDecimal(999999999999999.1).scale()); System.out.println(new BigDecimal(999999999999999.1)); System.out.println(new BigDecimal("9999999999999999999999999999999999999999.000000").scale()); System.out.println(new BigDecimal("9999999999999999999999999999999999999999.000000")); System.out.println(new BigDecimal("9999999999999999999999999999999999999999.000000").divide(new BigDecimal("9"),RoundingMode.HALF_DOWN)));
下面是打印结果,对照看后面的注释部分。
System.out.println(new BigDecimal(1).scale()); // 0 System.out.println(new BigDecimal(1.0).scale()); // 0 System.out.println(new BigDecimal(1.00).scale()); // 0 System.out.println(new BigDecimal(1.1).scale()); // 51 System.out.println(new BigDecimal(1.11).scale()); // 52 System.out.println(new BigDecimal(1.1111).scale()); // 51 System.out.println(new BigDecimal(11.1).scale()); // 49 System.out.println(new BigDecimal(111.1).scale()); // 45 System.out.println(new BigDecimal(1111.1).scale()); // 41 System.out.println(new BigDecimal(11111.1).scale()); // 39 System.out.println(new BigDecimal("1").scale()); // 0 System.out.println(new BigDecimal("1.0").scale()); // 1 System.out.println(new BigDecimal("1.00").scale()); // 2 System.out.println(new BigDecimal("1.1").scale()); // 1 System.out.println(new BigDecimal("1.11").scale()); // 2 System.out.println(new BigDecimal(999999999999999.1).scale()); // 3 System.out.println(new BigDecimal(999999999999999.1)); // 999999999999999.125 System.out.println(new BigDecimal("9999999999999999999999999999999999999999.000000").scale()); // 6 System.out.println(new BigDecimal("9999999999999999999999999999999999999999.000000")); // 9999999999999999999999999999999999999999.000000 System.out.println(new BigDecimal("9999999999999999999999999999999999999999.000000").divide(new BigDecimal("9"),RoundingMode.HALF_DOWN))); // 1111111111111111111111111111111111111111.000000
根据上面的打印结果来进行分析:
1) 对于整型,精度就是0
2) 对于double型
小数点后面是0的话,精度就是0;
小数点后面不是0,则取决于整数位的位数,整数位越多,精度越小;当整数位接近15位时,精度就趋于0,再多1位数据可能开始溢出(具体情况取决于double类型的数值表示)。
3) 对于字符串类型的构造函数,小数点后面有几位,精度就是几位,而且几乎没有位数限制(试了40位都没有问题)
总结
尽量使用字符串来构建BigDecimal对象,这样不会受到到double本身取值范围限制的影响。System.out.println(new BigDecimal("1.000000").scale());
或者可以在初始化BigDecimal对象后,显示为设置一次精度。
BigDecimal orderAmount = new BigDecimal(0); orderAmount = orderAmount.setScale(6, RoundingMode.HALF_EVEN);
另外,BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,在运算时(包括setScale)千万要保存操作后的值。往往我们会使用连续调用,最后保存一次值。
BigDecimal orderMonthAmount; // 省略orderMonthAmount的初始化 BigDecimal orderValue = orderMonthAmount.divide(new BigDecimal(30), RoundingMode.HALF_EVEN) .multiply(new BigDecimal(interval)) .setScale(2, BigDecimal.ROUND_HALF_EVEN);
参考
BigDecimal APIhttp://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
Java.math.BigDecimal.scale()方法实例
http://www.yiibai.com/java/math/bigdecimal_scale.html
Java BigDecimal详解
http://blog.csdn.net/jackiehff/article/details/8582449
谢谢!
http://www.alanzeng.cn/2017/01/bigdecimal-sacle/
相关文章推荐
- 关于JavaScript中计算精度丢失的问题
- 关于浮点数计算时的精度问题
- 关于JavaScript中计算精度丢失的问题(一)
- 关于精度问题(实数计算)
- 关于json 转换BigDecimal精度丢失问题
- 关于JavaScript中计算精度丢失的问题
- 关于JavaScript中计算精度丢失的问题
- 关于float计算结果不精确问题
- Java浮点数float,bigdecimal和double精确计算的精度误差问题总结
- 数值计算精度问题(double,float,Bigdecimal)
- 关于js中计算精度的问题解决办法
- 经得起雷劈:关于double和int/long相互转换失去精度计算错误的问题
- 关于mybatis 使用case when 计算BigDecimal 数据返回对象的问题
- Java浮点数float,bigdecimal和double精确计算的精度误差问题总结
- 货币计算中的精度问题--java.math.BigDecimal
- 关于加权平均、队列、算术平均对计算对结果的影响
- 关于BigDecimal 和 double 类型保存金钱,以及精度问题,银行家舍入法
- Java浮点数float,bigdecimal和double精确计算的精度误差问题总结
- 关于浮点数计算时的精度问题
- 金融项目java开发_BigDecimal(解决计算精度问题)