자바 스크립트의 Number.sign ()


101

숫자 부호 ( signum 함수 ) 를 찾는 사소한 방법이 있는지 궁금 하십니까?
명백한 것보다 짧거나 빠르거나 우아한 솔루션 일 수 있습니다.

var sign = number > 0 ? 1 : number < 0 ? -1 : 0;

짧은 답변!

이것을 사용하면 안전하고 빠를 것입니다 (출처 : moz )

if (!Math.sign) Math.sign = function(x) { return ((x > 0) - (x < 0)) || +x; };

성능 및 유형 강제 비교 바이올린 을보고 싶을 수 있습니다.

오랜 시간이 지났습니다. 또한 주로 역사적 이유 때문입니다.


결과

지금은 다음과 같은 솔루션이 있습니다.


1. 명확하고 빠름

function sign(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; }

1.1. kbec 에서 수정 -한 가지 유형은 더 적고 성능이 뛰어나며 짧게 [가장 빠름]

function sign(x) { return x ? x < 0 ? -1 : 1 : 0; }

주의: sign("0") -> 1


2. 우아하고 짧고 빠르지 않음 [가장 느림]

function sign(x) { return x && x / Math.abs(x); }

주의 : sign(+-Infinity) -> NaN ,sign("0") -> NaN

현재 InfinityJS의 법적 번호는이 솔루션이 완전히 정확하지 않은 것 같습니다.


3. 예술 ...하지만 매우 느림 [가장 느림]

function sign(x) { return (x > 0) - (x < 0); }

4. 빠른 비트 시프트를 사용
하지만sign(-Infinity) -> 0

function sign(x) { return (x >> 31) + (x > 0 ? 1 : 0); }

5. 형식 안전 [megafast]

! 브라우저 (특히 크롬의 v8)가 일부 마법 최적화를 수행하는 것처럼 보이며이 솔루션은 2 개의 추가 작업이 포함되어 있고 논리적으로 결코 더 빠를 수 없음에도 불구하고 (1.1)보다 훨씬 더 성능이 뛰어난 것으로 나타났습니다.

function sign(x) {
    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? 0 : NaN : NaN;
}

도구

개선을 환영합니다!


[Offtopic] 수락 된 답변

  • Andrey Tarantsov- 예술에 +100이지만 슬프게도 명백한 접근 방식보다 약 5 배 느립니다.

  • Frédéric Hamidi- 어쩐지 가장 많이 찬성 된 답변 (글을 쓰는 동안) 그리고 다소 멋지지만, 일을 어떻게해야하는지 확실히 아니에요, imho. 또한 숫자이기도 한 무한대 숫자를 올바르게 처리하지 못합니다.

  • kbec- 명백한 솔루션의 개선입니다. 그다지 혁명적이지는 않지만 모두 종합하면이 접근법이 가장 좋다고 생각합니다. 그를 위해 투표하십시오 :)


3
요점은 때때로 0특별한 경우라는 것입니다
2011 년

1
모든 알고리즘을 테스트하기 위해 JSPerf 테스트 세트 (다른 ​​종류의 입력 포함)를 만들었습니다 .
Alba Mendez 2013 년

2
@disfated, 그들 중 누구? 물론 test everything버전 을 실행하면 Safe는 특수 값 테스트를 거부하므로 더 빠를 것입니다! only integers대신 테스트를 실행 해보십시오 . 또한 JSPerf는 그저 자신의 일을하고 있으며 좋아하는 문제가 아닙니다. :)
Alba Mendez 2013 년

2
jsperf 테스트에 따르면 typeof x === "number"성능에 마법을 부여 하는 것으로 밝혀졌습니다 . 더 많은 실행, 특히 FF, Opera 및 IE를 명확하게 만드십시오.
disfated

4
완전성을 위해 나는 FF25Math.sign()등장하고 크롬으로 곧 출시 될 (0 === 0, "안전"만큼 빠르지 않음)에 대한 새로운 테스트 jsperf.com/signs/7 을 추가했습니다 .
Alex K.

답변:



28

숫자를 절대 값으로 나누면 부호도 제공됩니다. 단락 논리 AND 연산자를 사용하면 특수한 경우가 가능 0하므로 분할하지 않습니다.

var sign = number && number / Math.abs(number);

6
당신은 아마 싶어 var sign = number && number / Math.abs(number);경우number = 0
NullUserException

@NullUserException, 당신이 절대적으로 맞습니다 0. 특별한 경우가 필요합니다. 이에 따라 답변이 업데이트되었습니다. 감사합니다 :)
프레데릭 Hamidi

당신은 지금 최고입니다. 하지만 앞으로 더 많은 답이 있기를 바랍니다.
2010 년

24

찾고있는 함수는 signum 이며이를 구현하는 가장 좋은 방법은 다음과 같습니다.

function sgn(x) {
  return (x > 0) - (x < 0);
}

