Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl: understanding modulo operation on negative numbers (e.g. -10%3)

Tags:

perl

I'm learning Perl (5.14) and I'm a bit stuck on modulo with negative numbers. As an example, let's take a look at variations on 10%3.

To begin,

perl -le 'print -10%-3'

yields -1, as expected.

But,

perl -le 'print -10%3'

yields 2.

And,

perl -le 'print 10%-3'

yields -2.

I do not understand the last two results. I would expect only 1 or -1 as a result for any variation on 10%3. Why should 2, either positive or negative, be returned as a result?


1 Answers

You found a perl5 specification bug/feature that will very likely never be fixed. This modulo vs i_modulo bug is even documented as such, with a weird definition of modulo, which deviates from the mathematical definition and the implementation in libc, the Standard C library.

The documentation in http://perldoc.perl.org/perlop.html#Multiplicative-Operators describes only one case, not the second. And forgets to tell the whole story.

"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)."

Thus -13 % 4 is unspecified, 13 % -4 is described as returning -3, not 1. In reality -13 % 4 returns 3 not -1.

This perl5 behavior is only weird without use integer. With use integer you get proper and fast libc behavior.

   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)
   }

Note that with both arguments being literal integer constants, the result is constant folded at compile-time. But even with both arguments clearly being integer types, the constant folder uses the generic modulo operator, not the specific i_modulo operator, which is used under use integer. Or with a typed perl extension with both args being integers at compile-time.

This bug was even promoted to perl6, defined in parrot and moar as in perl5. I'm not sure if the jvm backend also uses a hack to use the weird perl5 definition.

like image 77
rurban Avatar answered Oct 31 '25 15:10

rurban



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!