2011-11-20 2 views
1

UDP (200 비트 단위)를 통해 매우 긴 이진 정수를 보내려고합니다. 배열의 pack 메소드를 사용하려고하면 변환하려고하는 문자열이 너무 큽니다.Ruby에서 긴 이진 정수 패킹

내가 잘못 생각하고 있습니까?

ruby-1.8.7-p352 :003 > [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i') 
RangeError: bignum too big to convert into `unsigned long' 
from (irb):3:in `pack' 
from (irb):3 

이 번호는 DNS 쿼리 패킷을 표현하도록되어 (이 숙제입니다, 우리는 어떤 DNS 라이브러리를 사용할 수 없습니다 것).

답변

-1

루비 1.9.3이 정상적으로 작동합니다.

irb(main):001:0> [0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101].pack('i') 
=> "UU\xBD\xAA" 
+0

이 버전은 오류없이 상당한 비트 수를 제거합니다. 예제는 다음과 같습니다 :'[b1010_1010_1011_1101_0101_0101_0101_0101] .pack ("i"). – WarHog

4

숫자를 더 작은 조각으로 나누어야합니다. 아마 가장 좋은 한 번에 32 비트를 인코딩하는 것입니다

> num = 0b1101001010101101111010100101010011010101010110010101010101010010010101001010101010101011101010101010101111010101010101010101 
=> 17502556204775004286774747314501014869 
> low_1 = num & 0xFFFFFFFF 
=> 2864534869 
> low_2 = (num >> 32) & 0xFFFFFFFF 
=> 625650362 
> low_3 = (num >> 64) & 0xFFFFFFFF 
=> 1297454421 
> low_4 = (num >> 96) & 0xFFFFFFFF 
=> 220913317 
> (low_4 << 96) + (low_3 << 64) + (low_2 << 32) + low_1 
=> 17502556204775004286774747314501014869 
> msg = [low_4, low_3, low_2, low_1].pack("NNNN") 
=> "\r*\336\245MU\225U%J\252\272\252\275UU" 
> msg.unpack("NNNN").inject {|sum, elem| (sum << 32) + elem} 
=> 17502556204775004286774747314501014869 

나는 다른 플랫폼으로 훨씬 쉽게 interopation을 만드는, 당신은 Network Byte Order 이러한 팩을하기 때문에 여기 32 비트를 선호합니다. pack() 메서드는 네트워크 바이트 순서 64 비트 정수를 제공하지 않습니다. POSIX는 64 비트 루틴을 제공하지 않으므로 놀랍지는 않습니다.

+1

#inject 블록의 두 번째'sum'은'elem'이어야합니다. – Patrik

+0

@Patrik, 당신은 틀린 것입니다. 나는 매우 당혹 스럽다. 수정 해줘서 고마워. – sarnold

+0

괜찮습니다! 그것은 일어난다. :-) – Patrik