2014-03-04 53 views
1

当然, System.out.println(0.1); 输出0.1。但是对于任意小数点总是这样吗? (排除的双号本身。如,System.out.println(0.10000000000000000001);输出0.1精度而导致的情况下)“System.out.println(DECIMAL)”是否始终在代码中输出相同的DECIMAL?

当我打System.out.println(DECIMAL);我认为,DECIMAL被转换成二进制(双)和二进制转换成十进制(以输出小数点作为字符串)


想想下面的转换。

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

CONVERSION1

(的显著位的范围内双倍)[D1]的最接近的二进制数被选择为[B]

例如[D1] 0.1 - > [B] 0x0.1999999999999a

CONVERSION2

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

例如[B] 0x0.1999999999999a - > [D2] 0.1

QUOTE Java7 API Double.toString(double d)

多少位必须被打印的米或一个小数部分?必须至少有一位数字来表示小数部分,并且除此之外还需要多少位数,但只需要多少位数来唯一地区分参数值和类型为double的相邻值。也就是说,假设x是由该方法对有限非零参数d产生的十进制表示所表示的精确数学值。那么d必须是最接近x的double值;如果两个double值都同样接近x,那么d必须是其中之一,d的有效数字的最低显著位必须为0


我的问题

“[D1] = [D2]”是否总是正确的?


为什么我问这个问题

思考下面的情况,

节省用户的十进制输入作为双 - >显示的是十进制

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

(如上所述,排除由双数本身的精度导致的情况。因为那很长的输入是罕见的情况。)

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

+0

听起来像你一路都知道,但你想要你的方式! :)但它会很有趣,看到它的一些答案。 – sakura

+0

我已经读过两遍你的问题,但我仍然不明白你的问题。 –

回答

0

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

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

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

+0

是否存在不输出相同小数的实际情况? –

+0

@idi_prog你的意思是特殊情况'System.out.println(DECIMAL)'? Fankly,我不知道。这需要仔细分析边缘情况。我认为,不同的产出很少。 – Henry

1

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

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

打印

0.01 

现在假设 “相等” 表示十进制的值相等,从而使0.1e-10.01是相等的。

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

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

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

打印

1.2345123451236E-311 

即使输入只有15显著位数:

,因为它们比正常数字精度要求不高这个道理​​并不适用于次正规数。