스타개발자 넓군은 int형이 21억까지 밖에 담을 수 없다는 사실에 짜증나서

Number형을 쓰기로 했다.

100억, 1000억이 되도 프로그램은 잘~돌아갔다.

근데 어느날 에러가 빵빵터져서 값을 살펴보니

서버에서 날라온 값이 1600000000010000253 이었다.

근데 실제로 Number 변수에 담긴 값은 전혀 다르게 1600000000010000100 였던것이다.

Number는 큰 수를 담을 수 있다기에 쓴거였는데 이게 왠일?

여기서 의문이 들었다.

"int 대신 Number를 쓸 경우 어느 정도까지가 안전한걸까?"


Number는 64비트 부동 소숫점 방식을 사용한다.

총 8바이트 = 64비트를 사용한다.

즉, 64개의 on/off로 표현된다는 얘기다.

첫번째 비트 하나는 음수인지 양수인지를 판단하는데 사용되고 (아래에서 s 라고 사용한다) [각주:1]

그 다음 11비트를 지수로 사용된다. (아래에서 n 이라고 사용한다) [각주:2]

그 다음 남는 52비트를 소수로 사용한다. (아래에서 k 라고 사용한다) [각주:3]

k는 소숫점을 나타내는데 1 + ( 1 / k ) 로 쓰인다.

k가 2 라면 1 + ( 1 / 2 ) = 1.5 라는 뜻이다.

편의상 아래에서는 1.k 라고 표현하겠다.

즉 Number 숫자 하나는 다음과 같이 표현된다.

s * ( 2^n ) * 1.k 로 표현된다.



보기 쉽게

( 2^n ) * 1.k

라고 하겠다.



10진수 2를 표현해보면

( 2^1 ) * 1.0 = 2 * 1 = 2

n = 1, k = 0 이다.

9를 표현해보자.

= 8 + 1
= 8 * 1.125
= ( 2^3 ) * 1.125
= ( 2^3 ) * ( 1 + ( 0.125 ) )
= ( 2^3 ) * ( 1 + ( 1 / 8 ) )
= 9

9 하나 표현하는데 이렇게 복잡하다.



그렇다면 Number가 무지 큰 수까지 표현할 수 있다는건 알겠는데

int 보다 더 큰 값을 사용하기 위해서 Number를 쓸 때

과연 얼마나 큰 값까지 정확하게 표현될 수 있을지 알아보자.

1씩 더해가면서 구해보면 되지 않아?




자 그렇다면 유추를 해보자

a라는 값을 만들려면 (어떤수 * 1.얼마)로 표현되어야한다.

여기서 핵심은 "1.얼마"에 있다.

즉, k 에 답이 있다.



여기서 k의 비밀을 파헤쳐보겠다.

Number로 표현하는 정수는 다음과 같은 기준이 되는 수가 있다.

2^0 = 1
2^1 = 2
2^2 = 4
2^3 = 8
2^4 = 16
...
2^n = N

여기서 16을 한번 골라서 예를 들어보자.

16을 표현해보면

16 = 2^4 * 1.0

n = 4, k = 0 이다.

이 16을 기준으로 17, 18, 19를 표현하려면

각각 1, 2, 3씩을 16에 더해주면 된다.

다른말로 하면 즉 1/16, 2/16, 3/16 을 1에 더해서 곱해주면 된다.

17 = 16 * ( 1*( 1/16 ) )
18 = 16 * ( 1*( 2/16 ) )
19 = 16 * ( 1*( 3/16 ) )

이걸 n, k 방식으로 바꿔보면 이렇다.

17 = 2^4 * 1.(1/16)
18 = 2^4 * 1.(2/16)
19 = 2^4 * 1.(3/16)
20 = 2^4 * 1.(4/16)
21 = 2^4 * 1.(5/16)
22 = 2^4 * 1.(6/16)
23 = 2^4 * 1.(7/16)
24 = 2^4 * 1.(8/16)
25 = 2^4 * 1.(9/16)
26 = 2^4 * 1.(10/16)
27 = 2^4 * 1.(11/16)
28 = 2^4 * 1.(12/16)
29 = 2^4 * 1.(13/16)
30 = 2^4 * 1.(14/16)
31 = 2^4 * 1.(15/16)
32 = 2^5 * 1.(0/32)
33 = 2^5 * 1.(1/32)

64(2^6)를 기준으로 65, 66을 표현하면

65 = 2^6 * 1.(1/64)
66 = 2^6 * 1.(2/64)
...
127 = 2^6 * 1.(63/64)

이런식으로 나간다.

자세히보면 1/64 여기에 바로 답이 있다.





자 이제 머리를 환기 시키고 새로운 주제로 넘어간다.

위에서 수를 증가시켜주기 위해서 1/16, 2/16, 3/16 표현이 되는데

다음과 같이 풀어볼수 있다.

1/16 = 1/16

2/16 = 1/8

3/16 = 1/16 + 2/16
       = 1/16 + 1/8

