Floating point 当'expr'嵌套在Tcl中时,为什么算术结果不同?

Floating point 当'expr'嵌套在Tcl中时,为什么算术结果不同?,floating-point,expression,tcl,Floating Point,Expression,Tcl,了解到由于浮点数的内部表示而导致的不准确(请参阅,搜索到:“使用相等测试”…),执行以下操作时仍然会有一个惊喜: % expr int(0.57 * 10000) 5699 % expr int([expr 0.57 * 10000]) 5700 嵌套的expr是否被禁止?为什么它会改变传递的浮点值?或者它会改变浮点运算的顺序,影响结果吗 更新:关于的主题(以及二级链接)和的良好阅读。这是一个有趣的问题,因为它涉及到一些微妙的事情 % expr int(0.57 * 10000) 5699

了解到由于浮点数的内部表示而导致的不准确(请参阅,搜索到:“使用相等测试”…),执行以下操作时仍然会有一个惊喜:

% expr int(0.57 * 10000)
5699
% expr int([expr 0.57 * 10000])
5700
嵌套的
expr
是否被禁止?为什么它会改变传递的浮点值?或者它会改变浮点运算的顺序,影响结果吗


更新:关于的主题(以及二级链接)和的良好阅读。

这是一个有趣的问题,因为它涉及到一些微妙的事情

% expr int(0.57 * 10000)
5699
这段代码(没有替换,所以它“毫不奇怪地”工作)表明浮点数本身是令人惊讶的事情。特别是,0.57没有IEEE双精度浮点数(以2为基数)的精确表示;事实上,它的表示比精确的0.57稍微低一点,所以当向下舍入时(这就是
int(…)
所做的;10000本身是精确的),您将下降到5699。在其他语言中也会看到同样的行为

% expr int([expr 0.57 * 10000])
5700
现在这特别有趣。您首先看到的是内部计算正在进行,结果浮点被转换为字符串(因为实际上没有其他方法可以这样做)。现在,您必须使用Tcl 8.4(或之前的版本),其中默认的数字呈现规则(实际上)是通过打印数字的前15位有效数字得到的;在本例中,这将为您提供
5700.00000000000
(好吧,在右侧截断一些零),然后从头开始重新解释为double(确切地说是5700.0),然后转换为5700

Tcl 8.5中更改了数字转换规则。如今,当Tcl将浮点数转换为字符串时,它会生成最短的字符串,该字符串将转换回完全相同的浮点数(即,通过字符串区域的侧行程将在生成的双精度中给出相同的位模式)。这意味着你现在再也看不到上面两件事之间的区别了。(如果确实要强制使用固定的小数位数,请使用
格式%.15g[expr 0.57*10000]

如果你正确地调整你的表达方式,你也不会在8.0到8.4之间看到观察到的行为,正如社区十多年来一直建议人们做的那样:

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

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

谢谢你确认了我的怀疑,并增加了很多知识。是的,如果有tcl8.4标签,我会设置它,Sherlock;-)