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

Perl:理解负数的模运算(例如-10%3),perl,Perl,我正在学习Perl(5.14),我对负数模有点迷恋。作为一个例子,让我们看看10% 3的变化。 首先, perl -le 'print -10%-3' 按预期产生-1 但是, 产生2 以及 产生-2 我不明白最后两个结果。对于10%3的任何变化,我预计结果只有1或-1。为什么结果应该返回正数或负数的2?Perl通常使用独立于机器的算术模运算符 这是从 二进制%是模运算符,它计算第一个参数相对于第二个参数的除法余数 给定整数操作数$a和$b: 如果$b为正,则$a%$b为$a减去$b小于或等于

我正在学习Perl(5.14),我对负数模有点迷恋。作为一个例子,让我们看看10% 3的变化。 首先,

perl -le 'print -10%-3'
按预期产生
-1

但是,

产生
2

以及

产生
-2


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

Perl通常使用独立于机器的算术模运算符

这是从

二进制
%
是模运算符,它计算第一个参数相对于第二个参数的除法余数

给定整数操作数
$a
$b

  • 如果
    $b
    为正,则
    $a%$b
    $a
    减去
    $b
    小于或等于
    $a
    的最大倍数
  • 如果
    $b
    为负值,则
    $a%$b
    $a
    减去
    $b
    中不小于
    $a
    的最小倍数(即,结果将小于或等于零)
  • 如果操作数
    $a
    $b
    是浮点值,并且
    $b
    (即
    abs($b)
    )的绝对值小于
    (UV_MAX+1)
    ,则操作中将只使用
    $a
    $b
    的整数部分(注意:此处
    UV_MAX
    表示无符号整数类型的最大值)
  • 如果右操作数(
    abs($b)
    )的绝对值大于或等于
    (UV_MAX+1)
    %
    计算等式(
    $r=$a-$i*$b
    )中的浮点余数其中,
    $i
    是一个特定的整数,它使
    $r
    与右操作数
    $b
    具有相同的符号(与左操作数
    $a
    类似于C函数
    fmod()
    ),且绝对值小于
    $b

请注意,
use integer
在作用域中时,
%
允许您直接访问由C编译器实现的模运算符。此运算符对于负操作数的定义不太好,但执行速度更快。

您发现了perl5规范的错误/功能,很可能永远无法修复。 这个模与i_模的错误甚至被记录为模的奇怪定义,这与数学定义和libc(标准C库)中的实现不同

中的文档只描述了一个案例,而不是第二个。并且忘记了讲述整个故事

"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)."
因此-13%4未指定,13%4被描述为返回-3,而不是1。 实际上-13%4返回3而不是-1

这种perl5行为只有在没有
使用整数的情况下才会奇怪。
使用
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)
   }
请注意,如果两个参数都是文字整型常量,则结果在编译时是常量折叠的。但是,即使两个参数显然都是整数类型,常量文件夹也使用通用的模运算符,而不是特定的i_模运算符,该运算符在use integer下使用。或者使用类型化的perl扩展,两个参数都是int编译时的EGER


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

这对我来说是一个不直观的定义,但它确实解释了观察到的行为。我想知道是否有许多其他语言以同样的方式定义模。我认为libc实现一个负整数参数的on为“未定义良好”很搞笑。libc使用负整数参数定义两种状态。负%正和正%负,并与其结果一致。符号只影响符号,而不影响数字。这是机器独立的。而perl5仅定义第二种情况,而不是第一种情况,并将结果更改为偏离libc及其结果n使用整数的情况。你们都是对的……在Perl5试图仍然支持的C89中,带负参数的除法和模都依赖于实现。libc提供了一致的截断div函数(使用整数是否使用它?)。C99修复了这个问题(谢天谢地)对于标准运算符,and定义为截断除法/模。Perl5似乎返回地板模,但int(a/b)正在截断,这使得大多数用户不一致。Raku(Perl6)对div和mod使用地板除法,这是一致的。另请参见:and
"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)."
   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)
   }