Java 往返字符串 -> 浮点数 -> 字符串,即使对于(某些)不能表示为浮点数的值也是如此?



正如许多地方所解释的那样(例如为什么十进制数不能精确地用二进制表示?),并不是所有的十进制分数都可以表示为浮点值(例如存储在Java中的float中)。

给出的典型例子是"0.2"。根据这个漂亮的IEEE 754转换器,最接近0.2的float大约是0.20000000298023224,所以将"0.2"解析为float应该会得到这个结果。

然而,我注意到Java似乎能够做不可能的事情:

String number="0.2";
float f = Float.parseFloat(number);
System.out.println("Result of roundtrip String -> float -> String: "+f);

打印:

返回String -> float -> String: 0.2

在IDeone.com上测试

Java如何知道我想要(四舍五入)输出"0.2",而不是精确输出"0.20000000298023224"如上所述?

Float.toString()的Javadocs试图解释这一点:

m或a的小数部分必须打印多少位数字?必须至少有一个数字来表示小数部分,并且除此之外,需要多少位数,但只有多少位数唯一区分参数值与类型的相邻值浮动。

不幸的是,这更让我困惑。为什么"打印尽可能多的数字以唯一区分参数值"允许Java打印"0.2"?

理想情况下,答案也会解释为什么选择这个打印算法。它是使(一些)往返工作,如在这个例子中?还有其他动机吗?

输出的四舍五入不是由于某些打印算法。这是因为float的大小。

String fs = "0.2";
double f = Float.parseFloat(fs);
System.out.println(f);

:

0.20000000298023224

在Ideone.com上测试

这清楚地表明字符串"0.2"被解析为0.20000000298023224,但float数据类型无法保存它,并将其四舍五入到0.2。double数据类型能够保存此数据,因此,当将其解析为float,但将其存储在双精度中时,您将得到预期的输出。

我猜0.2属于"Value Set Conversion"