JavaScript% (по модулю) дает отрицательный результат для отрицательных чисел - PullRequest
218 голосов
/ 17 декабря 2010

Согласно Google Calculator (-13) % 64 равен 51.

Согласно Javascript (см. JSBin ) это -13.

Как мне это исправить?

Ответы [ 12 ]

227 голосов
/ 17 декабря 2010
Number.prototype.mod = function(n) {
    return ((this%n)+n)%n;
};

Взято из этой статьи: Ошибка по JavaScript JavaScript

132 голосов
/ 26 июня 2013

Использование Number.prototype - МЕДЛЕННО, потому что каждый раз, когда вы используете метод-прототип, ваш номер оборачивается Object. Вместо этого:

Number.prototype.mod = function(n) {
  return ((this % n) + n) % n;
}

Использование:

function mod(n, m) {
  return ((n % m) + m) % m;
}

См .: http://jsperf.com/negative-modulo/2

~ 97% быстрее, чем при использовании прототипа. Если производительность важна для вас, конечно ..

25 голосов
/ 17 декабря 2010

Оператор % в JavaScript - это оператор остатка, а не оператор по модулю (основное отличие заключается в том, как обрабатываются отрицательные числа):

-1 % 8 // -1, not 7

15 голосов
/ 31 октября 2012

Функция "mod" для возврата положительного результата.

var mod = function (n, m) {
    var remain = n % m;
    return Math.floor(remain >= 0 ? remain : remain + m);
};
mod(5,22)   // 5
mod(25,22)  // 3
mod(-1,22)  // 21
mod(-2,22)  // 20
mod(0,22)   // 0
mod(-1,22)  // 21
mod(-21,22) // 1

И конечно же

mod(-13,64) // 51
9 голосов
/ 10 апреля 2013

Принятый ответ заставляет меня немного нервничать, потому что он использует оператор%. Что если Javascript изменит поведение в будущем?

Вот обходной путь, который не использует%:

function mod(a, n) {
    return a - (n * Math.floor(a/n));
}

mod(1,64); // 1
mod(63,64); // 63
mod(64,64); // 0
mod(65,64); // 1
mod(0,64); // 0
mod(-1,64); // 63
mod(-13,64); // 51
mod(-63,64); // 1
mod(-64,64); // 0
mod(-65,64); // 63
8 голосов
/ 09 июня 2018

Операция JavaScript по модулю

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

Компьютеры точнынаучные инструменты, но они работают, манипулируя объектами в дискретных пространствах (у вас есть ограниченное количество пикселей на экране, есть ограниченное количество битов, которые находятся за каждым числом и т. д.)

Попробуйте игнорироватьограничений или спецификаций структуры, и вскоре вы обнаружите, что у вас есть несоответствие импеданса между вашей математической формулой и кодом, который вы пытаетесь написать.

Оператор по модулю

Иногда ситуации осложняютсяложно рекламируемые или понятые каркасные функции или операторы.Эта статья посвящена оператору по модулю.

Спросите любого программиста на C # или JavaScript, что такое оператор по модулю в их языке, и есть большая вероятность, что он ответит:% (например, знак процента).Большое количество документации относится к знаку% как оператору по модулю.

Ух ты!Это тонкая, но очень опасная ошибка.В C # и JavaScript оператор% используется фактически для вычисления остатка (со знаком), оставшегося, когда один операнд делится на второй операнд.Поэтому операнд должен правильно называться оператором остатка со знаком.

На первый взгляд, оператор остатка со знаком работает аналогично оператору по модулю.Давайте проведем несколько тестов, сравнив результаты, возвращаемые JavaScript, с результатами, возвращенными Google.

В Chrome откройте консоль (нажмите F12 и выберите вкладку Консоль).Введите один за другим вычисления из левого столбца.Далее введите те же выражения в строке поиска Google.Обратите внимание на результаты.Они должны быть одинаковыми.

                JavaScript  Google
    5 % 3       2           2
    26 % 26     0           0
    15 % 12     3           3

Давайте теперь попробуем использовать отрицательное значение в качестве первого операнда:

enter image description here

Surprise!

-5% 3 = 1 (в соответствии с Google) -5% 3 = -2 (в соответствии с JavaScript)

Ну ... это не должно быть сюрпризом, если мы посмотрим наопределение оператора% в JavaScript (… или даже в C # или во многих других языках).Google вычисляет истинное значение по модулю, в то время как эти компьютерные языки рассчитывают напоминание со знаком.

Однако не все языки программирования / платформы имеют одинаковую реализацию для%.Например, в Python оператор% вычисляет истинное значение по модулю так же, как Google.

enter image description here

Эта разница в поведении между языками может привести к незначительнымошибки в ваших вычислениях, особенно если вы пытаетесь перенести алгоритм с одного языка на другой!

Понятная проблема - это наполовину решенная проблема

Предположим, нам нужно реализовать (научный)вычисления в JavaScript с использованием арифметики по модулю.

Поскольку теперь мы понимаем, что JavaScript не имеет истинного оператора по модулю, мы можем легко реализовать нашу операцию по модулю как функцию.

Существует несколько способовреализовать по модулю в JavaScript.Я покажу вам 3 способа сделать это.

// Implement modulo by replacing the negative operand 
// with an equivalent positive operand that has the same wrap-around effect
function mod(n, p)
{
    if ( n < 0 )
        n = p - Math.abs(n) % p;

    return n % p;
}

// Implement modulo by relying on the fact that the negative remainder
// is always p numbers away from a positive reminder
// Ex: -5 % 3 | -5 = -2 * 3 + 1 and -5 = -1 * 3 + (-2) | -2 + 3 = 1  
function mod(n, p)
{
    var r = n % p;

    return r < 0 ? r + p : r;
}

// Implement modulo by solving n = v * p + r equation  
function mod(n, p) 
{
    return n - p * Math.floor( n / p );
}

Имея в своем распоряжении более точные инструменты, мы теперь готовы приступить к этим (научным) расчетам и рассчитывать на получение правильных результатов каждый раз.

Примечание. Существует множество вычислений, использующих арифметику по модулю ... Если вы хотите узнать, как использовать эти новые функции по модулю при реализации кода Caesar Cipher / ROT13, вы можете проверить эту статью .

3 голосов
/ 12 мая 2014

Если x является целым числом, а n является степенью 2, вы можете использовать x & (n - 1) вместо x % n.

> -13 & (64 - 1)
51 
3 голосов
/ 17 декабря 2010

Хотя он не ведет себя так, как вы ожидали, это не значит, что JavaScript не «ведет себя».Это выбор JavaScript, сделанный для вычисления по модулю.Потому что по определению любой ответ имеет смысл.

См. это из Википедии.Справа видно, как разные языки выбирали знак результата.

2 голосов
/ 04 апреля 2014

Похоже, что если вы пытаетесь модовать около градусов (то есть, если у вас -50 градусов - 200 градусов), вы захотите использовать что-то вроде:

function modrad(m) {
    return ((((180+m) % 360) + 360) % 360)-180;
}
1 голос
/ 13 мая 2015

Я имею дело с отрицательным и отрицательным n

 //best perf, hard to read
   function modul3(a,n){
        r = a/n | 0 ;
        if(a < 0){ 
            r += n < 0 ? 1 : -1
        }
        return a - n * r 
    }
    // shorter code
    function modul(a,n){
        return  a%n + (a < 0 && Math.abs(n)); 
    }

    //beetween perf and small code
    function modul(a,n){
        return a - n * Math[n > 0 ? 'floor' : 'ceil'](a/n); 
    }
...