Perl数字比较之数字串的理解与调试
Perl numeric comparison of numeric strings understanding and debugging
我有 2 个变量,x、y 和“数字”数据。请注意,这两个都来自不同的来源(mysql 数据和解析的文件数据),所以我首先假设它们最终都是字符串。
## this will work fine with any data that I assign manually, so can't reproduce the issue for you here...
## $x sourced from an sql query, $y sourced from a parsed file
warn "test x == y, $x == $y is " . ($x == $y);
warn "test x != y, $x != $y is " . ($x != $y);
warn "test x eq y, $x eq $y is " . ($x eq $y);
warn "test x ne y, $x ne $y is " . ($x ne $y);
warn "unpack x, " . unpack 'H*', $x;
warn "unpack y, " . unpack 'H*', $y;
输出
test x == y, 14 == 14 is
test x != y, 14 != 14 is 1
test x eq y, 14 eq 14 is 1
test x ne y, 14 ne 14 is
unpack x, 3134
unpack y, 3134
除非我今天头发不好,这是有可能的。前两个测试“看起来”不正确,因为我希望将字符串转换为数字并进行比较。
我可以使用“ne”而不是 != 来绕过它,但我想尝试理解,所以我不会在其他地方引入错误,因为有些问题我不明白。
注意:
如果我事先将 14 或“14”分配给 $y 进行测试,一切都会如我所料。对 $x 做同样的事情没有什么区别,所以我假设 $y 有一些“有趣”的东西。
如果我分配 $y = $y + 0 或类似的值以确保它是一个数字,则没有任何区别。
由于我无法很好地重现该示例,因此我试图了解可能存在的问题,以及如何找出 $y 的“不同”之处或对其进行探究。
编辑:
如果我 Devel::Peek 在 $x (比较后没有改变)
SV = PVNV(0xe2de4c0) at 0x101ccad8
REFCNT = 1
FLAGS = (IOK,NOK,POK,pIOK,pNOK,pPOK)
IV = 14
NV = 14
PV = 0x447ab580 "14"[=12=]
CUR = 2
LEN = 10
如果我 Devel::Peek 在 $y
SV = PVNV(0xcf94880) at 0xf039770
REFCNT = 1
FLAGS = (NOK,pIOK,pNOK)
IV = 14
NV = 14
PV = 0
我也注意到:
warn ($x - $y);
output: -1.77635683940025e-15
这表明 choroba 可能是正确的(尽管为什么 $y 需要对数字比较进行字符串化,我可以看到在调试中添加到字符串时可能会发生这种情况,但在原始字符串中不会)。不过,我对整个事情感到有点惊讶,因为它没有显示浮动,也没有任何简单的方法来判断是否是这种情况。
Edit2:有趣的是,这只发生在测试数据中的数字 14 上,例如数字 12 给出了正确的结果,如果发生了一些舍入,这又可能有意义。我已经通过 $x=int($x + 0.5) 和 $y=int($y + 0.5) 解决了它,因为这实际上是我想要的值。
编辑:ikegamisprintf on $y 产生
14.0000000000000017763568394002504646778106689453125
出于兴趣,我一直追溯到 XML::LibXML::Reader find_value() 调用,其中数字最初是一个 0.14 字符串并相乘,所以我没有这样做的错误在代码中检查一些正确的数据。
不应该 Devel::Peek 在后台将数字显示为 14.0000000000000017763568394002504646778106689453125 吗?
编辑:只是为了那些感兴趣的人,我现在可以通过设置以下内容手动复制它,这会使问题更加明显。
my $x = "0.14";
$x *= 100;
my $y = 14;
my $x = 14.000000000000001;
my $y = 14;
将值字符串化时,Perl 会根据需要对数字进行四舍五入。
另请参阅
What Every Computer Scientist Should Know About Floating-Point Arithmetic
我有 2 个变量,x、y 和“数字”数据。请注意,这两个都来自不同的来源(mysql 数据和解析的文件数据),所以我首先假设它们最终都是字符串。
## this will work fine with any data that I assign manually, so can't reproduce the issue for you here...
## $x sourced from an sql query, $y sourced from a parsed file
warn "test x == y, $x == $y is " . ($x == $y);
warn "test x != y, $x != $y is " . ($x != $y);
warn "test x eq y, $x eq $y is " . ($x eq $y);
warn "test x ne y, $x ne $y is " . ($x ne $y);
warn "unpack x, " . unpack 'H*', $x;
warn "unpack y, " . unpack 'H*', $y;
输出
test x == y, 14 == 14 is
test x != y, 14 != 14 is 1
test x eq y, 14 eq 14 is 1
test x ne y, 14 ne 14 is
unpack x, 3134
unpack y, 3134
除非我今天头发不好,这是有可能的。前两个测试“看起来”不正确,因为我希望将字符串转换为数字并进行比较。
我可以使用“ne”而不是 != 来绕过它,但我想尝试理解,所以我不会在其他地方引入错误,因为有些问题我不明白。
注意: 如果我事先将 14 或“14”分配给 $y 进行测试,一切都会如我所料。对 $x 做同样的事情没有什么区别,所以我假设 $y 有一些“有趣”的东西。 如果我分配 $y = $y + 0 或类似的值以确保它是一个数字,则没有任何区别。
由于我无法很好地重现该示例,因此我试图了解可能存在的问题,以及如何找出 $y 的“不同”之处或对其进行探究。
编辑: 如果我 Devel::Peek 在 $x (比较后没有改变)
SV = PVNV(0xe2de4c0) at 0x101ccad8
REFCNT = 1
FLAGS = (IOK,NOK,POK,pIOK,pNOK,pPOK)
IV = 14
NV = 14
PV = 0x447ab580 "14"[=12=]
CUR = 2
LEN = 10
如果我 Devel::Peek 在 $y
SV = PVNV(0xcf94880) at 0xf039770
REFCNT = 1
FLAGS = (NOK,pIOK,pNOK)
IV = 14
NV = 14
PV = 0
我也注意到:
warn ($x - $y);
output: -1.77635683940025e-15
这表明 choroba 可能是正确的(尽管为什么 $y 需要对数字比较进行字符串化,我可以看到在调试中添加到字符串时可能会发生这种情况,但在原始字符串中不会)。不过,我对整个事情感到有点惊讶,因为它没有显示浮动,也没有任何简单的方法来判断是否是这种情况。
Edit2:有趣的是,这只发生在测试数据中的数字 14 上,例如数字 12 给出了正确的结果,如果发生了一些舍入,这又可能有意义。我已经通过 $x=int($x + 0.5) 和 $y=int($y + 0.5) 解决了它,因为这实际上是我想要的值。
编辑:ikegamisprintf on $y 产生
14.0000000000000017763568394002504646778106689453125
出于兴趣,我一直追溯到 XML::LibXML::Reader find_value() 调用,其中数字最初是一个 0.14 字符串并相乘,所以我没有这样做的错误在代码中检查一些正确的数据。
不应该 Devel::Peek 在后台将数字显示为 14.0000000000000017763568394002504646778106689453125 吗?
编辑:只是为了那些感兴趣的人,我现在可以通过设置以下内容手动复制它,这会使问题更加明显。
my $x = "0.14";
$x *= 100;
my $y = 14;
my $x = 14.000000000000001;
my $y = 14;
将值字符串化时,Perl 会根据需要对数字进行四舍五入。
另请参阅 What Every Computer Scientist Should Know About Floating-Point Arithmetic