부동 소수점을 JavaScript의 정수로 변환하는 가장 좋은 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/131406

  •  02-07-2019
  •  | 
  •  

문제

부동 소수점 번호를 JavaScript의 정수로 변환하는 몇 가지 방법이 있습니다. 내 질문은 방법이 최고의 성능을 제공하거나 가장 호환되거나 모범 사례로 간주되는 것은 무엇입니까?

다음은 다음과 같은 몇 가지 방법입니다.

var a = 2.5;
window.parseInt(a); // 2
Math.floor(a);      // 2
a | 0;              // 2

나는 거기에 다른 사람들이 있다고 확신합니다. 제안?

도움이 되었습니까?

해결책

에 따르면 이 웹 사이트:

Parseint는 때때로 부동 소수점 번호를 정수로 바꾸는 수단으로 사용됩니다. 인수가 숫자 유형 인 경우 먼저 문자열로 변환 된 다음 숫자로 구문 분석되기 때문에 그 작업에 매우 적합합니다.

숫자를 반올림하려면 수학 중 하나를 정수하기 위해서는 Math.round, Math.ceil 및 Math.floor가 바람직합니다 ...

다른 팁

Douglas Crockford의 "JavaScript : The Good Parts"에서 :

Number.prototype.integer = function () {
    return Math[this < 0 ? 'ceil' : 'floor'](this);
}

그렇게하면 모든 숫자 객체에 메소드를 추가합니다.

그런 다음 다음과 같이 사용할 수 있습니다.

var x = 1.2, y = -1.2;

x.integer(); // 1
y.integer(); // -1

(-10 / 3).integer(); // -3

분명히 Double Bitwise-Not는 숫자를 바닥에 가장 빠른 방법입니다.

var x = 2.5;
console.log(~~x); // 2

여기서 기사가되었지만 지금은 404를 얻었습니다. http://james.padolsey.com/javaScript/double-bitwise-not/

Google에 캐시가 있습니다. http://74.125.155.132/search?q=cache:wpZnhsbJGt0J:james.padolsey.com/javascript/double-bitwise-not/+double+bitwise+not&cd=1&hl=en&ct=clnk&gl=us

그러나 Wayback Machine은 하루를 절약합니다! http://web.archive.org/web/20100422040551/http://james.padolsey.com/javaScript/double-bitwise-not/

대답은 이미 주어졌지만 명확합니다.

이를 위해 수학 라이브러리를 사용하십시오. 둥근, 천장 또는 바닥 기능.

Parseint는 문자열을 여기서 필요하지 않은 int로 변환하기위한 것입니다.

Tofixed는 플로트를 문자열로 변환하기위한 것입니다.

수학 기능은 문자열로 전환하거나 문자열로 전환하지 않기 때문에 어쨌든 잘못된 다른 선택보다 빠릅니다.

숫자 (a) .tofixed (0)를 사용할 수 있습니다.

또는 단지 A.tofixed (0);

편집하다:

그것은 절단과 약간 다른 0 장소로 반올림되며, 다른 사람이 제안한 것처럼 두 번의 정수가 아닌 끈을 반환합니다. 디스플레이 목적에 유용합니다.

var num = 2.7;  // typeof num is "Number"
num.toFixed(0) == "3"

