Tom在一家汽车配件商店购买了一个价值$1.10的火花塞,但是他钱包中都是两美元一张的钞票。如果他用一张两美元的钞票支付这个火花塞,那么应该找给他多少零钱呢?
下面是一个试图解决上述问题的程序,它会打印出什么呢?
publicclassChange{
publicstaticvoidmain(Stringargs[]){
System.out.println(2.00-1.10);
}
}
你可能会很天真地期望该程序能够打印出0.90,但是它如何才能知道你想要打印小数点后两位小数呢?
如果你对在Double.toString文档中所设定的将double类型的值转换为字符串的规则有所了解,你就会知道该程序打印出来的小数,是足以将double类型的值与最靠近它的临近值区分出来的最短的小数,它在小数点之前和之后都至少有一位。因此,看起来,该程序应该打印0.9是合理的。
这么分析可能显得很合理,但是并不正确。如果你运行该程序,你就会发现它打印的是0.8999999999999999。
问题在于1.1这个数字不能被精确表示成为一个double,因此它被表示成为最接近它的double值。该程序从2中减去的就是这个值。遗憾的是,这个计算的结果并不是最接近0.9的double值。表示结果的double值的最短表示就是你所看到的打印出来的那个可恶的数字。
更一般地说,问题在于并不是所有的小数都可以用二进制浮点数来精确表示的。
如果你正在用的是JDK5.0或更新的版本,那么你可能会受其诱惑,通过使用printf工具来设置输出精度的方订正该程序:
//拙劣的解决方案——仍旧是使用二进制浮点数
System.out.printf("%.2f%n",2.00-1.10);
这条语句打印的是正确的结果,但是这并不表示它就是对底层问题的通用解决方案:它使用的仍旧是二进制浮点数的double运算。浮点运算在一个范围很广的值域上提供了很好的近似,但是它通常不能产生精确的结果。二进制浮点对于货币计算是非常不适合的,因为它不可能将0.1——或者10的其它任何次负幂——精确表示为一个长度有限的二进制小数
解决该问题的一种方式是使用某种整数类型,例如int或long,并且以分为单位来执行计算。如果你采纳了此路线,请确保该整数类型大到足够表示在程序中你将要用到的所有值。对这里举例的谜题来说,int就足够了。下面是我们用int类型来以分为单位表示货币值后重写的println语句。这个版本将打印出正确答案90分:
System.out.println((200-110)+"cents");
解决该问题的另一种方式是使用执行精确小数运算的BigDecimal。它还可以通过JDBC与SQLDECIMAL类型进行互操作。这里要告诫你一点:一定要用BigDecimal(String)构造器,而千万不要用BigDecimal(double)。后一个构造器将用它的参数的“精确”值来创建一个实例:newBigDecimal(.1)将返回一个表示0.100000000000000055511151231257827021181583404541015625的BigDecimal。通过正确使用BigDecimal,程序就可以打印出我们所期望的结果0.90:
importjava.math.BigDecimal;
publicclassChange1{
publicstaticvoidmain(Stringargs[]){
System.out.println(newBigDecimal("2.00").
subtract(newBigDecimal("1.10")));
}
}
这个版本并不是十分地完美,因为Java并没有为BigDecimal提供任何语言上的支持。使用BigDecimal的计算很有可能比那些使用原始类型的计算要慢一些,对某些大量使用小数计算的程序来说,这可能会成为问题,而对大多数程序来说,这显得一点也不重要。
总之,在需要精确答案的地方,要避免使用float和double;对于货币计算,要使用int、long或BigDecimal。对于语言设计者来说,应该考虑对小数运算提供语言支持。一种方式是提供对操作符重载的有限支持,以使得运算符可以被塑造为能够对数值引用类型起作用,例如BigDecimal。另一种方式是提供原始的小数类型,就像COBOL与PL/I所作的一样。
分享到:
相关推荐
### float与double精度详解 #### 一、浮点数的基础概念 在计算机科学中,`float` 和 `double` 是两种常用的浮点数类型,它们主要用于处理实数运算。这两种类型的区别主要体现在精度和范围上。 #### 二、浮点数的...
float与double的范围和精度 float和double是两种常用的浮点数类型,它们的范围和精度是由其内部存储格式决定的。了解float和double的范围和精度对于编程和数据处理非常重要。 1. 范围 float和double的范围是由...
iOS 之关于 double/float 数据计算精度问题详解 iOS 开发中,double 和 float 数据类型的计算精度问题是一个常见的问题。本篇文章将详细介绍 iOS 中 double/float 数据计算精度问题的根源、解决方案和高精度计算...
总结来说,float和double是编程中处理浮点数的关键数据类型,理解它们的表示方法、精度、误差和运算规则是编写高效、准确的科学计算程序的基础。在实际开发中,开发者需要根据需求来平衡精度、性能和内存消耗,合理...
float和double浮点数类型的精度和范围解析 浮点数类型float和double是编程语言中最常用的数值类型,但是它们...因此,在商业计算中,我们应该使用java.math.BigDecimal来避免精度问题,而不是使用float和double类型。
"float_double存储问题" float 和 double 是 C 语言和 C# 语言中最常用的浮点类型,它们分别使用单精度和双精度来存储浮点数据。 float 数据占用 32bit,而 double 数据占用 64bit。 在 IEEE 的规范下,float ...
下面我们将详细探讨Java中的数值范围、float和double类型的精度问题,并且提供解决方案。 一、Java中的数值范围 Java中的基本数据类型有多种,包括整数类型(int、long)、浮点数类型(float、double)。每种类型...
当我们使用`atof()`函数将字符串转换为`float`或`double`时,可能会遇到精度损失问题。例如,将字符串"8.2"转换为`float`时,结果为8.1999998,而转换为`double`时,结果为8.1999999999999993。这是因为浮点数在...
特别是在处理二进制数据或者进行低级编程时,了解如何将十六进制(HEX)转换为浮点数(float)或双精度浮点数(double)至关重要。这个"HEX-Float转换工具"就是这样一个实用程序,它帮助用户方便快捷地完成这种转换...
测试可能包括各种边界条件,如最大整数值、最小整数值、随机整数以及特定模式的整数,以全面评估转换过程中的精度问题。 执行生成的`int2flt.exe`可执行文件,将运行这个测试,输出哪些整数在转换过程中出现了精度...
标题中的"Java 精确计算 - double-float-String"指向的是Java中处理浮点数(double和float)以及字符串表示的数值时可能遇到的精度问题,以及如何通过特定方法实现精确计算。描述中提到的链接指向了一个具体的博客...
在C#编程中,处理多位小数的精度问题是一个常见的挑战。这主要涉及到浮点数和定点数的数据类型,以及它们在数学运算中可能出现的精度损失。本文将深入探讨这个问题,并提供解决方案。 首先,让我们理解为何会出现...
例如,`float`和`double`类型的值在进行加减乘除运算后,结果可能与预期不符,尤其是在比较两个浮点数是否相等时,直接使用`==`可能会得到错误的结果。 为了解决这个问题,我们可以采用以下策略: 1. **避免直接...
在进行浮点数转换时,需要注意精度丢失和溢出问题。由于浮点数的有限精度,某些特定的十进制数字可能无法精确表示为二进制浮点数,这可能导致计算结果出现微小的误差。此外,过大或过小的数值可能会导致指数溢出,...
在C语言或类似的编程环境中,`long double`通常代表最高精度的浮点数类型,而`float`则是较低精度的一种。在某些情况下,隐式类型转换可能会发生,这可能会影响数值计算的精度。 描述中的“instantiate a ...
3. **精度和范围**:由于`float`和`double`的位数不同,它们的精度和表示的数值范围也有所差异。`double`通常具有更高的精度和更大的数值范围,因此在需要更高精度的计算中更常被使用。 了解这些基础知识后,可以...
而浮点类型,如float和double,是用于存储小数的数值类型,广泛应用于科学计算、图形处理等领域。了解和掌握十六进制与浮点类型的转换是每一位IT专业人员的基本技能。 十六进制是一种逢16进1的计数系统,使用16个...
decimal, double, 和 float 是 C# 中三种不同的浮点数类型,它们之间的区别在于精度、范围和应用场景。 首先,float 是 32 位单精度浮点数,具有 7 位有效数字,范围约为 ±1.5 × 10^(-45) 到 ±3.4 × 10^(38)。...
"关于浮点数的精度问题" 浮点数精度问题是一个经典的问题,对于了解和学习C语言有一定帮助。浮点数的精度问题是由于计算机对浮点数的存储方式和表示方法所致。 IEEE754 的浮点数存储格式对浮点数的表示方法进行了...