“System.out.println(DECIMAL)”是否始终在代码中输出相同的DECIMAL?

时间:2014-03-04 11:24:43

标签: java floating-point floating-point-precision

当然, System.out.println( 0.1 ); 输出0.1。但对于任意小数,它总是如此吗? (排除由双数本身精度产生的情况。例如,System.out.println( 0.10000000000000000001);输出0.1

当我点击System.out.println( DECIMAL );时,我认为,DECIMAL被转换为二进制(double),二进制转换为十进制(以十进制形式输出十进制)


考虑以下转换。

十进制[D1] - > (CONVERSION1) - >二进制[B] - > (CONVERSION2) - >小数[D2]

CONVERSION1

(在double的有效位数范围内)[D1]的最近二进制选择为[B]

e.g。 [D1] 0.1-> [B] 0x0.1999999999999a

CONVERSION2

[D2]是十进制数,可以唯一地区分[B]并具有最小的数字。

e.g。 [B] 0x0.1999999999999a - > [D2] 0.1

QUOTE Java7 API Double.toString(double d)

  

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


我的问题

是" [D1] = [D2]"总是如此?


为什么我问这个问题

考虑以下情况,

将用户的十进制输入保存为double - >显示十进制

我想知道[用户的输入=显示]是否有保证。

(如上所述,排除由双数本身的精度引起的情况。由于这种长输入是罕见的情况。)

我知道当我需要准确的算术时,我应该使用BigDecimal。但在这种情况下,我不需要准确的算术。只想显示与用户输入相同的小数。

2 个答案:

答案 0 :(得分:1)

这部分取决于你对平等的定义。如果你需要精确的字符串匹配,答案是否定的。例如:

System.out.println(0.1e-1);

打印

0.01

现在假设“相等”表示十进制值相等,因此0.1e-10.01相等。

如果您将双打限制为正常数字(非次正常,上溢或下溢)且小数位数小于16,则您是安全的。无穷小数小数轮到每个二进制小数,可以用double精确表示。要恢复原始,它必须是该集合中最短的成员。这意味着它与相同或较短长度的两个最接近的十进制数之间的差异必须足够大,以确保它们可以舍入到不同的双精度数。要获得相同或更短长度的另一个十进制数,需要更改原始数字的至少一个十进制ulp。

如果两个十进制数在2 ^ 54中的差异超过一个部分且处于正常数字范围内,则它们相距太远而无法映射到同一个双精度数。

这种推理不适用于次正规数,因为它们的精度低于普通数:

System.out.println(0.123451234512345e-310);

打印

1.2345123451236E-311

即使输入只有15位有效数字。

答案 1 :(得分:0)

第一次转换,从十进制到二进制,可能会产生另一个数学值,因为并非每个小数都可以精确地表示为二进制数。这与二进制的准确性无关,以0.1为例。

从二进制到十进制的第二次转换总是可以无损方式进行,即产生相同的数学值。这通常需要一个可笑的长十进制表示,所以在实践中你会将值四舍五入到更短的表示,然后再不再是相同的数学值。

您的问题的答案“[D1] = [D2]是否总是正确的?”因此一般来说没有。这一切都取决于二进制和十进制表示的准确性。