Effective Java(2nd Edition) Item 48 如果需要精确结果,请避免使用float与double(译文)
来源:互联网 发布:最好的汽车报价软件 编辑:程序博客网 时间:2024/04/27 17:14
设计float与double类型主要用于科学与工程计算。它们用于二进制浮点运算,二进制浮点运算被仔细设计,可在一个很宽的数量级范围内提供足够精确的近似计算。然而它们不能提供精确的结果,当需要精确的结果时就不应使用它们。Float与double类型特别不适合于货币计算,因为不可能用float或double精确的表示0.1(及任何10的负幂次方的数)。
例如,假设你手头有$1.03,你花了42¢,你还剩多少钱呢?下面是解答这个问题的最自然的代码片断:
System.out.println(1.03 - .42);
不幸的是,它的输出是0.6100000000000001。这并非一个孤立现象。假设你手头有一美元,你买了9只垫圈,每只10美分,还剩多少钱呢?
System.out.println(1.00 - 9 * .10);
如果按这段代码,你得$0.09999999999999998.
你可能会认为只要在打印前先四舍五入就可以解决这个问题,不幸的是,这并非总是可行的。例如,假设你手头有1美元,贷架上放着一排精美的糖果,标价为10美分、20美分、30美分,如些值到1美元。你想买每颗这样的糖果,从10美分开始,值到余下的钱不够买下一颗为止。你能买几颗糖呢?还留下多少钱呢?下面是一个解决这个问题的自然代码段。
// Broken - uses floating point for monetary calculation!
public static void main(String[] args) {
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);
}
如果你运行这段代码,你可以发现你能买到三颗糖,剩下$0.3999999999999999。这是一个错误的答案。解决这个问题的正确做法是在货币计算中使用BigDecimal、int或long。
下面的程序段在前面的程序中用BigDecimal直接替换了double。
public static void main(String[] args) {
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。这是正确的答案。
然而使用BigDecimal也有两点劣势,它没有基本算术类型方便,而且比较慢。如果你解决的是单个小问题,比较慢就不成问题。但前面这个劣势可能会让你不舒服。
可依据所处理的数量大小,使用int或long来代替BigDecimal,并由自已跟踪处理小数点位。在上面的例子中,一个显然的方法是使用美分而不是美元来进行所有的运算。下面的程序展示了这个方法。
public static void main(String[] args) {
int itemsBought = 0;
int funds = 100;
for (int price = 10; funds >= price; price += 10) {
itemsBought++;
funds -= price;
}
System.out.println(itemsBought + " items bought.");
System.out.println("Money left over: "+ funds + " cents");
}
总之,不要将float或double用于需要精确结果的计算。如果你希望系统跟踪处理小数点,并且不介意不使用基本类型的不便与花销,就使用BigDecimal。使用BigDecimal还有一个额外的好处是你可以完全控制四舍五入,允许你只要有小数尾数,就可以选择八种四舍五入模式之一进行操作。如果你所运行的业务运算要求有特别地四舍五入行为,这会带来很大便利。如果性能是关键的,而且你也不介意自已跟踪处理小数点位,数值也不特别大,就使用int或long。如果数值不超过十进制9位数,你可以使用int,如果数值不超过18位数,你可以使用long。如果数值可能超过18位,你就得使用BigDecimal。
- Effective Java(2nd Edition) Item 48 如果需要精确结果,请避免使用float与double(译文)
- Java:Effective Java 学习笔记(第48条:如果需要精确的答案,请避免使用float和double)
- Effective Java(2nd Edition) Item 59 避免使用不必要的受检查异常(译文)
- Effective Java(2nd Edition) Item 47 学习与使用类库(译文)
- 第48条:如果需要精确的答案,请避免使用float和double
- Effective Java(2nd Edition) Item 57 仅为例外条件使用异常(译文)
- Effective Java(2nd Edition) Item 60 优先使用标准异常(译文)
- Effective Java(2nd Edition) Item 63 译文
- 第48条:如果需要精确的答案,请避免适用float和double
- Effective Java读书笔记--如果想要知道精确的答案,就要避免使用double和float
- Effective Java(2nd Edition) Item 62 归档方法所抛出的异常(译文)
- Effective Java(2nd Edition) Item 61 适当抽象抛出的异常(译文)
- Effective Java(2nd Edition) Item 45 最小化局部变量的作用域(译文)
- 48条:如果需要精确的答案,避免使用float和double
- 如果要求精确的答案,请避免使用float和double
- 31-如果要求精确的答案,请避免使用float和double
- Effective Java(2nd Edition) Item 46 for-each循环优于传统的for循环(译文)
- Effective Java(2 Edition) Item 64译文
- struct的data对齐
- 设置iphone屏幕方向
- 扩展字符串左右对齐方法
- 让office2007右键新建97-03版本的doc,xls.ppt文件
- UILabel使用说明
- Effective Java(2nd Edition) Item 48 如果需要精确结果,请避免使用float与double(译文)
- 通过内核对象在服务程序和桌面程序之间通信的小问题
- P2P之UDP穿透NAT的原理与C#实现
- 第一次春节过年回家买票记
- 几种通讯协议的比较
- Uploading image to Flickr via AppleScript
- 好用的 MS SQL 2005 字串加密應用 ( MD5 & SHA1 )
- 驿站
- JDK 6.0 API之 类 Matcher