【发布时间】:2012-10-02 15:56:38
【问题描述】:
在下面的代码中,我遇到了一个奇怪的现象。在 if {$ma == $mb} 线上运行时,mb 和 ma 都等于 1.0,但没有采用 if。当我将== 更改为eq 或[cequal $ma $mb] 时,if 被采用。
此外,当我尝试使用 1.0(if {$ma == 1.0} 和 if {$1.0 == $mb})更改其中一个变量时,也没有采用 if,但是采用了带有表达式 if {1.0 ==1.0} 的 if。
在将== 更改为eq 后发生在我身上的另一件事是0.0 和-0.0 在使用eq 时不相等,但在使用== 时是相等的。
这些差异的根源是什么?
我知道在浮点数比较中,最好使用一个小的 epsilon 来检查两个数字是否真的彼此接近,但在这种情况下,比较是为了避免被零除。
代码:
proc geometry_intersect_two_sections {xa1 ya1 xa2 ya2 xb1 yb1 xb2 yb2} {
if {($xa1 == $xa2) && ($xb1 == $xb2)} {
return {}
}
if {!($xa1 == $xa2)} {
set ma [expr (($ya1-$ya2)*1.0)/($xa1-$xa2)]
set na [expr $ya1 - ($ma * 1.0 * $xa1)]
}
if {!($xb1 == $xb2)} {
set mb [expr (($yb1-$yb2)*1.0)/($xb1-$xb2)]
set nb [expr $yb1 - ($mb * 1.0 * $xb1)]
}
if {$xa1 == $xa2} {
set retx [expr $xa1 * 1.0]
set rety [expr $retx * 1.0 * $mb + $nb]
if {($rety <= [max $yb1 $yb2]) && ($rety >= [min $yb1 $yb2]) && ($rety <= [max $ya1 $ya2]) && ($rety >= [min $ya1 $ya2]) && \
($retx <= [max $xb1 $xb2]) && ($retx >= [min $xb1 $xb2]) && ($retx <= [max $xa1 $xa2]) && ($retx >= [min $xa1 $xa2])} {ety]
} else {
return {}
}
}
if {$xb1 == $xb2} {
set retx [expr $xb1 * 1.0]
set rety [expr $retx * 1.0 * $ma + $na]
if {($rety <= [max $yb1 $yb2]) && ($rety >= [min $yb1 $yb2]) && ($rety <= [max $ya1 $ya2]) && ($rety >= [min $ya1 $ya2]) && \
($retx <= [max $xb1 $xb2]) && ($retx >= [min $xb1 $xb2]) && ($retx <= [max $xa1 $xa2]) && ($retx >= [min $xa1 $xa2])} {
return [list $retx $rety]
} else {
return {}
}
}
if {$mb == $ma} {
return {}
}
set retx [expr 1.0 * ($na - $nb)/($mb - $ma)]
set rety [expr 1.0 * ($ma * $retx) + $na]
if {($rety <= [max $yb1 $yb2]) && ($rety >= [min $yb1 $yb2]) && ($rety <= [max $ya1 $ya2]) && ($rety >= [min $ya1 $ya2]) && \
($retx <= [max $xb1 $xb2]) && ($retx >= [min $xb1 $xb2]) && ($retx <= [max $xa1 $xa2]) && ($retx >= [min $xa1 $xa2])} {
return [list $retx $rety]
} else {
return {}
}
【问题讨论】:
-
你确定这两个变量的字面值都是 1.0 吗?是否有可能其中一个的值像 1.0000000001 并且由于四舍五入而打印为 1.0?
-
@BryanOakley,我不知道,当我执行
[set ma]和[puts $ma]时,我得到了1.0,而eq在它们之间确实返回了true。 -
当您使用
eq时,Tcl 会将值转换为字符串,从而丢弃精度。 -
我注意到您在使用
expr时没有在表达式周围加上大括号,这非常慢,因为它每次都强制重新解析表达式(以防万一其中一个论点是1+2+3*4-79或其他)。除非您需要重新解释,否则将表达式放在大括号中并使其快速运行。 (它也更安全,因为它使像[exit]这样的值成为语法错误,而不是结束进程的调用......)
标签: floating-point tcl