2017-01-20 2 views
5

При наивности использования мод команды в Баше остаточный получает неправильный знак (на моем взгляде) для отрицательного числителя:Как получить положительный знак результата из мод в Баше

Если я пишу:

for i in {-5..5}; do echo $(($i % 3)) ; done 

я получаю выход (как строки)

-2 -1 0 -2 -1 0 1 2 0 1 2 

Как я добиться "правильного" поведения

1 2 0 1 2 0 1 2 0 1 2 
+2

Связанный: [modulo оператор с отрицательным операндом, ошибкой или функцией?] (Http://www.unix.com/shell-programming-and-scripting/260045-newbie-question-modulo-operator-negative-operand- bug-feature.html) – fedorqui

ответ

3

Add 3, а затем Mod 3 к первому набору результатов:

$ for i in {-5..5}; do printf "%d " $(((($i % 3) + 3) % 3)) ; done 
1 2 0 1 2 0 1 2 0 1 2 

Если вы знаете максимальный диапазон, вы можете просто добавить достаточно значительно большую кратна 3, чтобы все числа положительны перед первой операцией по модулю ,

$ for i in {-5..5}; do printf "%d " $((($i + 3000000) % 3)) ; done 

Однако первый подход является более чистым и универсальным.

Наконец, для удовольствия:

positive_mod() { 
    local dividend=$1 
    local divisor=$2 
    printf "%d" $(((($dividend % $divisor) + $divisor) % $divisor)) 
} 

for i in {-5..5}; do 
    printf "%d " $(positive_mod $i 3) 
done 
+1

В общем, вы можете добавить 3 к числителю, пока результат не будет положительным, * затем * разделите на 3. '(j + k * 3)% 3 == j% 3' для всех' k '. – chepner

+1

@chepner: Вы можете это сделать, но вы никогда не сможете точно знать, насколько велика 'k'. Если вы выполняете всю операцию после первого модуля, то мы знаем, что 'k = 1'. – Harvey

+0

А, правильно, я неправильно понял, что вы делали. – chepner

2

По wikipedia негативных признаков допускается.

[Результат a mod n] это по-прежнему оставляет неопределенность знака, если остаток равен нулю: два возможных варианта для остатка происходит, один отрицательный, а другой положительный, и два возможных варианта для частного возникновения. Обычно в теории чисел положительный остаток всегда выбирается, но языки программирования выбираются в зависимости от языка и знаков a или n.

Таким образом, это зависит от языка программирования. Поскольку bash, очевидно, ушел за «отрицательный остаток», который вы могли бы избежать, например, Perl, как это:

for i in {-5..5}; do perl -le "print $i%3"; done 

Это происходит за счет запуска интерпретатора Perl индивидуально для каждого целого числа.

Действительно! Поскольку OP, похоже, заботится о правильной математике, вы можете подумать о переходе на что-то вроде python и сделать цикл и все там.

+1

Это за счет запуска Perl-интерпретатора по отдельности для каждого целого. Он работает, но я думаю, что немного более длительное решение, избегающее Perl, стоит производительности и избегает внешней зависимости. – Fred

+0

Когда я говорю неправильно, я беру взгляд на теорию чисел. –

+0

@Fred: хорошая точка, я добавил это к ответу – hansaplast

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