Victor
Victor

Reputation: 1879

Convert three bytes, two's complement, signed integer

In the SEG-D seismic data format, some header parameters are formatted as three bytes, two’s complement, signed binary. All values are big-endian.

Using String#unpack, Ruby core can only convert 16-bit and 32-bit values, but not 24-bit.

How can I get the binary values converted into integers in the following two’s complement way:

"\x00\x00\x00" => 0x000000 (0)
"\x00\x00\x01" => 0x000001 (1)
"\x7F\xFF\xFF" => 0x7FFFFF (8388607)
"\xFF\xFF\xFF" => -0x000001 (-1)
"\x80\x00\x00" => -0x800000 (-8388608)

Upvotes: 1

Views: 740

Answers (1)

Victor
Victor

Reputation: 1879

Convert the fist byte as signed 8-bit (two’s complement) and the second and third as unsigned 16-bit.

# String to be converted (-8388608)
bin = "\x80\x00\x00"

# Convert as signed 8-bit and unsigned 16-bit (big-endian)
values = bin.unpack("c S>")

# Add with the first byte weighted
converted = values[0] * 2**16 + values[1]

Alternate version of the last line using bitwise operations shift and OR (probably more efficient):

converted = values[0] << 16 | values[1]

Upvotes: 3

Related Questions