java double 运算精度_Java中的float、double计算精度问题

java中的float、double计算存在精度问题,这不仅仅在java会出现,在其他语言中也会存在,其原因是出在IEEE 754标准上。

而java对此提供了一个用于浮点型计算的类——BigDecimal(java.math.BigDecimal),通过将double替换成BigDecimal进行计算可以获得较为精确的计算结果。

BigDecimal的构造方法有许多,在此推荐使用BigDecimal(String val)的构造方法,通过String字符串进行构造。可能会有人直接使用BigDecimal(double val)去构造,但为什么推荐要使用String而不用double直接构造?原因如BigDecimal(double val)前的注释所说:

Translates a {@code double} into a {@code BigDecimal} which is the exact decimal representation of the {@code double}'s binary floating-point value. The scale of the returned {@code BigDecimal} is the smallest value such that (10 scale val) is an integer.

Notes: The results of this constructor can be somewhat unpredictable. One might assume that writing {@code new BigDecimal(0.1)} in Java creates a {@code BigDecimal} which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625.This is because 0.1 cannot be represented exactly as a {@code double} (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

The {@code String} constructor, on the other hand, is perfectly predictable: writing {@code new BigDecimal("0.1")} creates a {@code BigDecimal} which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the {@linkplain #BigDecimal(String) String constructor} be used in preference to this one.

When a {@code double} must be used as a source for a {@code BigDecimal}, note that this constructor provides an exact conversion; it does not give the same result as converting the {@code double} to a {@code String} using the {@link Double#toString(double)} method and then using the {@link #BigDecimal(String)} constructor. To get that result, use the {@code static} {@link #valueOf(double)} method.

balabala的一大段?挑出重点看,Notes(说明):The results of this constructor can be somewhat unpredictable(这个结果可能是不可预测的)。原因在后面一句话也说了,若用 0.1 new一个BigDecimal,则它实际上是等于0.1000000000000000055511151231257827021181583404541015625,原因无需细看,跳过。

The {@code String} constructor, on the other hand, is perfectly predictable(通过字符串构造,是可以完全预测的)。到此注释说的差不多了。

而BigDecimal中一系列的add、subtract等方法对应着加减乘除就不必多说。

到这里就结束了吗?不,如果单纯的将double替换成BigDecimal,就会大幅降低程序的运行速度,因此需要进行一定的优化:非替换,而是改进。

依旧用double定义、储存数据,但计算时,使用BigDecimal进行计算(若需要精确的计算),最后只需.doubleValue()即可得到较为精确的double类型的计算结果了。

由此可以编写一个用于浮点型计算的工具类,专职浮点型计算工作。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

1 importjava.math.BigDecimal;2

3 /**

4 * 浮点型较为精确计算工具类5 */

6 public classCalculateUtil {7 /**

8 * 私有构造9 */

10 privateCalculateUtil(){}11 /**

12 * 加法运算13 *@paramnum1 被加数14 *@paramnum2 加数15 *@return两数之和16 */

17 public static double add(double num1, doublenum2){18 BigDecimal b1 = newBigDecimal(Double.toString(num1));19 BigDecimal b2 = newBigDecimal(Double.toString(num2));20 returnb1.add(b2).doubleValue();21 }22 /**

23 * 减法运算24 *@paramnum1 被减数25 *@paramnum2 减数26 *@return两数之差27 */

28 public static double sub(double num1, doublenum2){29 BigDecimal b1 = newBigDecimal(Double.toString(num1));30 BigDecimal b2 = newBigDecimal(Double.toString(num2));31 returnb1.subtract(b2).doubleValue();32 }33 /**

34 * 乘法运算35 *@paramnum1 被乘数36 *@paramnum2 乘数37 *@return两数之积38 */

39 public static double mul(double num1, doublenum2){40 BigDecimal b1 = newBigDecimal(Double.toString(num1));41 BigDecimal b2 = newBigDecimal(Double.toString(num2));42 returnb1.multiply(b2).doubleValue();43 }44 /**

45 * 除法运算(小数点后10位)46 *@paramnum1 被除数47 *@paramnum2 除数48 *@return两数之商49 */

50 public static double div(double num1, doublenum2){51 return div(num1, num2, 10);52 }53

54 /**

55 * 除法运算56 *@paramnum1 被除数57 *@paramnum2 除数58 *@paramscale 小数点后精度位数59 *@return两数之商60 */

61 public static double div(double num1, double num2, intscale){62 if(scale<0)63 throw new IllegalArgumentException("The scale must be a positive integer or zero");64 BigDecimal b1 = newBigDecimal(Double.toString(num1));65 BigDecimal b2 = newBigDecimal(Double.toString(num2));66 returnb1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();67 }68 /**

69 * 四舍五入70 *@paramnum 需要四舍五入的数71 *@paramscale 小数点后精度位数72 *@return四舍五入值73 */

74 public static double round(double num, intscale){75 if(scale<0)76 throw new IllegalArgumentException("The scale must be a positive integer or zero");77 BigDecimal b1 = newBigDecimal(Double.toString(num));78 return b1.divide(new BigDecimal("1"), scale, BigDecimal.ROUND_HALF_UP).doubleValue();79 }80

81 }

View Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值