'최고의'방법 의존합니다 에:

  • 반올림 모드 : 뭐 반올림의 유형 (플로트에서 정수로) 당신은 기대/요구합니다.
    분수 부품을 갖는 양수 및/또는 음수의 경우.
    일반적인 예 :
    float | trunc | floor |  ceil | near (half up)
    ------+-------+-------+-------+---------------
    +∞    |   +∞  |   +∞  |   +∞  |   +∞  
    +2.75 |   +2  |   +2  |   +3  |   +3
    +2.5  |   +2  |   +2  |   +3  |   +3
    +2.25 |   +2  |   +2  |   +3  |   +2
    +0    |   +0  |   +0  |   +0  |   +0
     NaN  |  NaN  |  NaN  |  NaN  |  NaN
    -0    |   -0  |   -0  |   -0  |   -0
    -2.25 |   -2  |   -3  |   -2  |   -2
    -2.5  |   -2  |   -3  |   -2  |   -2
    -2.75 |   -2  |   -3  |   -2  |   -3
    -∞    |   -∞  |   -∞  |   -∞  |   -∞  
    
    플로트에서 정수 변환을 위해 우리 천하게 예상하다 "잘림"
    (일명 "제로를 향해 라운드" 일명 "인피니티에서 멀리 떨어져").
    효과적으로 이것은 플로팅 포인트 번호의 분수 부분을 '절단'합니다.
    대부분의 기술과 (내부적으로) 내장 된 방법이 이런 식으로 행동합니다.
  • 입력 : (부동 소수점) 숫자가 어떻게 표현되는지 :
    • String
      일반적으로 radix/base : 10 (소수점)
    • 부동 소수점 ( '내부') Number
  • 출력 : 결과 값으로하고 싶은 일 :
    • (중간) 출력 String (기본 Radix 10) (화면)
    • 결과 값에 대한 추가 계산을 수행하십시오
  • 범위:
    입력/계산-결과를 기대하는 숫자 범위에서
    그리고 어떤 범위를 위해 해당 '올바른'출력을 기대하십니까?

~ 후에 이러한 고려 사항은 적절한 방법과 속도에 대해 생각할 수 있습니다!


ECMAScript 당 262 사양에 따라 : 모두 숫자 (유형 Number) JavaScript에서는 다음과 같이 표시/저장됩니다.
"IEEE 754 이중 정밀 부동 부동 소수점 (Binary64)"형식.
너무 정수입니다 또한 represented in the 같은 부동 소수점 형식 (분수가없는 숫자).
참고 : 대부분의 구현 하다 더 효율적 인 (속도 및 메모리 크기) 정수 유형을 사용하십시오. 내부적 가능할 때!

이 형식은 1 부호 비트, 11 지수 비트 및 처음 53 개의 유의 한 비트 ( "Mantissa")를 저장하므로 다음을 말할 수 있습니다. Number-값 ~ 사이 -252 그리고 +252 분수를 가질 수 있습니다.
다시 말해: 모두 대표 긍정적이고 부정적인 Number-값 ~ 사이 252 (거의) 2(211/2=1024) (그 시점에서 형식은 그것을 호출합니다 하루 Infinity)는 이미 정수입니다 (나머지 분수 및/또는 최소한의 정수 숫자를 나타내는 비트가 남지 않기 때문에 내부 둥글게 됨).

그리고 첫 번째 'gotcha'가 있습니다.
내부 반올림 모드를 제어 할 수 없습니다 Number-내장 리터럴/문자열에서 플로트 변환 (Rounding-Mode : IEEE 754-2008”라운드에서 가장 가까운 넥타이, 짝수와 짝수) 및 내장 된 산술 작업 (Rounding-Mode : IEEE 754-2008 "Round- 가장 큰 ").
예를 들어:
252+0.25 = 4503599627370496.25 둥글고 다음과 같이 저장됩니다. 4503599627370496
252+0.50 = 4503599627370496.50 둥글고 다음과 같이 저장됩니다. 4503599627370496
252+0.75 = 4503599627370496.75 둥글고 다음과 같이 저장됩니다. 4503599627370497
252+1.25 = 4503599627370497.25 둥글고 다음과 같이 저장됩니다. 4503599627370497
252+1.50 = 4503599627370497.50 둥글고 다음과 같이 저장됩니다. 4503599627370498
252+1.75 = 4503599627370497.75 둥글고 다음과 같이 저장됩니다. 4503599627370498
252+2.50 = 4503599627370498.50 둥글고 다음과 같이 저장됩니다. 4503599627370498
252+3.50 = 4503599627370499.50 둥글고 다음과 같이 저장됩니다. 4503599627370500

