如果要求精确的答案,请避免使用float和double
2013-11-19 19:29
375 查看
float和double类型的主要设计目的是为了科学计算和工程计算。它们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。因为要让一个float或者double精确地表示0.1(或者10的任何负数次方值)是不可能的,float和double类型对于货币计算尤为不合适,因为要让一个float或double精确地表示0.1或10的任何其他负数次方值是不可能的。比如System.out.println(2.0-1.1)将会打印0.899999999999999,而不是你所希望的0.9,这种舍入错误产生的原因是浮点数实际上是用二进制系统实现的,而分数1/10在二进制系统中没有精确的表示,其道理就如同在十进制系统中无法精确表示1/3一样;再比如0.5在二进制系统中有精确表示,而0.55在二进制系统中没有精确表示。
输出结果为:
0.6100000000000001
0.09999999999999998
你可能会认为,只要在打印之前将结果做一下舍入就可以解决这个问题,但遗憾的是,这种做法并不总是可行。
例如:假设你口袋里有1美元,你看到货架上有一排糖果,标价分别是10美分、20美分、30美分等等,一直到1美元。你打算从标价为10美分的开始买,每种买一颗,直到不能支付货架上的任何一种价格为止,那么你可以买多少颗糖果?还会找回多少零头?下面是一个简单的程序,用来解决这个问题:
如果运行这个程序你会发现你可以支付3颗糖果,并且还剩0.3999999999999999美元。显然这个答案是不正确的。解决这个问题的正确办法是使用BigDecimal、int或long进行货币计算。
下面看看使用BigDecimal类型代替double的程序:
输出结果0.00和4 这样就正确了
关于BigDecimal的方法我们下去再仔细看看;
这里要说的是BigDecimal是引用数据类型
总而言之: 对于任何要精确答案的计算任务,请不要用double和float。如果你想 计算十进制小数点,并且不介意非基本类型带来的不便,那就用BigDecimal;使用 BigDecimal还有个额外的好处就是他允许你完全控制舍入,每当一个操作涉及舍入的时候 它允许你从8种舍入模式中选择一种。如果你正确通过法定要求的舍入行为进行业务计算使用BigDecimal时非常方便的;如果性能十分关键,并且你又不介意自己记录十进制的 小数点,而且涉及数值不大,就可以使用int或者long; 如果数值范围没有超过9位的十进制数字,可以用int;如果数值范围没有超过18位的十进制数字,用long 如果范围超过了18位数,那我们必须使用BigDecimal。
System.out.println(1.03 – .42); System.out.println(1.00 – 9 * .10);
输出结果为:
0.6100000000000001
0.09999999999999998
你可能会认为,只要在打印之前将结果做一下舍入就可以解决这个问题,但遗憾的是,这种做法并不总是可行。
例如:假设你口袋里有1美元,你看到货架上有一排糖果,标价分别是10美分、20美分、30美分等等,一直到1美元。你打算从标价为10美分的开始买,每种买一颗,直到不能支付货架上的任何一种价格为止,那么你可以买多少颗糖果?还会找回多少零头?下面是一个简单的程序,用来解决这个问题:
double funds = 1.00; int itemsBought = 0; for (double price = .10; funds >= price; price += .10) { funds -= price; itemsBought++; } System.out.println(itemsBought + " items bought."); System.out.println("Change: $" + funds);
如果运行这个程序你会发现你可以支付3颗糖果,并且还剩0.3999999999999999美元。显然这个答案是不正确的。解决这个问题的正确办法是使用BigDecimal、int或long进行货币计算。
下面看看使用BigDecimal类型代替double的程序:
final BigDecimal TEN_CENTS = new BigDecimal(".10"); int itemsBought = 0; BigDecimal funds = new BigDecimal("1.00"); for (BigDecimal price = TEN_CENTS; funds.compareTo(price) >= 0; price = price .add(TEN_CENTS)) { itemsBought++; funds = funds.subtract(price); } System.out.println(itemsBought + " items bought."); System.out.println("Money left over: $" + funds);
输出结果0.00和4 这样就正确了
关于BigDecimal的方法我们下去再仔细看看;
这里要说的是BigDecimal是引用数据类型
总而言之: 对于任何要精确答案的计算任务,请不要用double和float。如果你想 计算十进制小数点,并且不介意非基本类型带来的不便,那就用BigDecimal;使用 BigDecimal还有个额外的好处就是他允许你完全控制舍入,每当一个操作涉及舍入的时候 它允许你从8种舍入模式中选择一种。如果你正确通过法定要求的舍入行为进行业务计算使用BigDecimal时非常方便的;如果性能十分关键,并且你又不介意自己记录十进制的 小数点,而且涉及数值不大,就可以使用int或者long; 如果数值范围没有超过9位的十进制数字,可以用int;如果数值范围没有超过18位的十进制数字,用long 如果范围超过了18位数,那我们必须使用BigDecimal。
相关文章推荐
- C++中获取UTC时间精确到微秒的实现代码
- 斐波那契数列时间复杂性的近似证明和精确证明
- 框计算精确搜索之架构篇
- 桥牌知识--我的精确叫牌精萃和打牌基本方法
- Math.round()亏了一方
- find命令应用详解
- js加减乘除丢失精度问题
- Kafka 0.11.0.0 是如何实现 Exactly-once 语义的
- Android开发_精准排布控件位置
- 使用BigDecimal进行精确运算
- CADisplayLink的调用足够精确吗?
- python中实现精确的浮点数运算详解
- 浅谈iOS 关于小数精确计算(NSDecimalNumber)
- js精确的加减乘除实例
- 获取当前系统本地时间,精确到毫秒的实例
- JS浮点数运算结果不精确的Bug解决
- 第13周作业 她胖吗
- 整数排序【编程】
- mysql 游标取值为空的问题
- 使用vector 和map构造二维矩阵和二维表格