ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Effective JavaScript [2] - 숫자형 타입
    Javascript 2016. 11. 28. 22:23



    본 게시물은 Effective Javascript의 내용을 재구성하여 작성되었음을 알립니다. 저작권 문제 발생시 게시물이 비공개 될 수 있습니다. 


    주요내용.

    - 자바스크립트의 숫자는 double-정확도의 부동 소수점 숫자다.

    - 자바스크립트의 정수는 별개의 데이터형이 아니라 double의 부분집합이다.
    - 비트단위 연산자는 숫자를 32비트의 부호과 있는 integer처럼 처리한다.

    - 부동 소수점 산술 연산의 정확도가 한계가 있음을 주의해야 한다.


    자바스크립트의 부동 소수점 숫자 이해하기 


    자바스크립트에는 숫자형 데이터가 단 하나밖에 없다. typeof 연산자의 동작을 통해 자바스크립트가 정수형이나 부동 소수점 숫자를 단순히 숫자형으로 분류한다는 사실을 확인해 볼 수 있다.


    typeof 17;        // "number"

    typeof 98.6;     // "number"

    typeof -2.1;      // "number"


    사실, 자바스크립트 내의 모든 숫자는 IEEE 754 표준에서 정의한 64비트로 인코딩된 배정밀도의(double-precision) 부동 소수점, 즉 흔히 'double'로 알려진 숫자다. double은 53비트까지의 정확도로 완벽하게 integer로 표현할 수 있다. -9,007,199,254,740,992(-2^53)부터 9,007199,254,740,992(2^53)까지의 모든 integer는 유효한 double 값들이다. 따라서 자바스크립트에서 integer 연산은 별도 integer형 없이도 완벽하게 가능하다. 


    대부분의 산술 연산자는 정수형이나 실수 또는 이 둘의 조합으로 동작한다.


    0.1 * 1.9;    // 0.19

    -99 + 100;    // 1

    21 - 12.3;    // 8.7

    2.5 / 5;     // 0.5


    비트단위 연산자는 특별한 점이있다. 이는 인자들을 직접 부동 소수점 숫자처럼 처리하지 않고, 암묵적으로 32비트 정수로 변호나한다. (정확하게 말하자면 32비트, big-endian, 2의 보수로 처리된다). 예를 들어 비트단위 OR 연산을 수행하는 경우 


    8 | 1; // 9


    위 단순해 보이는 표현식은 몇 가지 평가 단계를 거친다. 자바스크립트의 숫자 8과 1은 항상 double 형이다. 하지만 32비트 정소형, 즉 32개의 0과 1로 도 표현될 수 있다. 숫자 8은 다음과 같은 형태가 된다.


    00000000000000000000000000001000


    숫자형의 toString  메서드를 사용해 직접 확인해 볼 수 있다.


    (8).toString(2);     // "1000"


    toString의 인자는 기수(radix)를 나타내는데, 이 경우에는 기수가 2인(즉, 2진 바이너리) 표현을 가리킨다. 결과에는 값에 영향을 미치지 않는 왼쪽 0이 생략된다. 



    정수형 1을 32비트로 표현하면 다음과 같다.


    00000000000000000000000000000001


    비트단위 OR 표현식은 두 개의 비트 시퀀스를 합치며, 입력 중 어떤 1 비트라도 발견하면 1값을 가지게 된다. 따라서 8 | 1의 결과는 다음과 같은 비트 패턴을 갖게 된다.


    00000000000000000000000000001001


    이 시퀀스는 정수형 9를 나타나낸다. 이 값을 표준 라이브러리 함수인 parseInt 에 기수 2를 지정하여 다시 검증해 볼 수 있다.


    parseInt("1001", 2);    // 9


    모든 비트단위 연산자는 동일한 방식으로 동작한다. 입력값을 정수형으로 변환하고 정수 비트 패턴에서 각 연산을 수행하고 나서, 표준 자바스크립트 부동 소수점 숫자 값으로 변환해 결과를 되돌려 준다. 연산 표현식이나 변수가 명시적으로 동작할 때면 최적화 컴파일러가 실행되어 데이터를 내부적으로 정수형으로 저장하여 부동 소수점으로 저장하지 않기도 한다. 


    아직 별로 신경쓰이지 않는다고 해도 부동 소수점 숫자는 결국 골치아픈 존재라 할 수 있다. 부정확한 연산 결과값 때문인데 완전 간단해 보이는 산술 연산에서 잘못된 결과를 만들어 내기도 한다.


    0.1 + 0.2;     // 0.300000000000000004


    64비트의 정확도는 충분히 넓지만, double은 실수에 비해 여전히 유한한 숫자 범위만 표현할 수 있다. 부동 소수점 산술 연산은 근사 값만을 만들어 낼수 있고 가장 가까운 표현가능한 실수로 반올림한다. 계산을 계속 수행하다 보면 이런 반올림 오류가 누적되어 더욱 더 부정확한 결과를 낳게 된다. 반올림은 간혹 일반적인 산술 결과에서 기대하기 어려운 어이없는 편차를 보이기도 한다.

    예를 들어 어떤 실수 x, y, z라도 항상 (x + y) + z = x + ( y + z)이며 이를 결합 가능하다고 말한다. 하지만 부동 소수점 숫자는 항상 그렇진 않다. 


    ( 0.1 + 0.2 ) + 0.3; // 0.600000000001

    0.1 + (0.2 + 0.3); // 0.6


    부동 소수점의 정확도와 성능은 서로 상충관계다.

    정확도가 관건이라면, 이런 한계에 대해 반드시 알아두어야 한다. 한 가지 유용한 대안은 가능한 정수 값을 사용하는 것이다. 정수 값은 반올림 없이 표현이 가능하기 때문이다. 

    돈 계산을 할 때 프로그래머는 종종 통화의 가장 작은 액면가로 변환하여 전체 숫자를 계산할 수 있게 숫자를 높인다. 예를 들어, 앞선 계산을 달러라고 가정한다면, 다음과 같이 소수점의 달러 대신에 세트로 변환해 정수로 처리할 수 있다. 


    ( 10 + 20 )  + 30 ;    // 60

    10 + (20 + 30) ;    // 60


    정수를 처리할 때 모든 연산이 -2^53과 2^53 범위 내에 맞춰진다는 점도 염두에 두어야 한다.



    - 자바스크립트의 숫자는 double-정확도의 부동 소수점 숫자다.

    - 자바스크립트의 정수는 별개의 데이터형이 아니라 double의 부분집합이다.
    - 비트단위 연산자는 숫자를 32비트의 부호과 있는 integer처럼 처리한다.

    - 부동 소수점 산술 연산의 정확도가 한계가 있음을 주의해야 한다.



    끄읕.



Designed by Tistory.