【问题标题】:Convert three bytes, two's complement, signed integer转换三个字节、二进制补码、有符号整数
【发布时间】:2019-01-05 23:38:36
【问题描述】:

SEG-D seismic data format中,一些头部参数被格式化为三个字节,二进制补码,有符号二进制。所有值都是大端的。

使用String#unpack,Ruby 核心只能转换 16 位和 32 位值,不能转换 24 位。

如何通过以下two’s complement 方式将二进制值转换为整数:

"\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)

【问题讨论】:

    标签: ruby endianness signed twos-complement 24-bit


    【解决方案1】:

    将第一个字节转换为有符号 8 位(二进制补码),将第二个和第三个字节转换为无符号 16 位。

    # 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]
    

    使用按位运算 shiftOR 的最后一行的替代版本(可能更有效):

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

    【讨论】:

    • 我非常尊重任何理解pack/unpack的人。我不止一次尝试过要掌握它,但总是在几分钟后因头痛欲裂而放弃。考虑以下调整:values[0] &lt;&lt; 16 + values[1]。见Integer#<<
    • @CarySwoveland 确实更优雅,但我只私下使用&lt;&lt; 和其他按位运算。对于初学者来说,它们非常神秘。 :-)
    • 如果一个 Rubiest 理解 pack/unpack,这是一个合理的假设,即他们知道 Integer#&lt;&lt;(以及元编程的微妙之处)。
    • @CarySwoveland 谈到微妙之处:(values[0] &lt;&lt; 16) + values[1] ;-)
    • @CarySwoveland 另一种选择是使用二进制 OR 而不是加号,即values[0] &lt;&lt; 16 | values[1]。或a, b = bin.unpack('c S&gt;')a &lt;&lt; 16 | b。或单线bin.unpack('c S&gt;').yield_self { |a, b| a &lt;&lt; 16 | b }
    猜你喜欢
    • 2020-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-16
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多