JavaScript % (모듈로)는 음수에 대해 음수 결과를 제공합니다.


252

구글 계산기 에 따르면 (-13) % 64입니다 51.

자바 스크립트에 따르면 (이 참조 JSBin을 그것이) -13.

이 문제를 어떻게 해결합니까?


이것은 우선 순위 문제 일 수 있습니다. 당신은 의미합니까 (-13) % 64-(13 % 64)? 개인적으로, 나는 단지 명확성을 위해 두 가지 방법으로 parens를 넣었습니다.
MatrixFrog

2
기본적으로 자바는 음수로 모듈러스 계산어떻게 수행합니까? 비록 이것이 자바 스크립트 질문이지만.
James K. Polk 대통령

85
자바 스크립트는 때때로 아주 잔인한 농담 같은 느낌
dukeofgaming

6
구글은 틀릴 수 없다
caub

10
JS의 근본적인 문제는 %모듈로 연산자가 아닙니다. 나머지 연산자입니다. JavaScript에는 모듈러스 연산자가 없습니다. 그래서 받아 들여진 대답은 갈 길입니다.
Redu

답변:


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

이 기사에서 가져온 : JavaScript Modulo Bug


23
나는 그것을 "버그"라고 부를 것입니다. 모듈로 연산은 음수에 대해 잘 정의되어 있지 않으며 컴퓨팅 환경에 따라 다르게 처리됩니다. 모듈로 연산 에 관한 Wikipedia의 기사 는 그것을 잘 다루고 있습니다.
Daniel Pryden

22
그것은 종종 '모듈로'라고 불리기 때문에 바보처럼 보일 수 있는데, 수학 정의와 동일하게 행동 할 것임을 암시합니다 (ℤ / nℤ 대수 참조).
etienne

7
왜 n을 추가하기 전에 모듈로를 사용합니까? 왜 n을 더한 다음 모듈로를 사용하지 않겠습니까?
22:34에

12
@starwed이 % n을 사용하지 않으면 실패합니다 ( x < -n예 : (-7 + 5) % 5 === -2하지만) ((-7 % 5) + 5) % 5 == 3.
fadedbee

7
이 함수에 액세스하려면 -13 % 10 대신 (-13) .mod (10) 형식을 사용해야한다는 답을 추가하는 것이 좋습니다. 더 명확합니다.
Jp_

161

Number.prototype프로토 타입 방법을 사용할 때마다 숫자가로 래핑되므로 Using 는 SLOW 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 % 빠릅니다. 물론 성능이 중요하다면 ..


1
좋은 팁. 나는 당신의 jsperf를 가져 와서이 질문의 나머지 솔루션과 비교했습니다 (그러나 이것이 최선의 방법 인 것 같습니다) : jsperf.com/negative-modulo/3
Mariano Desanze

11
미세 최적화. 당신은 일을 할 거라고 엄청난 차이를 전혀를 만들이위한 모드 계산의 양을. 가장 명확하고 유지 보수가 쉬운 것을 코딩 한 후 다음 성능 분석을 최적화하십시오.
ChrisV

난 당신이있어 생각 n들과 m두 번째 예 @StuR에서 잘못된 방향으로 약이야. 이어야합니다 return ((n % m) + m) % m;.
vimist

이것은 답변 자체가 아니라 승인 된 답변에 대한 의견이어야합니다.
xehpuk

5
이 답변에 언급 된 동기는 마이크로 최적화이지만, 프로토 타입을 수정하는 것은 문제가 있습니다. 부작용이 가장 적은 접근법을 선호하십시오.
Keen

30

%JavaScript 의 연산자는 모듈로 연산자가 아닌 나머지 연산자입니다 (주요 차이점은 음수가 처리되는 방식에 있음).

-1 % 8 // -1, not 7


8
그것은 해야 나머지 연산자를 호출 할 수 있지만 됩니다 계수 운영자라고 : developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/...
빅 McLargeHuge

15
@DaveKennedy : MDN은 공식 언어 참조가 아니며 커뮤니티 편집 사이트로 가끔 잘못되기도합니다. 스펙 은 그것을 모듈로 연산자라고 부르지 않으며, 내가 알 수없는 한 (ES3으로 돌아갔습니다). 그것은 연산자가 암시적인 나눗셈의 나머지 부분을 산출하고 단지 "% 연산자"라고 부릅니다.
TJ Crowder

2
이 호출 remainder되면 정의에 따라 0보다 커야합니다. 고등학교 의 분할 정리 를 기억할 수 없습니까 ?! 그래서 어쩌면 당신은 여기에 모습을 가질 수 있습니다 en.wikipedia.org/wiki/Euclidean_division
아마드

19

긍정적 인 결과를 반환하는 "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

