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