gpt4 book ai didi

floating-point - 为什么使用==时tcl中的1.0不等于1.0

转载 作者:行者123 更新时间:2023-12-04 22:22:39 26 4
gpt4 key购买 nike

在下面的代码中,我遇到了一个奇怪的现象。在 if {$ma == $mb} 线上运行时, mbma 都等于 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 {}
}

最佳答案

众所周知,IEEE 浮点值(Tcl 在内部使用,因为它们受您的 CPU 硬件支持)具有它们不完全表示值的特性。无论如何都是一个近似值;它们确实准确地表示值,因为它们具有固定的位数(double 为 64,这是 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}]
}

然后你会像这样使用它:
# Instead of: if {$x == 42.3} { ... }
if {[equal_float $x 42.3]} { ... }

请注意,这样做的另一个后果是您永远不应将浮点数用于迭代目的,因为这会导致错误累积并超过 epsilon。不是以 0.1 的步长从 0 到 25,而是以整数步长从 0 到 250,然后通过乘以 0.1 得出浮点值。

关于floating-point - 为什么使用==时tcl中的1.0不等于1.0,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12693890/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com