1
MDN은 공식적인 언어 참조가 아니며 커뮤니티 편집 사이트로서 때때로 잘못되기도합니다. 스펙 은 그것을 모듈로 연산자라고 부르지 않으며, 내가 알 수없는 한 (ES3으로 돌아갔습니다). 그것은 연산자가 암시적인 나눗셈의 나머지 부분을 산출하고 단지 "% 연산자"라고 부릅니다.
TJ Crowder

1
죄송합니다. 지정한 링크는 실제로 #sec-applying-the-mod-operatorURL에서 바로 참조 합니다 :) 어쨌든, 메모 주셔서 감사합니다. 내 대답에서 보풀을 가져갔습니다. 어쨌든 중요하지 않습니다.
Shanimal

3
@ Shanimal : LOL! 그렇습니다. HTML 편집기에서 오류가 발생했습니다. 사양 텍스트는 그렇지 않습니다.
TJ Crowder

10

허용 된 답변은 % 연산자를 재사용하기 때문에 약간 긴장합니다. 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
자바 스크립트가 수학 정의와 일치하도록 모듈로 연산자를 변경 한 경우에도 허용 된 답변이 계속 작동합니다.
22

20
"자바 스크립트가 미래에 행동을 바꾸면 어떨까요?" 왜 그럴까요? 그러한 기본 운영자의 행동을 바꿀 가능성은 없습니다.
nnnnnn

1
추천 답변 # answer-4467559에 대한이 관심사 및 대안을 공유하여 +1 및 4 가지 이유 : (1) 그 이유, 예 그것을 찾을 필요조차 없습니다. (2) 부서진 하나의 관점에서 작업 op를 정의하는 것은 인상적이지만 적어도 첫 번째 모습에서 걱정 스럽습니다. 한눈에. (4) 작은 : 2 (mod) div 대신 1 div + 1 mul을 사용하고 좋은 FPU가없는 이전 하드웨어에서 들었습니다. 곱셈이 더 빠릅니다.
Destiny Architect

2
@DestinyArchitect 그것은 신중하지 않다, 그것은 무의미하다. 나머지 연산자의 동작을 변경하려는 경우이를 사용하여 다양한 프로그램을 중단 할 수 있습니다. 결코 일어나지 않을 것입니다.
Aegis

9
무엇의 행동 경우 -, *, /, ;, ., (, ), ,, Math.floor, function또는 return변경? 그런 다음 코드가 끔찍하게 손상되었습니다.
xehpuk

5

예상대로 동작하지 않지만 JavaScript가 '동작'이 아님을 의미하지는 않습니다. 모듈로 계산을 위해 만들어진 JavaScript입니다. 정의에 따라 두 가지 대답 모두 의미가 있기 때문입니다.

Wikipedia에서 이것을 보십시오 . 다양한 언어가 결과 표시를 어떻게 선택했는지 오른쪽에서 볼 수 있습니다.


3

경우 x정수이며 n2의 힘, 당신은 사용할 수 있습니다 x & (n - 1)대신 x % n.

> -13 & (64 - 1)
51 

2

따라서 정도를 조정하려고하면 (-50도-200 도인 경우) 다음과 같은 것을 사용하고 싶은 것 같습니다.

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

1

나는 음수 a와 음수 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); 
    }

1

이것은 버그가 아니며 모듈로를 계산하는 3 가지 함수가 있습니다. 필요에 맞는 것을 사용할 수 있습니다 (유클리드 함수를 사용하는 것이 좋습니다)

소수 부분 함수 잘라 내기

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

정수 부분 함수

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

유클리드 기능

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

1
유클리드 함수에서 m <0은 ((this % n) + n) % n이 항상 양수이기 때문에 쓸모가 없습니다.
bormat

@bormat 예, 그렇습니다. 그러나 자바 스크립트 %에서는 부정적인 결과를 반환 할 수 있습니다 (이것은 이러한 함수의 목적이며이를 수정하는 것입니다)
zessx

이 코드를 작성했습니다. Number.prototype.mod = function (n) {var m = ((this % n) + n) % n; 반환 m <0? m + Math.abs (n) : m; }; [/ code]는 m이 음수 인 n의 값 하나를 제공합니다. 첫 번째 % 뒤에 n을 추가하므로 m은 음수 인 n의 값이 아닙니다.
bormat

이 확인이 없으면 대신에 parseInt(-41).mod(-7)반환 -6됩니다 1(그리고 이것은 내가 작성한 정수 부분 함수의 목적입니다)
zessx

하 괜찮아, 네가 옳아, 모든 사과, 네거티브 모듈로를 잊어 버렸어, "이것"네거티브에 대해서만 생각하고 있었어. Math.abs Number.prototype.mod = function (n) {return ((this % n) + Math.abs (n)) % n; }; (-41) .MOD (-7) == 1 // 필요가 없습니다에서는 parseInt
bormat

0

당신을 위해 일할 NPM 패키지가 있습니다. 다음 명령으로 설치할 수 있습니다.

npm install just-modulo --save

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 리포지토리는 다음 링크를 통해 찾을 수 있습니다.

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.