4/16 = 1/4

5/16 = 1/16 + 4/16
       = 1/16 + 1/4

6/16 = 2/16 + 4/16
       = 1/8 + 1/4

7/16 = 1/16 + 2/16 + 4/16
       = 1/16 + 1/8 + 1/4

...

15/16 = 1/16 + 2/16 + 4/16 + 8/16
         = 1/16 + 1/8 + 1/4 + 1/2

뭔가 리듬이 느껴지는가?

모두 1/x 의 조합으로만 표현이 가능하다.

16은 2^4, 8은 2^3, 4는 2^2, 2는 2^1 이다.

여기에 쓰인 4, 3, 2, 1이 바로 k 다.

k를 위한 비트수가 52비트라는 얘기는

1/2^52 + 1/2^51 + 1/2^50 ......... 1/2^1

까지 표현할 수 있다는 뜻이다.

이 숫자들의 배열도 매우 흥미로운 내용으로 채울 수 있지만 오늘의 포스트 주제에 너무 멀어지므로 결론으로 빨리 가보자.

그렇다면 이렇게 1/k의 조합으로 얼마나 작은수까지 나눌 수 있을까?

1/k 의 조합으로 더 이상 1단위로 나눌 수 없을만큼 큰 수가 바로 우리가 찾는 그 수가 아닐까?



1/2^52 + 1/2^51 + 1/2^50 ......... 1/2^1

바로 이 수가 바로 정수로 1씩 증가했을 때 차곡차곡 나타낼 수 있는 최대라는 뜻이다.

k가 4 일때 나타낼 수 있던 마지막 숫자가

31 = 16 + 15
    = 16 + 1*(15/16)
               = 15/16 = 1/16 + 2/16 + 4/16 + 8/16
                           = 1/16 + 1/8 + 1/4 + 1/2

위와 같았다.

k=4로는 128, 즉 2^5는 나타낼 수 없었다.

k가 4라면 나타낼 수 있는 제일 큰 수는 ( 2^5 ) - 1 이다.

그렇다면 k를 52까지 나타낼 수 있을때 제일 큰 수는 2^53 - 1이 될것이다.

즉 2^53보다 값이 크다면 정확하게 계산하지 못한다는 뜻이다.



2^53은 9,007,199,254,740,992 이다.

테스트를 한번 해보자.

trace( 9007199254740990 );
trace( 9007199254740991 );
trace( 9007199254740992 );
trace( 9007199254740993 );
trace( 9007199254740994 );

이 구문을 플래시에서 실행해보자.

그냥 긁어붙여도 된다.

9007199254740990
9007199254740991
9007199254740992
9007199254740992
9007199254740994

위와 같이 찍혔을 것이다.

Number 형이 9007199254740992가 넘어가면서 k가 52로는 1씩 계산할 수 없으므로 끝자리가 3을 표현하지 못해 4로 건너뛰어버린것이다.

즉 9007199254740992 까지가 1씩 증가시켰을 때 손실이 없는 보장된 범위라는 뜻이다.

한글로는 9경이다.

생각보다 크지 않다. 막 셀 수 없는 어마어마한수가 아니라 9000억 * 10 이 끝이다.

이 이상을 1씩 카운팅한다면

그 프로그램은 당장 오류가 발생할 것이다.





우리가 플래시를 다루면서 만약 9경을 넘는 수를 정확하게 카운팅해야된다면

Number 역시 답이 아니라는 뜻이다.

Number도 9경이 넘어가면서 1자리에서 손실이 발생하기 시작한다.

자릿수로는 16자리지만 16자리를 풀로 사용할 수 있는게 아니기 때문에

자릿수로는 고작 15자리까지만 보장이 된다는 뜻이다.



숫자가 15자리가 넘어가는 상황이 있다면 반드시 문자열로 다루고

대수연산에 쓰이는 수학라이브러리를 찾아 활용해야한다.





For the better.






  1. 1과 -1을 나타내는 sign이라고 해서 s 라고 사용한다. [본문으로]
  2. Exponent, 지수라고 한다. 2^n으로 사용하기 때문에 n이라고 한다. n 이 표현하는 범위는 1024에서 -1023 까지 표현되기 때문에 실제로 읽어오는 n 값에 1023을 빼줘야 실제 값이 된다. 읽어온 값이 1024라면 실제 n 값은 1이 된다. [본문으로]
  3. 원래는 m으로 사용한다. Mantissa, log 함수에서 소숫점을 나타내는 가수를 뜻한다. 하지만 n과 m으로 쓰면 헷갈려서 그냥 k 라고 한다. [본문으로]
