2012-03-28 127 views
4

寂寂因为浮点数的内部表现的不准确(见Wikipedia,搜索到:“用平等的测试” ...),还有在做的时候仍然是一个惊喜:当`expr`嵌套在Tcl中时,为什么算术结果会有所不同?

% expr int(0.57 * 10000) 
5699 
% expr int([expr 0.57 * 10000]) 
5700 

是嵌套expr禁止?为什么它会改变通过的浮点值?还是它会改变浮点算法的执行顺序,影响结果的顺序?

更新:关于comparing floating point numbers with speed(和辅助链接),some basics and not so basics herethe IEEE 754-2008 standard's description的主题很好的阅读。

回答

7

这是一个有趣的问题,因为它触及了一些微妙的事情。

% expr int(0.57 * 10000) 
5699 

此代码(有没有换人,所以它的工作原理“意料之中”)显示,浮点数,本身就是令人惊奇的事情。特别是,0.57没有精确的表示形式作为IEEE双精度浮点数(基数为2);实际上,它的表示比精确到0.57稍低,所以当向下舍入时(这是int(...)所做的; 10000本身就是确切的),您可以下降到5699.您也会看到与其他语言相同的行为。

% expr int([expr 0.57 * 10000]) 
5700 

现在这特别有趣。你首先看到内部计算正在完成,并且生成的float被转换为一个字符串(因为实际上没有其他方法可以做到这一点)。现在,您必须使用Tcl 8.4(或之前),默认数字渲染规则是(实际上)通过打印数字的前15个有效数字而得到的;在这种情况下,让你5700.00000000000(当然,在右边零的一些截断),这就是再从头作为第一重新演绎双(准确5700.0),然后是会转换为5700

的数量规则转换在Tcl 8.5中改变。现在,当Tcl将浮点数转换为字符串时,它会产生最短的字符串,该字符串将转换回完全相同的浮点数(即通过字符串域的旁路将在所得到的双精度中给出相同的位模式)。这意味着你现在从来没有看到上述两件事之间的区别。 (如果你真的想要强制固定的小数位数,请使用format %.15g [expr 0.57 * 10000]。)

如果你正确地使用表达式,就像社区建议人们做的那样,你也不会观察到8.0到8.4的行为十多年来:

$ tclsh8.4 
% expr {int([expr 0.57 * 10000])} 
5699 

这是因为这并不强制内部expr调用的结果被解释为一个字符串。 (它也更快,更安全。)

+0

感谢您确认怀疑并添加了大量的知识。而且,是的,如果我有一个tcl8.4标签,Sherlock ;-) – cfi 2012-03-28 10:57:08

相关问题