% expr 60.9-59.7
1.1999999999999957
在上述示例中,expr
似乎以其计算的更高精度输出浮点运算的结果。
对于简单的,我希望有一个更合理的输出,比如这个C++代码的输出:
#include <iostream>
int main()
{
double a = 60.9;
a -= 59.7;
std::cout << "double a = " << a << std::endl;
float b = 60.9;
b -= 59.7;
std::cout << "float b = " << b << std::endl;
}
输出:
double a = 1.2
float b = 1.2
因此问题:
为什么TCL输出expr
结果的精度高于计算结果的精度,从而导致lsb伪影?
有可能通过设置全局精度变量或全局输出分辨率变量之类的变量来防止这种闹剧吗?
有一个全局变量控制Tcl在转换为字符串时使用的精度位置:Tcl_precision。然而,在查找这个答案时,我发现自从上次使用它以来,它一直被弃用,并且使用format命令的显示控件是首选。看见http://wiki.tcl.tk/1650了解如何使用它以及为什么不应该使用它的详细信息。
请注意,您在使用C++时也会遇到同样的问题;这是IEEE浮点数格式的问题,而不是Tcl的问题。您所抱怨的"过度"精度只是显示输出的确切值,而没有对其进行格式化以满足您的需求。C/C++与;Tcl是格式化C输出的默认精度为6位。
这个答案表明,对于C++,这个问题也会出现。
您无法控制结果的值。你想控制你的输出方式:
% expr 60.9-59.7
1.1999999999999957
% puts [format {%.2f} [expr {60.9-59.7}]]
1.20
浮点运算由Tcl的运行时执行,该运行时是从C编译的。它的工作原理与从C/C++编译的任何其他可执行文件中的浮点运算完全相同。然而,在Tcl中,与C/C++不同,字符串表示可能用于进一步的计算*,这意味着精度的任意损失将是一件坏事。
你可以用一个基本上看起来像这样的命令来代替普通的puts
命令(只是概念的证明:在实践中,你需要更多的基础设施来1(处理额外的参数,2(避免它在puts
捕获shell中以不同的方式工作,3(将对它的一些控制权返回给程序员,但这是非常可行的(:
proc _puts str {
if {[string is double -strict $str]} {
puts [format %g $str]
} else {
puts $str
}
}
默认情况下,这将打印四舍五入的浮点数字。
*)几十年前,Tcl代码是字节编译的,使用实际的浮点值及其字符串表示形式存储在一起,但如果程序员出于某种原因决定使用s.r,编译器仍然会屈从于他们的意愿。信任s.r."无损"的能力是语言和程序员之间合同的一部分,不太可能改变。