3
기다림. 실수가 있습니다 : for (x = -2; x <= 2; x ++) console.log ((x> 1)-(x <1)); (x = -2; x <= 2; x ++)에 대해 [-1, -1, -1, 0, 1]을 제공합니다. console.log ((x> 0)-(x <0)); 정확한 [-1, -1, 0, 1, 1] 제공
2013 년

13

JavaScript (ECMAScript)의 부호있는 0을 지원하지 않아야합니까? "megafast"함수에서 0이 아닌 x를 반환 할 때 작동하는 것 같습니다.

function sign(x) {
    return typeof x === 'number' ? x ? x < 0 ? -1 : 1 : x === x ? x : NaN : NaN;
}

따라서 ECMAScript의 Math.sign ( MDN ) 초안과 호환됩니다 .

x가 양수인지, 음수인지 또는 0인지 나타내는 x의 부호를 반환합니다.

  • x가 NaN이면 결과는 NaN입니다.
  • x가 −0이면 결과는 −0입니다.
  • x가 +0이면 결과는 +0입니다.
  • x가 음수이고 −0이 아니면 결과는 −1입니다.
  • x가 +0이 아니라 양수이면 결과는 +1입니다.

놀랍도록 빠르고 흥미로운 메커니즘이 인상적입니다. 더 많은 테스트를 기다리고 있습니다.
kbec 2014 년

10

최신 브라우저에서 진행되는 작업에 관심이있는 사람들을 위해 ES6 버전에는 기본 Math.sign 메서드가 있습니다. 여기 에서 지원을 확인할 수 있습니다 .

기본적으로 반환 -1, 1, 0또는NaN

Math.sign(3);     //  1
Math.sign(-3);    // -1
Math.sign('-3');  // -1
Math.sign(0);     //  0
Math.sign(-0);    // -0
Math.sign(NaN);   // NaN
Math.sign('foo'); // NaN
Math.sign();      // NaN

4
var sign = number >> 31 | -number >>> 31;

Infinity가 필요하지 않고 숫자가 openjdk-7 소스에서 찾을 수있는 정수라는 것을 아는 경우 초고속 : java.lang.Integer.signum()


1
이것은 -0.5와 같은 작은 음수 분수에서는 실패합니다. (소스가 Integers에 대한 구현에서 나온 것 같습니다.)
stared

1

재미를 위해 이것을 추가 할 것이라고 생각했습니다.

function sgn(x){
  return 2*(x>0)-1;
}

0 및 NaN 반환 -1
+/- 무한대에서 잘 작동합니다.


1

모든 숫자, 0및 및 및 및 -0에서 작동하는 솔루션 은 다음 Infinity-Infinity같습니다.

function sign( number ) {
    return 1 / number > 0 ? 1 : -1;
}

자세한 내용은 " +0과 -0이 같은가요? " 라는 질문 을 참조하십시오.


경고 : now 표준 Math.sign을 포함하여 이러한 답변 중 어떤 것도 케이스 0-0. 이것은 문제가되지 않을 수 있지만 특정 물리 구현에서는 중요 할 수 있습니다.


0

숫자를 비트 시프트하고 MSB (Most Significant Bit)를 확인할 수 있습니다. MSB가 1이면 숫자는 음수입니다. 0이면 양수 (또는 0)입니다.


@ NullUserException 나는 여전히 틀릴 수 있지만 "모든 비트 연산자의 피연산자는 빅 엔디안 순서와 2의 보수 형식으로 부호있는 32 비트 정수로 변환됩니다." 에서 촬영 MDN
Brombomb

여전히 끔찍한 작업처럼 보입니다. 여전히 1과 0을 -1과 1로 변환해야하고 0도 처리해야합니다. OP가 그것을 원했다면 사용하는 것이 더 쉬울 것입니다var sign = number < 0 : 1 : 0
NullUserException 2011 년

+1. 하지만 이동할 필요는 없습니다 n & 0x80000000. 비트 마스크처럼 할 수 있습니다 . 0,1, -1로 변환 :n && (n & 0x80000000 ? -1 : 1)
davin

@davin 모든 숫자가 해당 비트 마스크에서 작동하도록 보장됩니까? 플러그를 꽂았는데 -5e32고장 났습니다 .
NullUserException

@NullUserException ఠ_ఠ, 표준을 적용 할 때 동일한 기호를 유지하는 숫자 ToInt32. 거기에서 읽으면 (섹션 9.5) 32 비트 정수의 범위가 js 숫자 유형의 범위보다 작기 때문에 숫자 값에 영향을주는 모듈러스가 있습니다. 따라서 그 값이나 무한대에는 작동하지 않습니다. 그래도 대답이 마음에 듭니다.
다빈

0

방금 똑같은 질문을하려고했지만 글을 쓰기 전에 해결책을 찾았고이 질문이 이미 존재하는 것을 보았지만이 해결책을 보지 못했습니다.