반올림을 제어합니다 Number 분수 부품이 필요합니다 (그리고 그것을 나타내는 데 적어도 하나의 비트)가 필요합니다. 그렇지 않으면 천장/바닥/Trunc/근적이 공급 된 정수를 반환합니다.

최대 x 숫자의 숫자를 올바르게 x 중요한 분수 소수점 자리수로 올바르게하려면, 우리는 상응하는 최저 및 가장 높은 십진수 분수 값이 반올림 후에도 이진 분수 값을 제공하는 경우에만 적용됩니다 (따라서 천장 또는 바닥재되지 않음. 다음 정수).
예를 들어, '올바른'반올림 (CEIL/FLOON/TRUNC의 경우)을 최대 1 개의 중요한 분수 소수점 자리수 (x.1 to x.9), 우리는 필요합니다 적어도 우리에게주는 3 비트 (4가 아님) 이진 분수 값 :
0.1 더 가깝습니다 1/(23=8)=0.125 그것보다 0 그리고 0.9 더 가깝습니다 1-1/(23=8)=0.875 그것보다 1.

까지 ±2(53-3=50) 모든 표현 가능한 값은 첫 번째 유의 한 소수점 분수 숫자 (값 x.1 에게 x.9).
2 개의 소수의 경우 ±2(53-6=47), 3 개의 소수의 경우 ±2(53-9=44), 4 개의 소수의 경우 ±2(53-13=40), 5 개의 소수의 경우 ±2(53-16=37), 6 개의 소수의 경우 ±2(53-19=34), 7 개의 소수의 경우 ±2(53-23=30), 8 개의 소수의 경우 ±2(53-26=27), 9 개의 소수의 경우 ±2(53-29=24), 10 개의 소수의 경우 ±2(53-33=20), 11 개의 소수의 경우 ±2(53-36=17), 등..

"안전한 정수" JavaScript에서는 정수입니다.

  • 그것은 가능하다 바로 그거죠 IEEE-754 이중 정밀 번호로 표시 및
  • 누구의 IEEE-754 표현 할 수 없습니다 IEEE-754 표현에 맞게 다른 정수를 반올림 한 결과입니다.
    (일지라도 ±253 (2의 정확한 힘으로) 정확히 표현 될 수 있습니다. ~ 아니다 안전한 정수 ±(253+1) 최대 53 개의 가장 중요한 비트에 맞게 반올림하기 전에).

이는 (안전하게 표현 가능한) 정수의 하위 집합 범위를 효과적으로 정의합니다. ~ 사이 -253 그리고 +253:

  • 에서: -(253 - 1) = -9007199254740991 (포함한)
    (정적 속성으로 제공되는 상수 Number.MIN_SAFE_INTEGER ES6 이후)
  • 에게: +(253 - 1) = +9007199254740991 (포함한)
    (정적 속성으로 제공되는 상수 Number.MAX_SAFE_INTEGER ES6 이후)
    이 2 개의 새로운 ES6 상수에 대한 사소한 다색 :

    Number.MIN_SAFE_INTEGER || (Number.MIN_SAFE_INTEGER=
      -(Number.MAX_SAFE_INTEGER=9007199254740991) //Math.pow(2,53)-1
    );
    


ES6이므로 무료 정적 방법도 있습니다 Number.isSafeInteger() 전달 된 값이 유형 인 경우 테스트합니다 Number 그리고 안전한 정수 범위 내의 정수입니다 (부울 반환 true 또는 false).
참고 : 또한 돌아옵니다 false 을 위한: NaN, Infinity 그리고 분명히 String (숫자를 나타내더라도).
폴리 필 예시:

Number.isSafeInteger || (Number.isSafeInteger = function(value){
  return typeof value === 'number' && 
                value === Math.floor(value) &&
                value  <   9007199254740992 &&
                value  >  -9007199254740992;
});

