检测 Java 数字格式不准确



我想准确地解析一个整数,一个可能根据当前语言环境格式化的整数。如果我没有准确解析整数,我想知道它。所以我使用:

String string = "1111122222333334444455555";
Locale locale = Locale.getDefault();
NumberFormat numberFormat = NumberFormat.getIntegerInstance(locale);
numberFormat.setParseIntegerOnly();
Number number = numberFormat.parse(string);

显然,"1111122222333334444455555"代表一个很大的数字,比Long可以处理的还要大。所以NumberFormat给了我...Double??

我想我本来希望收到一个BigInteger而不是一个Double,特别是因为我要求一个特定于整数的数字格式化器。但没关系;更大的问题是我得到的双倍值是1.1111222223333344E24!这不等于1111122222333334444455555!!

如果NumberFormat给我一个解析的值,该值不等于存储在输入字符串中的值,我该如何检测?

换句话说:"我怎么知道我从NumberFormat得到的Double值是否与原始字符串中表示的整数值完全等同?

parse()的javadocs声明,如果可能的话,它将返回一个Long,否则它将返回一个Double。 因此,只需检查返回值是否为 Long 即可。

"如果可能,则返回一个 Long(例如,在 [Long.MIN_VALUE, Long.MAX_VALUE] 范围内并且没有小数),否则返回 Double。

"我怎么知道我从 NumberFormat 返回的双精度值是否与原始字符串中表示的整数值完全等效?"

如果它返回 Double,则它完全等同于您的整数值,因为 Double 无法准确表示该量级的值。 具体例子:

  Number a = numberFormat.parse("-9223372036854775809"); // Integer.MIN_VALUE - 1
  Number b = numberFormat.parse("-9223372036854775810"); // Integer.MIN_VALUE - 2
  System.out.println((a.equals(b))); // prints "true"
  Number c = numberFormat.parse("-9223372036854776800");
  System.out.println((a.equals(c))); // prints "true"

对于你的问题 -

If NumberFormat gives me a parsed value that does not equal that stored in the input string, how do I detect that?

您可以使用

    if(number.toString().equals(string))
      //Parsed correctly
   else
     //Invalid parse

这可能不是解决方案,但值得注意。

public static void main(String[] args) {
        String string = "1111122222333334444455555";
        Locale locale = Locale.getDefault();
        NumberFormat numberFormat = NumberFormat.getIntegerInstance(locale);
        numberFormat.setParseIntegerOnly(true);
        Number number = numberFormat.parse(string);
        BigDecimal b = new BigDecimal(number.toString());
        System.out.println(b.toBigInteger());
    }

此代码的输出为: 1111122222333334400000000

如您所见,这不等于实际字符串中的数字,因此它们可能是溢出的。

最新更新