Java 浮点的显示精度

Posted

技术标签:

【中文标题】Java 浮点的显示精度【英文标题】:Displayed precision of Java floating-point 【发布时间】:2019-02-25 15:45:44 【问题描述】:

如果我们运行以下代码:

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.22222222222222222222 中的长尾未被忽略(变量 d 中的最后一个十进制数字变为 3 而不是 2)。为什么?

【问题讨论】:

double 有两倍于浮点数的字节来表示数据。它可以更准确......但它不可能是完美的。 How many significant digits have floats and doubles in java? 数据量并没有改变浮点和双精度类型有其限制的事实。 ***.com/questions/322749/… @Lino:请不要将浮点问题标记为 that one 的重复项。这个问题询问为什么显示更多或更少的数字,这是 Java 将 floatdouble 转换为十进制的规则的结果,这在该问题或 this one 中没有解释。 【参考方案1】:

打印floatdouble 时看到的位数是Java 将floatdouble 默认转换为十进制的规则的结果。

Java 对浮点数的默认格式使用所需的最少有效十进制数字来区分数字与附近的可表示数字。1

在您的示例中,源文本中的1.2345678990922222f 被转换为float 值1.2345678806304931640625,因为在float 类型中可表示的所有值中,该值最接近1.2345678990922222。下一个较低和下一个较高的值是 1.23456776142120361328125 和 1.23456799983978271484375。

当打印这个值时,Java 只需要打印“1.2345679”,因为这足以让我们从它的邻居 1.23456776142120361328125 和 1.2345679998397827148475 中挑选出 float 值 1.2345678806304931640625。

73

对于您的 double 示例,1.22222222222222222222d 转换为 1.22222222222222232090871330001391470432281494140625。 double 中可表示的下一个较低值和下一个较高值是 1.2222222222222220988641083749826066195964813232421875 和 1.22222222222222254295331822504522277030491485559。如您所见,为了将 1.22222222222222232090871330001391470432281494140625 与其邻居区分开来,Java 需要打印“1.2222222222222223”。

脚注

1Java SE 10 的规则可以在 toString(float d) 部分的 java.lang.float 文档中找到。 double 文档类似。这段话,最相关的部分用粗体表示,是:

返回float argument 的字符串表示形式。下面提到的所有字符都是ASCII字符。

如果参数为 NaN,则结果为字符串“NaN”。

否则,结果是一个字符串,表示参数的符号和大小(绝对值)。如果符号为负,则结果的第一个字符是'-'('\u002D');如果符号为正,则结果中不会出现符号字符。至于幅度m

如果m为无穷大,则用字符“Infinity”表示;因此,正无穷大产生结果“Infinity”,负无穷大产生结果“-Infinity”。

如果m为零,则用字符“0.0”表示;因此,负零产生结果“-0.0”,正零产生结果“0.0”。

如果m大于等于10-3但小于107,则表示为整数部分m,十进制形式,不带前导零,后跟“.”('\u002E'),后跟代表m小数部分的一位或多位十进制数字.

如果m小于10-3或者大于等于107,那么用所谓的“计算机科学记数法。”令 n 为唯一整数,满足 10nm n+1;然后让 am 和 10n 的数学精确商,因此 1 ≤ a a 的整数部分,作为单个十进制数字,后跟“.”('\u002E'),然后是表示a 的小数部分,后跟字母 'E' ('\u0045'),后跟 n 表示为十进制整数,由该方法生成Integer.toString(int).

ma 的小数部分必须打印多少位? 必须至少有一个数字来表示小数部分,除此之外,必须有尽可能多的数字,但只有尽可能多的数字才能唯一地将参数值与 float 类型的相邻值区分开来。 也就是说,假设 x 是由该方法为有限非零参数 f 生成的十进制表示所表示的精确数学值。那么f必须是最接近xfloat值;或者,如果两个float 值同样接近 x,则 f 必须是其中之一,并且是 f 的有效位的最低有效位em> 必须为 0。

【讨论】:

以上是关于Java 浮点的显示精度的主要内容,如果未能解决你的问题,请参考以下文章

如何在Java中将浮点数组转换为双精度数组?

在 C 代码的 printf 语句中使用时,不会显示浮点或双精度值

java丢失精度问题

限制浮点精度?

Java中浮点类型的精度问题 double float

什么叫单精度浮点型?什么叫双精度浮点型?