JavaScript % (modulo) gives a negative result for negative numbers

JavascriptMathModulo

Javascript Problem Overview


According to Google Calculator (-13) % 64 is 51.

According to Javascript (see this JSBin) it is -13.

How do I fix this?

Javascript Solutions


Solution 1 - Javascript

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

Taken from this article: The JavaScript Modulo Bug

Solution 2 - Javascript

Using Number.prototype is SLOW, because each time you use the prototype method your number is wrapped in an Object. Instead of this:

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

Use:

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

See: http://jsperf.com/negative-modulo/2

~97% faster than using prototype. If performance is of importance to you of course..

Solution 3 - Javascript

The % operator in JavaScript is the remainder operator, not the modulo operator (the main difference being in how negative numbers are treated):

-1 % 8 // -1, not 7

Solution 4 - Javascript

A "mod" function to return a positive result.

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

And of course

mod(-13,64)	// 51

Solution 5 - Javascript

The accepted answer makes me a little nervous because it re-uses the % operator. What if Javascript changes the behavior in the future?

Here is a workaround that does not re-use %:

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

Solution 6 - Javascript

If x is an integer and n is a power of 2, you can use x & (n - 1) instead of x % n.

> -13 & (64 - 1)
51 

Solution 7 - Javascript

Though it isn't behaving as you expected, it doesn't mean that JavaScript is not 'behaving'. It is a choice JavaScript made for its modulo calculation. Because, by definition either answer makes sense.

See this from Wikipedia. You can see on the right how different languages chose the result's sign.

Solution 8 - Javascript

Fix negative modulo (reminder operator %)

Simplified using ES6 Arrow function, and without dangerously extending the Number prototype

const mod = (n, m) => (n % m + m) % m;

console.log(mod(-90, 360));    //  270  (Instead of -90)

Solution 9 - Javascript

This is not a bug, there's 3 functions to calculate modulo, you can use the one which fit your needs (I would recommend to use Euclidean function)

Truncating the decimal part function

console.log(  41 %  7 ); //  6
console.log( -41 %  7 ); // -6
console.log( -41 % -7 ); // -6
console.log(  41 % -7 ); //  6

Integer part function

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

console.log( parseInt( 41).mod( 7) ); //  6
console.log( parseInt(-41).mod( 7) ); //  1
console.log( parseInt(-41).mod(-7) ); // -6
console.log( parseInt( 41).mod(-7) ); // -1

Euclidean function

Number.prototype.mod = function(n) {
	var m = ((this%n)+n)%n;
	return m < 0 ? m + Math.abs(n) : m;
};

console.log( parseInt( 41).mod( 7) ); // 6
console.log( parseInt(-41).mod( 7) ); // 1
console.log( parseInt(-41).mod(-7) ); // 1
console.log( parseInt( 41).mod(-7) ); // 6

Solution 10 - Javascript

So it seems that if you're trying to mod around degrees (so that if you have -50 degrees - 200 degrees), you'd want to use something like:

function modrad(m) {
    return ((((180+m) % 360) + 360) % 360)-180;
}

Solution 11 - Javascript

I deal with négative a and negative n too

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

Solution 12 - Javascript

There is a NPM package that will do the work for you. You can install it with the following command.

npm install just-modulo --save

Usage copied from the README

import modulo from 'just-modulo';

modulo(7, 5); // 2
modulo(17, 23); // 17
modulo(16.2, 3.8); // 17
modulo(5.8, 3.4); //2.4
modulo(4, 0); // 4
modulo(-7, 5); // 3
modulo(-2, 15); // 13
modulo(-5.8, 3.4); // 1
modulo(12, -1); // NaN
modulo(-3, -8); // NaN
modulo(12, 'apple'); // NaN
modulo('bee', 9); // NaN
modulo(null, undefined); // NaN

GitHub repository can be found via the following link:

https://github.com/angus-c/just/tree/master/packages/number-modulo

Solution 13 - Javascript

For fun, here's a "wrap" function that works sorta like a modulo, except you can also specify the minimum value of the range (instead of it being 0):

const wrap = (value = 0, min = 0, max = 10) =>
  ((((value - min) % (max - min)) + (max - min)) % (max - min)) + min;

Basically just takes the true modulo formula, offsets it such that min ends up at 0, then adds min back in after.

Useful if you have a value that you want to keep between two values.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlec GorgeView Question on Stackoverflow
Solution 1 - JavascriptEnriqueView Answer on Stackoverflow
Solution 2 - JavascriptStuRView Answer on Stackoverflow
Solution 3 - JavascriptRob SobersView Answer on Stackoverflow
Solution 4 - JavascriptShanimalView Answer on Stackoverflow
Solution 5 - JavascriptwisbuckyView Answer on Stackoverflow
Solution 6 - JavascriptquasimodoView Answer on Stackoverflow
Solution 7 - JavascriptdheerosaurView Answer on Stackoverflow
Solution 8 - JavascriptRoko C. BuljanView Answer on Stackoverflow
Solution 9 - JavascriptzessxView Answer on Stackoverflow
Solution 10 - JavascriptJayCrosslerView Answer on Stackoverflow
Solution 11 - JavascriptbormatView Answer on Stackoverflow
Solution 12 - JavascriptmaartenpaauwView Answer on Stackoverflow
Solution 13 - JavascriptV. RubinettiView Answer on Stackoverflow