ECMAScript 2015 / ES6은 새로운 정적 메소드를 제공합니다 Math.trunc()
정수에 플로트를 자르려면 :

숫자 x의 적분 부분을 반환하여 분수 숫자를 제거합니다. X가 이미 정수 인 경우 결과는 x입니다.

또는 더 간단하게 (MDN):

다른 세 가지 수학 방법과 달리 : Math.floor(), Math.ceil() 그리고 Math.round(), 방법 Math.trunc() 작품은 매우 간단하고 간단합니다.
인수가 양수인지 음수인지 여부에 관계없이 점과 뒤에있는 숫자를 자르십시오.

우리는 더 설명 할 수 있습니다 (및 polyfill) Math.trunc() 따라서 :

Math.trunc || (Math.trunc = function(n){
    return n < 0 ? Math.ceil(n) : Math.floor(n); 
});

위의 Polyfill의 페이로드는 할 수 있습니다 잠재적으로 엔진에 비해 엔진에 대해 더 잘 최적화하십시오.
Math[n < 0 ? 'ceil' : 'floor'](n);

용법: Math.trunc(/* Number or String */)
입력: (정수 또는 부동 소수점) Number (하지만 행복하게 문자열을 숫자로 변환하려고합니다)
산출: (정수) Number (하지만 행복하게 문자열 context에서 숫자를 문자열로 변환하려고합니다)
범위: -2^52 에게 +2^52 (이 외에도 우리는 '반올림 오류'(그리고 어느 시점에서 과학적/지수 표기법)를 기대해야합니다. Number IEEE 754의 입력은 이미 분수 정밀도를 잃어 버렸습니다. ±2^52 에게 ±2^53 이미 있습니다 내부적으로 반올림 정수 (예를 들어 4503599627370509.5 내부적으로 이미 대표되어 있습니다 4503599627370510) 이후 ±2^53 정수도 느슨한 정밀도 (2).


탁자를 빼서 정수로 변환합니다 나머지 (%)의) 1:

예시: result = n-n%1 (또는 n-=n%1)
이것도해야합니다 잘라 부유물. 나머지 운영자가 더 높기 때문에 상위 뺄셈보다 우리는 효과적으로 얻습니다. (n)-(n%1).
양수의 경우이 층이 값을 쉽게 알 수 있습니다. (2.5) - (0.5) = 2,
음수의 경우이 천장은 값을 다음과 같습니다. (-2.5) - (-0.5) = -2 (왜냐하면 --=+ 그래서 (-2.5) + (0.5) = -2).

