2013-12-19 2 views
2

Я изучаю Perl (5.14), и я немного застрял в модуле с отрицательными числами. В качестве примера давайте посмотрим на варианты на 10% 3.Perl: понимание работы модуля на отрицательных числах (например, -10% 3)

Для начала

perl -le 'print -10%-3' 

дает -1, как и ожидалось.

Но

perl -le 'print -10%3' 

дает 2.

И

perl -le 'print 10%-3' 

дает -2.

Я не понимаю последние два результата. Я ожидал бы только 1 или -1 в результате при любом изменении на 10% 3. Почему в результате должно быть возвращено 2, положительное или отрицательное?

+0

См. Также: [Почему модуль отличается от разных языков программирования?] (Http://stackoverflow.com/questions/450410/why-is-modulus-different-in-different-programming-languages) и [ поведение% с отрицательными операндами, определенными в Perl 5?] (http://stackoverflow.com/questions/3610687/is-the-behavior-of-with-negative-operands-defined-in-perl-5) –

ответ

0

Вы обнаружили ошибку/особенность спецификации perl5, которая, скорее всего, никогда не будет исправлена. Эта ошибка modulo vs i_modulo даже задокументирована как таковая со странным определением 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.

Это поведение perl5 только странно без use integer. С 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) 
    } 

Обратите внимание, что с оба аргумента быть литеральные целые константы, то результат будет постоянным сложена во время компиляции. Но даже если оба аргумента явно являются целыми типами, постоянная папка использует общий оператор modulo, а не конкретный оператор i_modulo, который используется под целым числом use. Или с типизированным расширением perl, причем оба args являются целыми числами во время компиляции.

Эта ошибка была даже повышена до perl6, определенной в попугаи и moar, как в perl5. Я не уверен, что бэкэнд jvm также использует взломы, чтобы использовать странное определение perl5.

+0

Спасибо. Принудительное поведение libc с помощью «use integer» определенно кажется наиболее разумным способом работы с модулем в Perl. – John

3

Perl обычно использует арифметический оператор modulo, который не зависит от машины.

Это взято из Perl Documentation: Multiplicative Operators

Binary % является оператором по модулю, который вычисляет остаток от деления первого аргумента относительно второго аргумента.

Учитывая целочисленные операнды $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 в уравнении ($r = $a - $i*$b), где $i представляет собой некоторое целое число, что делает $r имеет тот же знак, правый операнд $b (не как левый операнд $a, как функция C fmod()), а абсолютное значение меньше, чем значение $b.

Обратите внимание, что когда use integer находится в области видимости, % дает прямой доступ к модулю оператору, реализованный вашему компилятор.Этот оператор не так определен для отрицательных операндов, но он будет выполняться быстрее.

+0

Это неинтуитивное определение для меня, но оно объясняет наблюдаемое поведение. Интересно, определяет ли многие другие языки по модулю одинаково. – John

+0

Утверждение о том, что реализация libc для одного отрицательного целочисленного аргумента «недостаточно четко определена» является весёлой. libc определяет оба состояния с отрицательными целыми аргументами. отрицательный% положительный и положительный% отрицательный, и соответствует его результатам. Знак влияет только на знак, а не на номер. Это не зависит от машины. В то время как perl5 определяет только второй случай, а не первый, и изменяет результаты, чтобы отклоняться от libc и собственного целого целого. – rurban

Смежные вопросы