아 백만년만에 블로그 글 쓰는거 같네요~


그러므로 간단하게 ㄱㄱ



BitmapData를 동그랗게 보여주고 싶을 때


마스크는 부담스러울 때 쓸 수 있는 메소드입니다.



이런 고양이 비트맵을



이렇게 나타내줄 수 있습니다.





아래는 코드입니다.


import flash.display.Bitmap;
import flash.display.BitmapData;

var bitmap: BitmapData = new Cat;
var circleBitmap: BitmapData = copyToCircle( bitmap );

addChild( new Bitmap( circleBitmap ) );

function copyToCircle( $target: BitmapData ): BitmapData
{
     var width: int = $target.width;
     var height: int = $target.height;
     const RADIUS: int = width > height ? int( height / 2 ) : int( width / 2 );
     const DIAMETER: int = 2 * RADIUS;
     
     var data: BitmapData = new BitmapData( DIAMETER, DIAMETER );
     
     var circle: Shape = new Shape;
     circle.graphics.beginFill( 0xFF0000, 1 );
     circle.graphics.drawRect( 0, 0, DIAMETER, DIAMETER );
     circle.graphics.drawCircle( RADIUS, RADIUS, RADIUS );
     circle.graphics.endFill();
     
     data.draw( $target );
     data.draw( circle, nullnull, BlendMode.ERASE );
     
     return data;
}

원리는 draw를 해주는 두줄의 코드입니다.


data.draw( $target );


일단 복사를 한번 해주고요


미리 동그라미 모양을 Shape으로 그려놓은 다음에


data.draw( circle, null, null, BlendMode.ERASE );


BlendMode를 ERASE로 그려주면


됩니다.


※ 이때 동그라미 모양이 중요한데


반전된 동그라미 모양입니다.


사각형에서 가운데가 동그라미로 빠진 모습입니다.



이렇게요~


저 빨간 모양을 Shape으로 그려주는게 포인트인데


Shape의 Vector drawing을 이용하면 쉽습니다.


circle.graphics.drawRect( 0, 0, DIAMETER, DIAMETER );

circle.graphics.drawCircle( RADIUS, RADIUS, RADIUS );


그냥 사각형을 그려주고 그다음에 원을 그려주면


겹치는 영역은 자동으로 색이 빠져버립니다.


동그라미 두개를 겹쳐서 그리면 겹치는 부분은 색이 빠지는 것과 같은 원리입니다.




메소드 저장해놓고 ㄱㄱ~




p.s) draw 이기 때문에 sand box type에 유의해야합니다. 

AIR 3 Release Candidate has been released a few days ago.

I've tried some test.

Here we go.

(You can download apk files and run it on your own Android phone.)




1. Toast, Notification, Vibrate, Beep, LCD

Download : ANEToast.apk - with captive runtime.[각주:1]





2. Play Ringtone Sounds.

Download : ANERingone.apk - with captive runtime.





3. Get my phone number.

Download : ANEPhoneNumber.apk - with captive runtime.





4. Get address book.

Download : ANEAddressList.apk - with captive runtime.









Conclusion 1. It's good more than I expected.

Conclusion 2. Not handy to create new Activity. I don't know exactly now.

Conclusion 3. Compile, packaging, install and launch on device is sucks now. You must do these on command line for now!! OMG. Thanks for ANT developers.



  1. Don't need AIR runtime. Just install it. [본문으로]

스타개발자 넓군은 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를 쓸 때

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




자 그렇다면 유추를 해보자

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 라고 한다. [본문으로]

+ Recent posts