如浮点类型一样, BigDecimal
也有一些令人奇怪的行为。尤其在使用 equals()
方法来检测数值之间是否相等时要小心。 equals()
方法认为,两个表示同一个数但换算值不同(例如, 100.00
和 100.000
)的 BigDecimal
值是不相等的。然而, compareTo()
方法会认为这两个数是相等的,所以在从数值上比较两个 BigDecimal
值时,应该使用 compareTo()
而不是 equals()
。
另外还有一些情形,任意精度的小数运算仍不能表示精确结果。例如, 1
除以 9
会产生无限循环的小数 .111111...
。出于这个原因,在进行除法运算时, BigDecimal
可以让您显式地控制舍入。 movePointLeft()
方法支持 10 的幂次方的精确除法。
SQL-92 包括 DECIMAL
数据类型,它是用于表示定点小数的精确数字类型,它可以对小数进行基本的算术运算。一些 SQL 语言喜欢称此类型为 NUMERIC
类型,其它一些 SQL 语言则引入了 MONEY
数据类型,MONEY 数据类型被定义为小数点右侧带有两位的小数。
如果希望将数字存储到数据库中的 DECIMAL
字段,或从 DECIMAL
字段检索值,则如何确保精确地转换该数字?您可能不希望使用由 JDBC PreparedStatement
和 ResultSet
类所提供的 setFloat()
和 getFloat()
方法,因为浮点数与小数之间的转换可能会丧失精确性。相反,请使用 PreparedStatement
和 ResultSet
的 setBigDecimal()
及 getBigDecimal()
方法。
对于 BigDecimal
,有几个可用的构造函数。其中一个构造函数以双精度浮点数作为输入,另一个以整数和换算因子作为输入,还有一个以小数的 String
表示作为输入。要小心使用 BigDecimal(double)
构造函数,因为如果不了解它,会在计算过程中产生舍入误差。请使用基于整数或 String
的构造函数。
对于 BigDecimal
,有几个可用的构造函数。其中一个构造函数以双精度浮点数作为输入,另一个以整数和换算因子作为输入,还有一个以小数的 String
表示作为输入。要小心使用 BigDecimal(double)
构造函数,因为如果不了解它,会在计算过程中产生舍入误差。请使用基于整数或 String
的构造函数。
如果使用 BigDecimal(double)
构造函数不恰当,在传递给 JDBC setBigDecimal()
方法时,会造成似乎很奇怪的 JDBC 驱动程序中的异常。例如,考虑以下 JDBC 代码,该代码希望将数字 0.01
存储到小数字段:
PreparedStatement ps = connection.prepareStatement("INSERT INTO Foo SET name=?, value=?"); ps.setString(1, "penny"); ps.setBigDecimal(2, new BigDecimal(0.01)); ps.executeUpdate(); |
在执行这段似乎无害的代码时会抛出一些令人迷惑不解的异常(这取决于具体的 JDBC 驱动程序),因为 0.01
的双精度近似值会导致大的换算值,这可能会使 JDBC 驱动程序或数据库感到迷惑。JDBC 驱动程序会产生异常,但可能不会说明代码实际上错在哪里,除非意识到二进制浮点数的局限性。相反,使用 BigDecimal("0.01")
或 BigDecimal(1, 2)
构造 BigDecimal
来避免这类问题,因为这两种方法都可以精确地表示小数。
|
在 Java 程序中使用浮点数和小数充满着陷阱。浮点数和小数不象整数一样“循规蹈矩”,不能假定浮点计算一定产生整型或精确的结果,虽然它们的确“应该”那样做。最好将浮点运算保留用作计算本来就不精确的数值,譬如测量。如果需要表示定点数(譬如,几美元和几美分),则使用 BigDecimal
。
原文地址:http://justjavac.iteye.com/blog/1073775