【问题标题】:How I can see the actual bit sequence of 0.1 in Python?如何在 Python 中查看 0.1 的实际位序列?
【发布时间】:2020-12-20 05:20:23
【问题描述】:

问题

如何可视化存储在 Python 内存中的 64 位二进制格式的浮点数 0.1,如图所示?一个 Python 代码,可以显示符号位、指数位和精度位,例如 (1,01010110111,1010101...)。

背景

浮点数需要用二进制位表示,据我从文章中了解到,它是 ± p × 2**e 其中±是 i 1 位,p 是 52 位精度,e 是 11 位的指数.

我想(3 * 0.1 == 0.3) is False的原因是因为0.1不能用64位表示,而在Python中它是0.1000000000000000055511151231257827021181583404541015625十进制。

print(3 * 0.1 == 0.3)     # False
print(0.3 * 1 == 0.3)     # True

print("%0.55f" % (1.0 / 10))
-----
0.1000000000000000055511151231257827021181583404541015625

print("%0.55f" % (0.1000000000000000055511151231257827021181583404541015625 - 0.1))
-----
0.0000000000000000000000000000000000000000000000000000000

但是,仍然无法理解它是如何工作的,并想看看它在二进制格式中的样子。

【问题讨论】:

    标签: python binary


    【解决方案1】:

    您可以使用struct 模块将浮点值打包到缓冲区中。 "d" format string 给出一个 8 字节的 double

    import struct
    
    x = float(0.1)
    buf = struct.pack("d", x)
    print(buf)  # b'\x9a\x99\x99\x99\x99\x99\xb9?'
    
    # Hex dump, for readability
    print(" ".join("{:02X}".format(b) for b in buf))  # 9A 99 99 99 99 99 B9 3F
    

    缓冲区将反映系统的本机字节顺序。您还可以在格式字符串中试验byte-order specifiers

    您还可以将相同的字节重新解释为整数。为此,您可以使用相同大小(8 字节)的无符号整数类型。在这种情况下,它将是long long 无符号整数(格式字符串"Q"):

    # Interpret bytes as unsigned integer.
    i, = struct.unpack("Q", buf)
    print("{:0>16X}".format(i))  # 3FB999999999999A
    

    最后,如果您愿意,您可以将缓冲区解释为 double,并确认该值在往返序列化中仍然存在:

    x2, = struct.unpack("d", buf)
    print(x2)       # 0.1
    print(x2 == x)  # True
    

    查看浮点表示组件

    要查看浮点数的各个组成部分,您可以使用位掩码检查整数等效部分。

    import struct
    
    x = -(16 + 4 + 2 + 1 + 0.5)
    buf = struct.pack("d", x)
    i, = struct.unpack("Q", buf)
    

    这里,x 的值为 -0b10111.1,或等效为 -0b1.01111 * 2^4

    关于IEEE 753 representation有两个重要说明:

    • 指数的偏差为 1023,因此我们预计指数中存储的值为 1027。
    • 尾数的前导 1 是隐式的,因此我们期望尾数位为 01111

    我们可以对问题中显示的位模式使用适当的掩码,然后以二进制形式打印

    print(format(i, '0>64b'))
    
    SIGN_MASK = 0x8000000000000000
    EXPN_MASK = 0x7FF0000000000000
    MANT_MASK = 0x000FFFFFFFFFFFFF
    print(format(i & SIGN_MASK, '0>1b')[:1])
    print(format(i & EXPN_MASK, '0>11b')[:11])
    print(format(i & MANT_MASK, '0>52b'))
    

    结果:

    1100000000110111100000000000000000000000000000000000000000000000
    1
    10000000011
    0111100000000000000000000000000000000000000000000000
    

    【讨论】:

    • 感谢您对模块的信息性回答。您是否还可以帮助我了解如何使用该模块查看指数精密零件?
    • 完成:您可以将位掩码应用于与位模式等效的整数。
    猜你喜欢
    • 1970-01-01
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-18
    • 2016-11-08
    • 2023-02-24
    • 2011-05-23
    相关资源
    最近更新 更多