【问题标题】:two's complement of numbers in pythonpython中数字的二进制补码
【发布时间】:2014-03-19 06:32:16
【问题描述】:

我正在编写的代码将包含所有 16 位长的负数和正数,其中 MSB 是符号,也就是二进制补码。这意味着我可以拥有的最小数字是 -32768,即 1000 0000 0000 0000 的二进制补码形式。我能拥有的最大数字是 32767,即 0111 1111 1111 1111

我遇到的问题是 python 用与正数相同的二进制表示法表示负数,只是在前面加上一个减号,即 -16384 显示为 -0100 0000 0000 0000 我想要的对于像 -16384 这样的数字,要显示的是 1100 0000 0000 0000

我不太确定如何编码。这是我的代码。本质上,如果该数字在 180 到 359 之间,它将为负数。我需要将其显示为二进制恭维值。我没有任何关于如何显示它的代码,因为我真的不知道该怎么做。

def calculatebearingActive(i):

    numTracks = trackQty_Active
    bearing = (((i)*360.0)/numTracks)
    if 0< bearing <=179:
        FC = (bearing/360.0)
        FC_scaled = FC/(2**(-16))
        return int(FC_scaled)

    elif 180<= bearing <=359:
        FC = -1*(360-bearing)/(360.0)
        FC_scaled = FC/(2**(-16))
        return int(FC_scaled)

    elif bearing ==360:
        FC = 0
        return FC

【问题讨论】:

  • 您是只关心显示还是还想执行计算?
  • 不看你的代码就很难找到你的bug。
  • 你为什么坚持要把'complement'编辑成'compliment'?
  • 为什么不使用实际的 16 位数字类型? Numpy 有它们。

标签: python twos-complement


【解决方案1】:

如果你正在做类似的事情

format(num, '016b')

要将您的数字转换为二进制补码字符串表示,您需要在字符串化之前实际获取负数的二进制补码:

format(num if num >= 0 else (1 << 16) + num, '016b')

或者接受 mod 65536:

format(num % (1 << 16), '016b')

【讨论】:

  • format(num if num &gt;= 0 else (1 &lt;&lt; 16) - num, '016b')num=-16384 得到 '10100000000000000',而 OP 想要 '1100 0000 0000 0000'
  • @zhangxaochen:哎呀。 - 必须是 +。固定。
  • 这正是我想要的。非常感谢你
  • 您也可以使用位掩码执行format(num &amp; 0xffff, '016b')
【解决方案2】:

一个值的补码是一个补码加一。

您可以基于此编写自己的转换函数:

def to_binary(value):
    result = ''
    if value < 0:
        result = '-'
        value = ~value + 1
    result += bin(value)
    return result

结果如下:

>>> to_binary(10)
'0b1010'
>>> to_binary(-10)
'-0b1010'

编辑:要显示前面没有减号的位,您可以使用此功能:

def to_twoscomplement(bits, value):
    if value < 0:
        value = ( 1<<bits ) + value
    formatstring = '{:0%ib}' % bits
    return formatstring.format(value)

>>> to_twoscomplement(16, 3)
'0000000000000011'
>>> to_twoscomplement(16, -3)
'1111111111111101'

