我正在学习Perl(5.14),我有点拘泥于负数的模运算。作为一个例子,让我们来看看10%3的变化。
首先,
perl -le 'print -10%-3'
如预期的那样产生-1
。
但是,
perl -le 'print -10%3'
得到CCD_ 2。
而且,
perl -le 'print 10%-3'
得到CCD_ 3。
我不理解最后两个结果。对于10%3的任何变化,我预计结果只有1或-1。为什么结果应该返回2,无论是正的还是负的?
您发现了一个perl5规范错误/功能,很可能永远无法修复。这个modulo vs i_modulo的错误甚至被记录为这样,对modulo有一个奇怪的定义,它偏离了数学定义和标准C库libc中的实现。
中的文档http://perldoc.perl.org/perlop.html#Multiplicative-运算符只描述一种情况,而不是第二种情况。忘了讲述整个故事。
"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。
如果没有use integer
,这种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)
}
注意,由于两个参数都是文字整数常量,结果在编译时是常量折叠的。但是,即使这两个参数显然都是整数类型,常量文件夹也使用通用的模运算符,而不是在use integer下使用的特定i_modulo运算符。或者使用类型化的perl扩展,两个参数在编译时都是整数。
这个bug甚至被提升到了第16个版本,在第15个版本中被定义为鹦鹉和魔。我不确定jvm后端是否也使用了破解来使用奇怪的perl5定义。
这摘自Perl文档:乘法运算符
二进制%
是模运算符,它计算第一个自变量相对于第二个自变量的除法余数。
给定整数操作数$a
和$b
:
- 如果
$b
为正,则$a % $b
为$a
减去小于或等于$a
的$b
的最大倍数 - 如果
$b
为负,则$a % $b
为$a
减去$b
的最小倍数,该倍数不小于$a
(即,结果将小于或等于零) - 如果操作数
$a
和2
0是浮点值,并且$b
(即abs($b)
)的绝对值小于(UV_MAX + 1)
,则操作中将仅使用$a
和$b
的整数部分(注意:此处UV_MAX
表示无符号整数类型的最大值) - 如果右操作数(
abs($b)
)的绝对值大于或等于(UV_MAX + 1)
,则%
计算等式(-2
1)中的浮点余数$r
,其中$i
是使$r
具有与右操作数$b
相同的符号(而不是像C函数fmod()
那样与左操作数$a
相同)并且绝对值小于$b
的符号的特定整数
请注意,当use integer
在作用域中时,%
允许您直接访问由C编译器实现的模运算符。这个运算符并没有很好地定义为负操作数,但它会执行得更快。