저작자 표시 비영리 동일 조건 변경 허락
신고
  1. 소연 2011.07.21 22:15 신고

    아따~ 어렵네~ㅋ 좀이따 다시읽어봐야게써.ㅋ

  2. neec 2011.07.21 23:31 신고

    Number에 대해 다시 한 번 생각해 보게 되는 계기가 됐던거 같습니다. 정수가 필요한 상황에서 괜한 오버헤드를 감수하는 실수형은 자칫 의도하지 않은 버그로의 지름길이 되지 않을까 생각됩니다.

    실제 64bit 정수형을 다루게 되는 상황은 꽤나 빈번하고 절실할 때가 많습니다.(GUID 등)
    공교롭게 as3에서는 사용자가 연산자를 재정의 하는 일은 불가능해 통상 int 두 개를 이용해 int64 클래스를 사용하게 돼죠. 실제 이 클래스가 지원해야 할 메서드는 add, mul, div, equal, toString, fromString이면 충분합니다.
    이 값은 런타임에 int 두 개로 존재하며 보관은 String인 형태가 되겠죠.

    • Favicon of http://wooyaggo.tistory.com 우야꼬  2011.07.22 00:24 신고

      operator 만 override가 된다면 많은걸 할 수 있을텐데 그게 참 아쉬워요 ㅎㅎ

  3. 2011.07.22 00:08 신고

    개발자들은 왜 이러고 노는걸까.

    • Favicon of http://wooyaggo.tistory.com 우야꼬  2011.07.22 00:25 신고

      헐 노는거 아니거덩~
      실제로 소셜 게임 만들다보면 큰수를 얼마나 자주 만나는데...;;;

      어디까지 표현할 수 있는지 알고 만드는거랑 모르고 만드는거랑 천지차이지

    • 2011.07.22 11:17 신고

      아아.. 노느게 아니였다니..ㅡㅜ
      그럼 더 싫어진다..ㅋㅋ

  4. Favicon of http://chanik.com 찬익 2011.07.22 01:20 신고

    부동소수점. 항상 골칫거리에요 ㅎㅎ
    자릿수도 중요하지만, 늘 같이 생각해야 하는 것이 floating하는 소수점이라는 사실 ㅎㅎ

    • Favicon of http://wooyaggo.tistory.com 우야꼬  2011.07.25 11:48 신고

      그저 큰수, 큰수... 라고만 알았지 막상 해보니까
      생각보다 큰수가 아니어서 약간 실망했습니다.
      그나저나 BigInt 나 int64 같은 클래스는 제대로 된게 별로 없네요 ㅠㅠ

  5. Favicon of http://desty.tistory.com desty 2011.07.22 07:51 신고

    고철덩어리 같으니라고 !

  6. 하늘아이 2011.07.22 10:27 신고

    괜찮은 팁이군요.
    그래도 변화를 최소화 하기 위해서 맨 마직막에 1/2를 무시해 주는 센스를 발휘해서.... 그 이상 값들은 짝수로만 찍히는군요..

    • Favicon of http://wooyaggo.tistory.com 우야꼬  2011.07.25 11:49 신고

      꼭 1/2 이라고 생각하긴 어려울거 같아요.
      그냥 전 9경까지만 안전하다~ 라고만 생각하려구요 ㅎㅎ

  7. Favicon of http://blog.jidolstar.com 지돌스타 2011.07.22 11:09 신고

    이렇게 멋진 글을~ overflow에 대한 대비는 항상 필수~ ^^

  8. Favicon of http://igna.tistory.com 야훔 2011.07.22 16:21 신고

    와우 멋져요! 감동받았습니다! 항상 궁금해하던건데!!

  9. synchrong 2011.07.24 01:52 신고

    M이론에 나온 10+1 차원에 빠진 야꼬군... 우리가 사는세계는 3차원이라고... 그만 돌아왕

    • Favicon of http://wooyaggo.tistory.com 우야꼬  2011.07.24 22:53 신고

      요즘은 다섯개 이론에 14차원까지 나왔다던데? ㅋㅋㅋㅋ
      난 초끈이론은 철학이라고 봐 ㅋ

  10. 응아 2011.07.24 10:51 신고

    고대 수학자.. 같습니다. ;;;;
    좋은 정보 재밌게 잘 읽고 갑니다!*^

    • Favicon of http://wooyaggo.tistory.com 우야꼬  2011.07.24 22:52 신고

      큰수 다룰때 늘 불안하던걸 함 자세잡고 풀어본건
      값을 알고나서 검색해보니 이미 너무너무 많이 알려진 사실이라
      머쓱합니다 ㅋㅋ

  11. 우르 2011.08.13 22:43 신고

    우야꼬의 플래시 cs4 샀다 왕 쓸모 많음
    감사???합니다.

  12. 우르 2011.08.13 22:43 신고

    우야꼬의 플래시 cs4 샀다 왕 쓸모 많음
    감사???합니다.

  13. Favicon of http://엄진영 a7788000 2011.09.07 20:14 신고

    나도야

  14. 컴백홍 2011.10.18 14:09 신고

    항상 궁금하던 건데, 속 시원히 풀어줘서 정말 감사합니다.

  15. Favicon of http://oddly.tistory.com TY 2012.02.22 18:31 신고

    멋진 글이네요 링크 추가해갈께요 ^^

+ Recent posts

티스토리 툴바