[英]How to know if a BigDecimal can exactly convert to float or double?
Class BigDecimal
has some useful methods to guarantee lossless conversion: BigDecimal
类有一些有用的方法来保证无损转换:
byteValueExact()
shortValueExact()
intValueExact()
longValueExact()
However, methods floatValueExact()
and doubleValueExact()
do not exist.但是,方法
floatValueExact()
和doubleValueExact()
不存在。
I read the OpenJDK source code for methods floatValue()
and doubleValue()
.我阅读了方法
floatValue()
和doubleValue()
的 OpenJDK 源代码。 Both appear to fallback to Float.parseFloat()
and Double.parseDouble()
, respectively, which may return positive or negative infinity.两者似乎分别回
Float.parseFloat()
和Double.parseDouble()
,它们可能返回正无穷大或负无穷大。 For example, parsing a string of 10,000 9s will return positive infinity.例如,解析 10,000 个 9 的字符串将返回正无穷大。 As I understand,
BigDecimal
does not have an internal concept of infinity.据我了解,
BigDecimal
没有无穷大的内部概念。 Further, parsing a string of 100 9s as double
gives 1.0E100
, which is not infinity, but loses precision.此外,将 100 个 9 的字符串解析为
double
得到1.0E100
,它不是无穷大,但会失去精度。
What is a reasonable implementation floatValueExact()
and doubleValueExact()
?什么是合理的实现
floatValueExact()
和doubleValueExact()
?
I thought about a double
solution by combining BigDecimal.doubleValue()
, BigDecial.toString()
, Double.parseDouble(String)
and Double.toString(double)
, but it looks messy.我想到了结合
BigDecimal.doubleValue()
、 BigDecial.toString()
、 Double.parseDouble(String)
和Double.toString(double)
的double
解决方案,但它看起来很乱。 I want to ask here because there may (must.) be a simpler solution.我想在这里问,因为可能(必须)有一个更简单的解决方案。
To be clear, I don't need a high performance solution.需要明确的是,我不需要高性能解决方案。
From reading the docs , all it does with the numTypeValueExact
variants is to check for existence of a fraction part or if the value is too big for the numeric type and throw exceptions. 通过阅读文档,它对
numTypeValueExact
变体所做的一切就是检查是否存在小数部分,或者该值对于数字类型来说是否太大并抛出异常。
As for floatValue()
and doubleValue()
, a similar overflow check is being done, but instead of throwing an exception, instead it returns Double.POSITIVE_INFINITY
or Double.NEGATIVE_INFINITY
for doubles and Float.POSITIVE_INFINITY
or Float.NEGATIVE_INFINITY
for floats.至于
floatValue()
和doubleValue()
,正在进行类似的溢出检查,但不是抛出异常,而是返回Double.POSITIVE_INFINITY
或Double.NEGATIVE_INFINITY
用于双精度和Float.POSITIVE_INFINITY
或Float.NEGATIVE_INFINITY
用于浮点数。
Therefore the most reasonable (and simplest) implementation of the exact
methods for float and double, should simply check if the conversion returns POSITIVE_INFINITY
or NEGATIVE_INFINITY
.因此,最合理(也是最简单)的 float 和 double
exact
方法的实现应该简单地检查转换是否返回POSITIVE_INFINITY
或NEGATIVE_INFINITY
。
Furthermore , remember that BigDecimal
was designed to handle the lack of precision that comes from using float
or double
for large irrationals, therefore as @JB Nizet commented , another check you can add to the above would be to convert the double
or float
back to BigDecimal
to see if you still get the same value.此外,请记住
BigDecimal
旨在处理由于对大型无理数使用float
或double
而导致的精度不足,因此正如@JB Nizet 评论的那样,您可以添加到上面的另一项检查是将double
或float
转换回BigDecimal
看看你是否仍然获得相同的价值。 This should prove the conversion was correct.这应该证明转换是正确的。
Here is what such a method would look like for floatValueExact()
:以下是
floatValueExact()
的这种方法:
public static float floatValueExact(BigDecimal decimal) {
float result = decimal.floatValue();
if (!(Float.isNaN(result) || Float.isInfinite(result))) {
if (new BigDecimal(String.valueOf(result)).compareTo(decimal) == 0) {
return result;
}
}
throw new ArithmeticException(String.format("%s: Cannot be represented as float", decimal));
}
The use of compareTo
instead of equals
above is intentional so as to not become too strict with the checks.使用
compareTo
而不是上面的equals
是有意的,以免对检查过于严格。 equals
will only evaluate to true when the two BigDecimal
objects have the same value and scale (size of the fraction part of the decimal), whereas compareTo
will overlook this difference when it does not matter.只有当两个
BigDecimal
对象具有相同的值和比例(小数部分的大小)时, equals
才会评估为 true,而compareTo
在无关紧要时将忽略这种差异。 For example 2.0
vs 2.00
.例如
2.0
与2.00
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.