(n >> 31) + (n > 0)

삼항을 추가하면 더 빠른 것 같습니다. (n >> 31) + (n>0?1:0)


아주 좋아. 귀하의 코드는 (1)보다 상당히 빠릅니다. (n> 0? 1 : 0)은 유형 캐스트가 없기 때문에 더 빠릅니다. 유일한 dissapointing 순간은 sign (-Infinity)가 0을 준다는 것입니다. 업데이트 된 테스트.
disfated

0

Martijn의 대답과 매우 유사합니다.

function sgn(x) {
    isNaN(x) ? NaN : (x === 0 ? x : (x < 0 ? -1 : 1));
}

더 읽기 쉽습니다. 또한 (또는 귀하의 관점에 따라) 숫자로 해석 될 수있는 것들을 더럽 힙니다. 예를 들어, 그것은 반환 -1되게 할 때 '-5'.


0

-0과 0을 반환하는 실질적인 의미가 Math.sign없으므로 내 버전은 다음과 같습니다.

function sign(x) {
    x = Number(x);
    if (isNaN(x)) {
        return NaN;
    }
    if (x === -Infinity || 1 / x < 0) {
        return -1;
    }
    return 1;
};

sign(100);   //  1
sign(-100);  // -1
sign(0);     //  1
sign(-0);    // -1

이것은 signum 함수가 아닙니다
disfated

0

내가 아는 방법은 다음과 같습니다.

수학 부호 (n)

var s = Math.sign(n)

이것은 기본 함수이지만 함수 호출의 오버 헤드로 인해 가장 느립니다. 그러나 'NaN'을 처리합니다. 여기서 아래의 다른 항목은 0 (예 : Math.sign ( 'abc')이 NaN)이라고 가정 할 수 있습니다.

((n> 0)-(n <0))

var s = ((n>0) - (n<0));

이 경우 부호에 따라 왼쪽 또는 오른쪽 만 1이 될 수 있습니다. 결과적으로 1-0(1), 0-1(-1) 또는 0-0(0)이됩니다.

이 속도는 Chrome에서 다음 속도와 함께 목과 목처럼 보입니다.

(n >> 31) | (!! n)

var s = (n>>31)|(!!n);

"Sign-propagating right shift"를 사용합니다. 기본적으로 31만큼 시프트하면 부호를 제외한 모든 비트가 삭제됩니다. 부호가 설정되어 있으면 결과는 -1이고 그렇지 않으면 0입니다. 오른쪽 |값을 부울로 변환하여 양수를 테스트합니다 (0 또는 1 [BTW :과 같은 숫자가 아닌 문자열 !!'abc'은이 경우 0이됩니다. not NaN]) 그런 다음 비트 OR 연산을 사용하여 비트를 결합합니다.

이것은 브라우저 전반 에서 최고의 평균 성능으로 보이지만 (적어도 Chrome과 Firefox에서 최고), 모든 브라우저에서 가장 빠른 것은 아닙니다. 어떤 이유로 IE에서는 삼항 연산자가 더 빠릅니다.

n? n <0? -1 : 1 : 0

var s = n?n<0?-1:1:0;

어떤 이유로 IE에서 가장 빠릅니다.

jsPerf

수행 된 테스트 : https://jsperf.com/get-sign-from-value


0

내 두 센트, Math.sign과 동일한 결과를 반환하는 함수, 즉 sign (-0)-> -0, sign (-Infinity)-> -Infinity, sign (null)-> 0 , sign (undefined)-> NaN 등

function sign(x) {
    return +(x > -x) || (x && -1) || +x;
}

Jsperf는 테스트 또는 개정판을 만들 수 없습니다. 테스트를 제공 할 수 없어서 죄송합니다.

누군가 Jsperf 개정판에 추가해 주시면 이전에 제공된 모든 솔루션과 어떻게 비교되는지 궁금합니다.

감사합니다!

짐.

편집하다 :

나는 다음과 같이 써야했다.

function sign(x) {
    return +(x > -x) || (+x && -1) || +x;
}

( (+x && -1)대신 (x && -1)) 처리 sign('abc')하려면 (-> NaN)


0

Math.sign은 IE 11에서 지원되지 않습니다. 베스트 답변을 Math.sign 답변과 결합하고 있습니다.

Math.sign = Math.sign || function(number){
    var sign = number ? ( (number <0) ? -1 : 1) : 0;
    return sign;
};

이제 Math.sign을 직접 사용할 수 있습니다.


1
당신은 제 질문을 업데이트하라고 저를 밀어 붙였습니다. 질문을받은 지 8 년이 지났습니다. 또한 내 jsfiddle을 es6 및 window.performance api로 업데이트했습니다. 그러나 나는 Math.sign의 유형 강제와 일치하기 때문에 mozilla의 버전을 polyfill로 선호합니다. 요즘에는 성능이 크게 중요하지 않습니다.
2010 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.