SIM*_*MEL 4 floating-point tcl
在下面的代码中,我遇到了一个奇怪的现象.在上线的运行if {$ma == $mb}都mb和ma都相等1.0,但如果不采取.当我改变了==to eq或者[cequal $ma $mb]if的时候.
此外,当我尝试用1.0(if {$ma == 1.0}和if {$1.0 == $mb})更改其中一个变量时,if也没有被采用,但是采用表达式的if if {1.0 ==1.0}.
发生在我身上改变后的另一件事==到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 {}
}
Run Code Online (Sandbox Code Playgroud)
IEEE浮点值(Tcl在内部使用,因为它们由CPU硬件支持)众所周知,它们具有的功能并不完全代表值.至少是第一个近似值; 它们确实代表了值,因为它们具有固定的位数(64位double,这是Tcl使用的),但它们所代表的值可能与您的想法略有不同(因为许多值无法在固定数目的二进制数位,正如1/3是几乎但不完全0.333333333在小数;它的确切相同的问题,但在另一个号码碱).
为了显示目的,Tcl采取了一些有限的步骤来解决这个问题; 从8.5开始,它将浮点数用于获得精确值所需的最小位数,并且在8.4和之前它只是在打印数字时使用较少的位数(最多15位十进制数而不是17位)这是精确表示所必需的,可通过魔术tcl_precision变量控制.不要设置那个变量; 它不能满足您的需要,因为它只是将值呈现给字符串,而不是值本身.相反,您需要使用不同的(并且非常熟知的)策略来实现相等:等于epsilon.
# Magic value! This one is OK for values in the range of small integers
proc equal_float {a b {epsilon 1e-15}} {
return [expr {abs($a - $b) < $epsilon}]
}
Run Code Online (Sandbox Code Playgroud)
然后你会像这样使用它:
# Instead of: if {$x == 42.3} { ... }
if {[equal_float $x 42.3]} { ... }
Run Code Online (Sandbox Code Playgroud)
请注意,这是另一个结果是您不应该使用浮点数进行迭代,因为这样可以使错误累积并超过epsilon.而不是以0.1为步长从0到25,以整数步长从0到250,然后乘以0.1得到浮点值.
| 归档时间: |
|
| 查看次数: |
1464 次 |
| 最近记录: |