如果我们运行以下代码:
float f = 1.2345678990922222f;
double d = 1.22222222222222222222d;
System.out.println("f = " + f + "\t" + "d = " + d);
它打印:
f = 1.2345679 d = 1.2222222222222223
字面量1.2345678990922222中的长尾将被忽略,但1.22222222222222222222222中的长尾将不被忽略(变量d中的最后一个十进制数字变为3而不是2)。为什么?
答案 0 :(得分:2)
在打印float
或double
时看到的位数是Java的规则,即默认将float
和double
转换为十进制的规则。 / p>
Java的浮点数字默认格式使用最少的有效十进制数字来区分数字和附近的可表示数字。 1
在您的示例中,源文本中的1.2345678990922222f
转换为float
值1.2345678806304931640640625,因为在float
类型可以表示的所有值中,该值最接近1.2345678990922222。下一个较低和下一个较高的值是1.23456776142120361328125和1.23456799983978271484375。
当打印此值时,Java只需要打印“ 1.2345679”,因为这足以使我们可以从其邻居1.23456776142120361328125和1.23456799983978271271484375中选择float
值1.2345678806304931640625。
对于您的double
示例,1.22222222222222222222d
转换为1.22222222222222232090871330001391470432281494140625。 double
中可表示的下一个较低值和下一个较高值是1.2222222222222220988641083749826066195964813232421875和1.2222222222222225429533182250452227890491485595703125。如您所见,为了区分1.22222222222222232090871330001391470432281494140625和其邻居,Java需要打印“ 1.2222222222222223”。
1 Java SE 10的规则可以在java.lang.float文档的toString(float d)
部分中找到。 double
文档是相似的。段落中最相关的部分为粗体:
返回
float argument
的字符串表示形式。下面提到的所有字符都是ASCII字符。
如果参数为NaN,则结果为字符串“ NaN”。
否则,结果是一个字符串,代表参数的符号和大小(绝对值)。如果符号为负,则结果的第一个字符为'
-
'('\u002D'
);如果符号为正,则结果中不显示符号字符。至于 m 的大小:
如果 m 为无穷大,则用字符“ Infinity”表示;因此,正无穷大产生结果“ Infinity”,而负无穷大产生结果“ -Infinity”。
如果 m 为零,则用字符“ 0.0”表示;因此,负零会产生结果“ -0.0”,而正零会产生结果“ 0.0”。
如果 m 大于或等于10 -3 但小于10 7 ,则表示为 m 的整数部分,无十进制形式,无前导零,后跟“
.
”('\u002E'
),后跟一个或多个十进制数字,表示< em> m 。如果 m 小于10 -3 或大于或等于10 7 ,则表示为所谓的“计算机科学计数法”。设 n 为唯一整数,以使10 n ≤ m <10 n < / em> +1 ;然后让 a 为 m 和10 n 的数学精确商,这样1≤ a < / em> <10。然后将幅度表示为 a 的整数部分,用一个十进制数字表示,后跟'
.
'('\u002E'
),后跟代表 a 的小数部分的十进制数字,后跟字母'E
'('\u0045'
),然后以 n 的形式表示为十进制整数,由方法Integer.toString(int)
产生。m 或 a 的小数部分必须打印多少个数字? 必须至少有一位数字来表示小数部分,并且除此以外,还必须要有多少个数字才能唯一地将参数值与类型为
float
的相邻值区分开来。< / strong>也就是说,假设 x 是此方法为有限的非零参数 f 生成的十进制表示形式所表示的精确数学值。然后 f 必须是最接近 x 的float
值;或者,如果两个float
值均与 x 相等,则 f 必须是其中之一,并且是 f的有效位的最低有效位必须为0。