이후 입력 그리고 산출 ~이다 Number 우리 ~해야 한다 얻으십시오 동일한 유용한 범위 및 출력 ES6에 비해 Math.trunc() (또는 폴리 필드입니다).
참고 : 힘든 i 두려움 (확실하지 않음) 차이점이있을 수 있습니다 : 우리는 원래 번호 (플로트)에서 산술 (내부적으로 "근접한"(일명 Banker 's Rounding)을 사용하는 산술을 사용하고 있기 때문에 두 번째 파생 번호 (분수) 초대하는 것 같습니다. Digital_Representation 및 산술 반올림 오류를 복리화하여 결국 플로트를 반환 할 수 있습니다.


(ab-)를 사용하여 플로트로 정수 변환 비트 동작:

이것은 작동합니다 내부적 강제 (부동 소수점) Number 서명 된 32 비트 정수 값으로 변환 (잘린 및 오버플로) (2의 보완) 약간의 작업을 사용하여 a Number (그리고 결과는 다시 변환됩니다 (부동 소수점) Number 정수 값만 보유합니다).

다시, 입력 그리고 산출 ~이다 Number (그리고 다시 문자열 입력에서 숫자 및 숫자 출력으로의 무음 변환).

더 중요한 힘든 것 (그리고 일반적으로 잊혀지지 않고 설명되지 않음) :
Bitwise 작동 및 번호 부호에 따라 다릅니다,, 유용한 범위 될거야 제한된 사이:
-2^31 에게 +2^31 (처럼 ~~num 또는 num|0 또는 num>>0) 또는 0 에게 +2^32 (num>>>0).

이것은 다음 조회 테이블에 의해 더 명확 해져야합니다 (포함 모두 '중요한'예) :

              n             | n>>0 OR n<<0 OR   |    n>>>0    | n < 0 ? -(-n>>>0) : n>>>0
                            | n|0 OR n^0 OR ~~n |             |
                            | OR n&0xffffffff   |             |
----------------------------+-------------------+-------------+---------------------------
+4294967298.5 = (+2^32)+2.5 |             +2    |          +2 |          +2
+4294967297.5 = (+2^32)+1.5 |             +1    |          +1 |          +1
+4294967296.5 = (+2^32)+0.5 |              0    |           0 |           0
+4294967296   = (+2^32)     |              0    |           0 |           0
+4294967295.5 = (+2^32)-0.5 |             -1    | +4294967295 | +4294967295
+4294967294.5 = (+2^32)-1.5 |             -2    | +4294967294 | +4294967294
       etc...               |         etc...    |      etc... |      etc...
+2147483649.5 = (+2^31)+1.5 |    -2147483647    | +2147483649 | +2147483649
+2147483648.5 = (+2^31)+0.5 |    -2147483648    | +2147483648 | +2147483648
+2147483648   = (+2^31)     |    -2147483648    | +2147483648 | +2147483648
+2147483647.5 = (+2^31)-0.5 |    +2147483647    | +2147483647 | +2147483647
+2147483646.5 = (+2^31)-1.5 |    +2147483646    | +2147483646 | +2147483646
       etc...               |         etc...    |      etc... |      etc...
         +1.5               |             +1    |          +1 |          +1
         +0.5               |              0    |           0 |           0
          0                 |              0    |           0 |           0
         -0.5               |              0    |           0 |           0
         -1.5               |             -1    | +4294967295 |          -1
       etc...               |         etc...    |      etc... |      etc...
-2147483646.5 = (-2^31)+1.5 |    -2147483646    | +2147483650 | -2147483646
-2147483647.5 = (-2^31)+0.5 |    -2147483647    | +2147483649 | -2147483647
-2147483648   = (-2^31)     |    -2147483648    | +2147483648 | -2147483648
-2147483648.5 = (-2^31)-0.5 |    -2147483648    | +2147483648 | -2147483648
-2147483649.5 = (-2^31)-1.5 |    +2147483647    | +2147483647 | -2147483649
-2147483650.5 = (-2^31)-2.5 |    +2147483646    | +2147483646 | -2147483650
       etc...               |         etc...    |      etc... |      etc...
-4294967294.5 = (-2^32)+1.5 |             +2    |          +2 | -4294967294
-4294967295.5 = (-2^32)+0.5 |             +1    |          +1 | -4294967295
-4294967296   = (-2^32)     |              0    |           0 |           0
-4294967296.5 = (-2^32)-0.5 |              0    |           0 |           0
-4294967297.5 = (-2^32)-1.5 |             -1    | +4294967295 |          -1
-4294967298.5 = (-2^32)-2.5 |             -2    | +4294967294 |          -2

참고 1 : 마지막 열에는 범위가 확장되었습니다 0 에게 -4294967295 사용 (n < 0 ? -(-n>>>0) : n>>>0).
참고 2 : Bitwise는 자체 변환 오버 헤드를 소개합니다 (에스) (심각도 대 Math 실제 구현에 따라 다릅니다 ~할 수 있었다 더 빨리 (종종 오래된 역사적 브라우저에서)).


분명히, 당신의 '부동 소수점'숫자가 String 우선 첫째로,
parseInt(/*String*/, /*Radix*/) 정수로 구문 분석하기위한 적절한 선택 일 것입니다. Number.
parseInt() ~ 할 것이다 잘라 (양수 및 음수의 경우).
그만큼 범위 위에서 설명한대로 IEEE 754 이중 정밀 부동 소수점으로 다시 제한됩니다. Math 행동 양식).

마지막으로, 당신이있는 경우 String 그리고 기대 a String 출력으로 Radix Point와 분수를 잘라낼 수도 있습니다 (또한 IEEE 754 Double Precision Floating Point에 비해 더 큰 정확한 잘림 범위를 제공합니다.±2^52))!


