Perl:理解对负数的模运算(例如 -10%3)

3 perl

我正在学习 Perl (5.14) 并且我有点坚持使用负数取模。例如,让我们看一下 10%3 的变体。

开始,

perl -le 'print -10%-3'
Run Code Online (Sandbox Code Playgroud)

产量-1,正如预期的那样。

但,

perl -le 'print -10%3'
Run Code Online (Sandbox Code Playgroud)

产量2

和,

perl -le 'print 10%-3'
Run Code Online (Sandbox Code Playgroud)

产量-2

我不明白最后两个结果。对于 10%3 的任何变化,我预计只有 1 或 -1。为什么结果应该返回 2,无论是正数还是负数?

rur*_*ban 5

您发现了一个很可能永远不会修复的 perl5 规范错误/功能。这个 modulo vs i_modulo 错误甚至被记录为这样,模的奇怪定义偏离了标准 C 库 libc 中的数学定义和实现。

http://perldoc.perl.org/perlop.html#Multiplicative-Operators中的文档只描述了一种情况,而不是第二种情况。并且忘记讲述整个故事。

"If $b is negative, then $a % $b is $a minus the smallest multiple of $b
that is not less than $a (that is, the result will be less than or
equal to zero)."
Run Code Online (Sandbox Code Playgroud)

因此 -13 % 4 是未指定的,13 % -4 被描述为返回 -3,而不是 1。实际上 -13 % 4 返回 3 而不是 -1。

这种 perl5 行为只是在没有use integer. 随着use integer你获得正确和快速的 libc 行为。

   use integer;
   print -13 % 4;  # => -1
   print  13 % -4; # => 1
   print -13 % -4; # => -1 (same with or without use integer)
   print  13 % 4;  # => 1 (same with or without use integer)

   { 
     no integer;
     print -13 % 4;  # => 3 (different to libc)
     print  13 % -4; # => -3 (different to libc)
     print -13 % -4; # => -1 (same with or without use integer)
     print  13 % 4;  # => 1 (same with or without use integer)
   }
Run Code Online (Sandbox Code Playgroud)

请注意,由于两个参数都是文字整数常量,因此结果是在编译时折叠的常量。但即使这两个参数显然都是整数类型,常量文件夹使用通用模运算符,而不是特定的 i_modulo 运算符,它在使用整数下使用。或者使用类型化的 perl 扩展,在编译时两个 args 都是整数。

这个 bug 甚至被提升到 perl6,在 parrot 和 moar 中定义为 perl5。我不确定 jvm 后端是否也使用 hack 来使用奇怪的 perl5 定义。