简体   繁体   English

如何知道 BigDecimal 是否可以准确地转换为 float 或 double?

[英]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_INFINITYDouble.NEGATIVE_INFINITY用于双精度和Float.POSITIVE_INFINITYFloat.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_INFINITYNEGATIVE_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旨在处理由于对大型无理数使用floatdouble而导致的精度不足,因此正如@JB Nizet 评论的那样,您可以添加到上面的另一项检查是将doublefloat转换回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.02.00

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM