BigDecimal 行为的差异
Difference in BigDecimal behavior
我有两段代码new BigDecimal("1.240472701")
和new BigDecimal(1.240472701)
。现在,如果我在两种方法上都使用 java 的 compareTo 方法,那么我会发现它们不相等。
当我使用 java 的 System.out.println()
方法打印值时。对于这两个值,我得到了不同的结果。例如
new BigDecimal("1.240472701") -> 1.240472701
new BigDecimal(1.240472701) -> 1.2404727010000000664291519569815136492252349853515625
所以我想了解这可能是什么原因?
您可以参考 public BigDecimal(double val)
的 Java 文档:
public BigDecimal(double val)
Translates a double into a BigDecimal
which is the exact decimal representation of the double's binary
floating-point value. The scale of the returned BigDecimal is the
smallest value such that (10^scale × val) is an integer.
The results of this constructor can be somewhat unpredictable. One
might assume that writing new BigDecimal(0.1) in Java creates a
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 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 String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates
a BigDecimal which is exactly equal to 0.1, as one would expect.
Therefore, it is generally recommended that the String constructor be
used in preference to this one.
When a double must be used as a source
for a BigDecimal, note that this constructor provides an exact
conversion; it does not give the same result as converting the double
to a String using the Double.toString(double) method and then using
the BigDecimal(String) constructor. To get that result, use the static
valueOf(double) method.
由于用户 thegauravmahawar 从文档中提供了答案。是的,这是因为 Scaling in BigDecimal case.
因此这些值可能看起来等于 You 但内部 java 在存储 BigDecimal 类型的值时使用缩放。
原因:缩放。
改进:
您可以对要比较的数字调用 setScale 以实现相同的功能:
像这样
new BigDecimal ("7.773").setScale(2).equals(new BigDecimal("7.774").setScale (2))
这将使您免于犯任何错误。
字符串 "1.240472701"
是十进制值的文本表示。 BigDecimal
代码对此进行解析并创建一个 BigDecimal
,其中 精确 值在字符串中表示。
但是 double
1.240472701
只是该精确十进制值的(接近)近似值。 Double
无法准确表示所有十进制值,因此 double
中存储的准确值略有不同。如果将其传递给 BigDecimal
,它会采用不同的值并将其转换为精确的 BigDecimal
。但是 BigDecimal
只有不精确的 double
可以通过,它不知道确切的文本表示。所以它只能表示double
中的值,不能表示源文本中的值
第一种情况:
String --> BigDecimal
因为 BigDecimal 可以精确表示小数值,所以转换是准确的。
第二种情况:
1 2
Source code text --> double --> BigDecimal
在第二种情况下,精度在第一次转换 (1) 中丢失。第二次转换 (2) 是精确的,但输入——双精度——是源代码文本 1.240472701
的不精确表示(实际上,它是 1.2404727010000000664291519569815136492252349853515625
)。
因此:永远不要用双精度初始化 BigDecimal,如果可以的话。请改用字符串。
这就是为什么第一个 BigDecimal 是准确的而第二个不是。
我有两段代码new BigDecimal("1.240472701")
和new BigDecimal(1.240472701)
。现在,如果我在两种方法上都使用 java 的 compareTo 方法,那么我会发现它们不相等。
当我使用 java 的 System.out.println()
方法打印值时。对于这两个值,我得到了不同的结果。例如
new BigDecimal("1.240472701") -> 1.240472701
new BigDecimal(1.240472701) -> 1.2404727010000000664291519569815136492252349853515625
所以我想了解这可能是什么原因?
您可以参考 public BigDecimal(double val)
的 Java 文档:
public BigDecimal(double val)
Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10^scale × val) is an integer.
The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a 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 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 String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one.
When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method.
由于用户 thegauravmahawar 从文档中提供了答案。是的,这是因为 Scaling in BigDecimal case.
因此这些值可能看起来等于 You 但内部 java 在存储 BigDecimal 类型的值时使用缩放。
原因:缩放。
改进:
您可以对要比较的数字调用 setScale 以实现相同的功能: 像这样
new BigDecimal ("7.773").setScale(2).equals(new BigDecimal("7.774").setScale (2))
这将使您免于犯任何错误。
字符串 "1.240472701"
是十进制值的文本表示。 BigDecimal
代码对此进行解析并创建一个 BigDecimal
,其中 精确 值在字符串中表示。
但是 double
1.240472701
只是该精确十进制值的(接近)近似值。 Double
无法准确表示所有十进制值,因此 double
中存储的准确值略有不同。如果将其传递给 BigDecimal
,它会采用不同的值并将其转换为精确的 BigDecimal
。但是 BigDecimal
只有不精确的 double
可以通过,它不知道确切的文本表示。所以它只能表示double
中的值,不能表示源文本中的值
第一种情况:
String --> BigDecimal
因为 BigDecimal 可以精确表示小数值,所以转换是准确的。
第二种情况:
1 2
Source code text --> double --> BigDecimal
在第二种情况下,精度在第一次转换 (1) 中丢失。第二次转换 (2) 是精确的,但输入——双精度——是源代码文本 1.240472701
的不精确表示(实际上,它是 1.2404727010000000664291519569815136492252349853515625
)。
因此:永远不要用双精度初始化 BigDecimal,如果可以的话。请改用字符串。
这就是为什么第一个 BigDecimal 是准确的而第二个不是。