추가의:
위의 정보에서 이제는 알아야 할 모든 것이 있어야합니다.

예를 들어 원하는 경우 0에서 둥글게 (일명 무한대로 돌아갑니다) 수정할 수 있습니다 Math.trunc() Polyfill 예시:

Math.intToInf || (Math.intToInf = function(n){
    return n < 0 ? Math.floor(n) : Math.ceil(n); 
});
var i = parseInt(n, 10);

같은 radix 값을 지정하지 않는 경우 '010' 8 월으로 취급 될 것입니다 (따라서 결과는 8 ~ 아니다 10).

Bitwise 연산자 사용. 정수로 변환하는 가장 분명한 방법은 아니지만 모든 종류의 데이터 유형에서 작동합니다.

당신의 기능이 주장을한다고 가정합니다 value, 그리고 기능은 value 항상 정수 여야합니다 (그리고 0은 받아 들여집니다). 그러면 다음 중 하나가 할당됩니다 value 정수로서 :

value = ~~(value)
value = value | 0;
value = value & 0xFF;   // one byte; use this if you want to limit the integer to
                        // a predefined number of bits/bytes

가장 좋은 점은 숫자 인 문자열 (텍스트 입력 등에서 얻을 수있는 것)과 함께 작동한다는 것입니다. ~~("123.45") === 123. 숫자가 아닌 모든 값이 발생합니다 0, 즉,

~~(undefined) === 0
~~(NaN) === 0
~~("ABC") === 0

그것은 문자열로 16 진수로 작동합니다 ( 0x 접두사)

~~("0xAF") === 175

몇 가지 유형의 강요가 관련되어 있다고 생각합니다. 이것들과 비교하기 위해 몇 가지 성능 테스트를 할 것입니다 parseInt() 그리고 Math.floor(),하지만 나는 여분의 편의를 좋아하지 않는 것을 좋아합니다. Errors 던져지고 얻는 것 0 숫자가 아닌 경우

그래서 벤치 마크를 만들었습니다 Chrome 입력이 이미 숫자 일 때 가장 빠른 것은 ~~num 그리고 num|0, 반 속도 : Math.floor, 그리고 가장 느린 일입니다 parseInt 보다 여기

benchmark result

편집하다: 이미 다른 사람이있는 것 같습니다. 반올림 벤치 마크 (더 많은 결과) 및 추가 방법: num>>0 (빨리 |0) 그리고 num - num%1 (때로는 빠른)

이 질문은 플로트에서 int로 변환하는 것에 대해 구체적으로 묻는 것으로 보입니다. 내 이해는 이것을하는 방법은 사용하는 것입니다. toFixed. 그래서...

var myFloat = 2.5;
var myInt = myFloat.toFixed(0);

누구든지 아는 사람이 있습니까? Math.floor() 다소 성능이 낮습니다 Number.toFixed()?

이런 식으로 할 수도 있습니다.

var string = '1';
var integer = a * 1;

parseint ()는 아마도 가장 좋은 것일 것입니다. a | 0 실제로 원하는 것을 수행하지 않습니다 (A가 정의되지 않은 또는 널 값인 경우 0을 지정합니다. 이는 빈 개체 또는 배열이 테스트를 통과 함을 의미합니다), Math.floor는 어떤 유형의 속임수로 작동합니다 (기본적으로 parseint ()라고 부릅니다. 백그라운드에서).

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top