NTP 타임스탬프에 Decimal Fractional Part에 대한 의문점 해소

NTP 타임스탬프 보다가 도저히 이해가 가지 않는 부분이 있었는데 진짜 간단한거 였는데 괜한 삽질만 했군요.

타임스탬프에 Decimal Fractional Part를 구할때 저는

int tmp = 0;
double result = 0;
for (int i=0; i<32; i++)
{
tmp = aa >> (31 - i);
if (tmp > 0)
{
result +=  (double)1.0 / Math.Pow(2, (i+1));
}
}
result *= 1000;

이런식으로 구해야 한다고 생각했는데
인터넷을 찾아보면 죄다

ulong milliseconds = intpart * 1000 + (fractpart * 1000) / 0x100000000L;

이걸 쓰더군요.
fractpart에 1000을 곱하는건 밀리세컨드로 바꾸느라 그런건데
저 0x100000000L로 나누는건 대체 뭔가 한참 고민했는데 (그리고 과연 이게 맞는건가 하는것도)

결론만 말하자면 저 0x100000000L은 >> (4*8) 하라는 비트연산이랑 같은거였더군요

예를 들어 설명해보죠.
0.34를 비트로 풀어보면

0.34*2 = 0.68 …0
0.68*2 = 1.36 …1
0.36*2 = 0.72 …0
0.72*2 = 1.44 …1

0.44*2 = 0.88 …0
0.88*2 = 1.76 …1
0.76*2 = 1.52 …1
0.52*2 = 1.04 …1

0.04*2 = 0.08 …0
0.08*2 = 0.16 …0
0.16*2 = 0.32 …0
0.32*2 = 0.64 …0

0.64*2 = 1.28 …1
0.28*2 = 0.56 …0
0.56*2 = 1.12 …1
0.12*2 = 0.24 …0

0.24*2 = 0.48 …0
0.48*2 = 0.96 …0
0.96*2 = 1.92 …0
0.92*2 = 1.84 …1

0.84*2 = 1.68 …1
0.68*2 = 1.36 …1
0.36*2 = 0.72 …0

0.72*2 = 1.44 …1

0.44*2 = 0.88 …0
0.88*2 = 1.76 …1
0.76*2 = 1.52 …1
0.52*2 = 1.04 …1

0.04*2 = 0.08 …0
0.08*2 = 0.16 …0
0.16*2 = 0.32 …0
0.32*2 = 0.64 …0

즉 0101 0111 0000 1010 0001 1101 0111 0000 입니다.

계산하기 편하게 계산기를 뚜두려봅시다.
여기다가 1000을 곱하면 (세컨드에서 밀리세컨드로 변환하니)

그럼 2진수로 0001 0101 0011 1111 1111 1000 0010 1111 1101 1000 0000
이 나오는데 여기서 >>(4*8) 를 해주면 0001 0101 0011 이게 남습니다.

여기서 의문 왜 32비트를 시프팅 해주냐
제 추측은 Fixed Point를 32:32으로 했으니 *1000을 함으로써 소수점 이하 3자리가 정수부분으로 올라왔으니
소수부분이었던 하위 32비트를 날리는걸로 생각합니다.

339가 나옵니다.
0.34*1000했으니 340나와야 하는거 아니냐고요.

http://linsoo.co.kr/archives/13865

여기에서 말했듯이 컴터에서 소수점 처리에는 오차가 있습니다.
32비트 말고 더 길게 늘리면 좀 더 정확한 수치가 나올텐데 뭐 어차피 컴터 시계 세팅하는데 1밀리세컨드까지 고집할 필욘 없겠죠.

이렇게 의문점 하나 해소!


크리에이티브 커먼즈 라이선스Linsoo의 저작물인 이 저작물은(는)크리에이티브 커먼즈 저작자표시-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.

댓글 남기기

이메일은 공개되지 않습니다.

This site uses Akismet to reduce spam. Learn how your comment data is processed.