我正在学习Perl(5.14)并且我有点卡在模数上,带有负数。举个例子,让我们来看看10%3的变化。
首先,
perl -le 'print -10%-3'
按预期收取-1
。
但是,
perl -le 'print -10%3'
收益2
。
和
perl -le 'print 10%-3'
收益-2
。
我不明白最后两个结果。我认为10%3的任何变化都只有1或-1。结果为什么要返回2,无论是正面还是负面?
答案 0 :(得分:3)
Perl通常使用与机器无关的算术模运算符。
这取自Perl Documentation: Multiplicative Operators
二进制%
是模运算符,它根据第二个参数计算第一个参数的除法余数。
给定整数操作数$a
和$b
:
$b
为正数,则$a % $b
为$a
减去$b
的最大倍数小于或等于$a
。 $b
为否定,则$a % $b
为$a
减去不小于$b
的{{1}}的最小倍数(即结果将小于或等于零)。 $a
和$a
是浮点值且$b
(即$b
)的绝对值小于abs($b)
,则仅(UV_MAX + 1)
和$a
的整数部分将在操作中使用(注意:此处$b
表示无符号整数类型的最大值)。 UV_MAX
)的绝对值大于或等于abs($b)
,(UV_MAX + 1)
计算等式中的浮点余数%
( $r
)其中$r = $a - $i*$b
是某个整数,使$i
具有与右操作数$r
相同的符号(而不是像C函数那样的左操作数$b
$a
)并且绝对值小于fmod()
的绝对值。 请注意,当$b
在范围内时,use integer
可让您直接访问由C编译器实现的模运算符。这个运算符没有为负操作数定义,但它会更快地执行。
答案 1 :(得分:1)
您发现了很可能永远不会修复的perl5规范错误/功能。 这个modulo vs i_modulo bug甚至被记录在案,其中有一个奇怪的modulo定义,它偏离了数学定义和libc(标准C库)中的实现。
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)."
因此未指定-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)
}
请注意,两个参数都是文字整数常量,结果在编译时是常量折叠。但即使两个参数显然都是整数类型,常量文件夹也使用通用模运算符,而不是使用整数下使用的特定i_modulo运算符。或者使用类型化的perl扩展,在编译时两个args都是整数。
这个bug甚至被提升为perl6,在perl5中以parrot和moar定义。我不确定jvm后端是否也使用hack来使用奇怪的perl5定义。