2012-11-18 4 views
1

예를 들어 'C4D81633'의 16 진수를 부호있는 2의 보수로 변환하려면 어떻게합니까? 예 : '-992471501'? 나는 16 진수로 부호가있는 2의 보수

['C4D81633'.scan(/[0-9a-f]{2}/i).reverse.join].pack('H*').unpack('l') 

을 시도했지만 나는 8 자 이하 길이의 입력을 줄 때 위의 코드는 잘 작동하지 않습니다.

답변

0

나는 인터넷 검색을 한 후 답을 발견 (귀하의 의견은 8 자리보다 긴 경우를 제외하고) 8 개 진수 숫자를 가지고 ... 나는 다음과 방법으로 추가

def convert_to_signed_twos_complement(integer_value, num_of_bits) 
    length  = num_of_bits 
    mid   = 2**(length-1) 
    max_unsigned = 2**length 
    (integer_value >= mid) ? integer_value - max_unsigned : integer_value 
end 

hex_to_convert = 'C4D81633' 
convert_to_signed_twos_complement(hex_to_convert.hex, 16) 

Note: the num_of_bits in method denote the max bit size of the binary you want 
+0

나는 작은 문자열 (예 : 'EC'는 -20으로 반환 됨)에서 작동하므로이 방법이 마음에 듭니다. – shivashankar

1

먼저 String#rjust을 입력에 사용하는 것이 어떻습니까?

['C4D81633'.rjust(8,'0').scan(/[0-9a-f]{2}/i).reverse.join].pack('H*').unpack('l') 

이 방법, 당신은 항상

6

부정 연산자 (-는) 이미 않는 두 가지의 칭찬 :

p (-0x1234).to_s(16) # => "-1234" 

문제는 Ruby의 to_s입니다. Ruby의 to_s는 부정적이라는 것을 알게되고 거의 항상 원하는 방식으로 출력합니다. 빼기 기호가 있습니다.

p (-0x1234 & 0xffff).to_s(16) # => "edcc" 

을 그럼 모두 함께 넣어 보자 : 나는 실제 작업을하는 것이 좋습니다

def negate(n, num_bits) 
    mask = (1 << num_bits) - 1 
    -n & mask 
end 

def negate_string(s, num_bits) 
    negate(s.hex, num_bits).to_s(16) 
end 

p negate_string("C4D81633", 32) # "3b27e9cd" 
2

을 우리는 부정 값을 마스크 경우

하지만, 우리는 루비가 우리가 원하는 것을 할거야 가능할 때 전화 번호. 따라서 "문자열 화 된 16 진수"를 가져 와서 실제 정수로 변환하십시오. (다른 사람들이 제안한대로, 'C4D81633'.hex). 나는이 방법을 몇 번 반복했다. 첫 번째는 @ shivashankar의 것이며 다른 하나는 속도 향상입니다. 블랙 박스로 만들고 싶다면 마지막으로 성능을 얻으십시오. 여기

def signed_twos_complement(integer_value, num_bits) 
    length = num_bits 
    mid = 2**(length-1) 
    max_unsigned = 2**length 
    (integer_value >= mid) ? integer_value - max_unsigned : integer_value 
end 

def signed_twos_complement2(i) 
    -(-i & (2**i.to_s(2).length)-1) 
end 

def signed_twos_complement3(i) 
    -(-i & (2**i.bit_length)-1) 
end 

def signed_twos_complement4(i, bits=i.bit_length) 
    -(-i & (2**bits)-1) 
end 

# Run chunk below in irb or pry to try benchmarking for yourself 
require 'benchmark' 
n = 9000000 
a = Array.new(n) { rand(1...n) }; 

Benchmark.bm do |x| 
    x.report { a.each { |z| signed_twos_complement(z, z.to_s(2).length) } } 
    x.report { a.each { |z| signed_twos_complement(z, z.bit_length) } } 
    x.report { a.each { |z| signed_twos_complement2(z) } } 
    x.report { a.each { |z| signed_twos_complement3(z) } } 
    x.report { a.each { |z| signed_twos_complement4(z) } } 
end 

내 벤치 마크 실행에서

user  system  total  real 
6.250000 0.040000 6.290000 ( 6.355923) 
2.290000 0.010000 2.300000 ( 2.347434) 
5.840000 0.040000 5.880000 ( 5.943748) 
2.160000 0.010000 2.170000 ( 2.223785) 
2.160000 0.020000 2.180000 ( 2.218012) 

편집 내 결과입니다 : 나는 좀 더 확장 될 signed_twos_complement4을 추가했다. 고급 보완을 위해 원하는 비트를 무시할 수 있습니다.