Perl:理解负数的模运算(例如-10%3)
我正在学习Perl(5.14),我对负数模有点迷恋。作为一个例子,让我们看看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 -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
类似于C函数$a
),且绝对值小于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)
}