【讨论】:

    【解决方案3】:

    以下是在 python 中以二进制形式打印补码(1s 和 2s)时的一些注意事项:

    UNSIGNED RANGE:      0 to (2^k)-1 for k bit number 
                   ex:   0 to (2^32)-1 numbers
                   ex:   0 to 7 for 3 bit unsigned numbers (count = 8)
    
    SIGNED RANGE:       -2^(k-1) to +2^(k-1)-1 for 1+k bit number (k-1 is for dividing current range k into two equal half)
                   ex:  -2^31 to +(2^31)-1 numbers  
                   ex   -8 to +7 for 1+3 bit signed numbers (count = 8)
    
    
    bin(int)->str converts an integer to binary string
       CAVEAT: 1. Since in python there is no limit to length of integer
               for ~x or !x (1s_complement/not/negate) we can't determine how many bits after MSB needs to be 1
               so python just prints out unsigned value of target negative number in binary format with a
               '-' sign in the beginning
               ex: for x = b'01010'(10) we get ~x = -0b'1011' (-11) 
                   but we should be getting -16+5 = -11 
                   (-b'10000'+b'00101') = -b'10101' (-11 signed) or (21 unsigned)
                   to get real binary value after negation(or 1s complement) one could simulate it
                   NOTE:  2^0 is always 1, so (2**0 == 1) in python
                   NOTE:  (1 << k) is always 2^k (left shift is 2 raised to the power k)
                   ex: bin((1 << k)-1 - x) which is ((2^k)-1)-x  (1s complement)
                   ex: bin((1 << k)-1 - x) + 1 which is (2^k)-x  (2s complement)
              2. Same goes for reverse parsing of signed binary string to int: 
                 ex: int("-0b'0101'", 2) gives -5 but instead it actually is -11 assuming -0b represents all bits 
                     from MSB till current to be like 1111......0101 which is actually -16+5 = -11
                     BUT due to PYTHON's limitation of representing signed binary values we need to adhere to 
                     current way of parsing considering unsigned binary strings with sign in front for -ve numbers
    
    # NOTE: how the significant prefix zeros doesn't matter in both +ve and -ve cases
    
    # Byte type inputs
    x = b'+1010'            # valid +ve number byte string
    x = b'1010'             # valid +ve number byte string
    x = b'-1010'            # valid -ve number byte string
    x = b'+01010'           # valid +ve number byte string
    x = b'01010'            # valid +ve number byte string
    x = b'-01010'           # valid -ve number byte string
    
    int(b'101')             # interprets as base 10 for each digit
    int(b'101', 2)          # interprets as base 2 for each digit
    int(b'101', 8)          # interprets as base 8 for each digit
    int(b'101', 10)         # interprets as base 10 for each digit
    int(b'101', 16)         # interprets as base 16 for each digit
    
    # String type inputs
    x = '+1010'            # valid +ve number string
    x = '1010'             # valid +ve number string
    x = '-1010'            # valid -ve number string
    x = '+01010'           # valid +ve number string
    x = '01010'            # valid +ve number string
    x = '-01010'           # valid -ve number string
    
    int('101')             # interprets as base 10 for each digit
    int('101', 2)          # interprets as base 2 for each digit
    int('101', 8)          # interprets as base 8 for each digit
    int('101', 10)         # interprets as base 10 for each digit
    int('101', 16)         # interprets as base 16 for each digit
    
    # print(bin(int(x, 2)), int(x,2), ~int(x, 2), bin(~int(x,2)), "-"+bin((1<<k)-1 - int(x,2)))
    
    
    k = 5                   # no of bits
    assert 2**0 == 1        # (2^0 is always 1)
    _2k = (1 << k)          # (2^k == left shift (2^0 or 1) by k times == multiply 2 by k times)
    x = '01010'             # valid +ve number string
    x = int(x,2)
    print("input:", x)      # supposed to be 1s complement of binStr but due to python's limitation, 
                            # we consider it -(unsigned binStr)
    _1s = '-'+bin((_2k-1)-x)
    print("1s complement(negate/not): ", _1s, ~x)
    _2s = '-'+bin(_2k-x)
    print("2s complement(1s +1):      ", _2s, ~x+1)
    
    output:
    k = 5 (5 bit representation)
    input: 10
    1s complement(negate/not):  -0b10101 -11
    2s complement(1s +1):       -0b10110 -10
    
    k=32 (32 bit representation)
    input: 10
    1s complement(negate/not):  -0b11111111111111111111111111110101 -11
    2s complement(1s +1):       -0b11111111111111111111111111110110 -10
    

    【讨论】:

      【解决方案4】:

      如果你真的想用 16 位存储数字,你可以使用 struct。

      import struct
      
      >>> struct.pack('h', 32767)
      '\xff\x7f'
      >>> struct.pack('h', -32767)
      '\x01\x80'
      

      你可以使用unpack解压

      >>> a = struct.pack('h', 32767)
      >>> struct.unpack('H', a)
      32767
      

      【讨论】:

      • 如果一个接口要解包,它会看到一个二进制的恭维数吗?我的意思是它会知道打包的值是负数吗?
      【解决方案5】:

      由于您没有给出任何代码示例,我无法确定发生了什么。根据您示例中的数字,我认为您没有使用bin(yourint),因为您的输出不包含0b。也许你已经在你的例子中削减了它。

      如果您将二进制数据存储为字符串,您可以执行以下操作:

          def handle_negatives(binary_string):
              If binary_string < 0:
                  binary_string = '1' + str(binary_string)[1:]
              Return binary_string
      

      【讨论】:

        猜你喜欢
        • 2010-12-08
        • 1970-01-01
        • 2014-12-25
        • 1970-01-01
        • 2019-08-04
        • 2021-04-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多