Python浮动到32位有限数量

时间:2017-01-27 02:00:32

标签: python python-3.x

如本网站所示:https://www.h-schmidt.net/FloatConverter/IEEE754.html

我已经查看过堆栈溢出的五个左右的帖子,但它们并不是我想要的。例如:

import struct

getBin = lambda x: x > 0 and str(bin(x))[2:] or "-" + str(bin(x))[3:]

def floatToBinary64(value):
    val = struct.unpack('Q', struct.pack('d', value))[0]
    return getBin(val)

def binaryToFloat(value):
    hx = hex(int(value, 2))   
    return struct.unpack("d", struct.pack("q", int(hx, 16)))[0]

# floats are represented by IEEE 754 floating-point format which are 
# 64 bits long (not 32 bits)

# float to binary
binstr = floatToBinary64(NUMBER)
print('Binary equivalent of .1:')
print(binstr + '\n')

# binary to float
fl = binaryToFloat(binstr)
print('Decimal equivalent of ' + binstr)
print(fl)

我意识到这与我正在寻找的非常接近。如果你将.1放入这个数字所在的代码中,它会将它列为.1,而在网站上它给我:0.10000000149011612。

如果有人能提供帮助那就太棒了!

2 个答案:

答案 0 :(得分:2)

这只是因为Python向您展示了该数字的最佳表示。这个值实际上是这样的:

>>> '%.60f' % fl
'0.100000000000000005551115123125782702118158340454101562500000'

这正是文字0.1变成的:

>>> '%.60f' % 0.1
'0.100000000000000005551115123125782702118158340454101562500000'

(哦,它不是0.10000000149011612因为用32而不是64位完成。实际上那个应该是0.100000001490116119384765625,转换器页面不准确。)

答案 1 :(得分:1)

您可以使用gmpy2库来处理任意精度二进制数,包括标准的32位和64位IEEE格式。

以下是一个例子:

>>> import gmpy2
>>> gmpy2.set_context(gmpy2.ieee(64))
>>> gmpy2.mpfr("0.1").__format__(".60f")
'0.100000000000000005551115123125782702118158340454101562500000'
>>> gmpy2.set_context(gmpy2.ieee(32))
>>> gmpy2.mpfr("0.1").__format__(".60f")
'0.100000001490116119384765625000000000000000000000000000000000'

编辑:添加了将mpfr转换为32位IEEE格式的示例函数。

import gmpy2
gmpy2.set_context(gmpy2.ieee(32))

def mpfr_to_float(x):
    '''Convert an mpfr object created by the IEEE 32-bit compatible
    context to a 32 character string containing 0 and 1.'''

    # Check for special values first.

    if gmpy2.is_infinite(x):
        if gmpy2.is_signed(x):
            return "1" * 9 + "0" * 23
        else:
            return "0" + "1" * 8 + "0" * 23

    if gmpy2.is_nan(x):
        return "0" + "1" * 31

    if gmpy2.is_zero(x):
        if gmpy2.is_signed(x):
            return "1" + "0" * 31
        else:
            return "0" * 32

    # Extract the mantissa, exponent, and precision. Note that the
    # values are slightly different than the IEEE 32-bit standard.

    mnt, exp, prc = x.digits(2)

    # MPFR explicitely stores the leading bit of the mantissa so the
    # precision is 24. To support subnormals, MPFR also uses a more
    # negative minimum exponent and decreases the precision of the
    # mantissa but maintains the leading '1' bit.

    # Remove any leading sign bit from the mantissa string.
    if mnt[0] == "-":
        sign_char = "1"
        mnt = mnt[1:]
    else:
        sign_char = "0"

    # Check for subnormals
    if exp + 126 <= 0:
        # Drop the last bit since it will always be '0' and after the
        # adjustments for subnormals, the leading bit will be '0'.
        mnt = mnt[:-1]
    else:
        # Drop the leading '1' bit for normal numbers.
        mnt = mnt[1:]

    # Handle subnormals by shifting trailing bits from the mantissa
    # string to the beginning. Adjust the exponent to match.
    while exp + 126 < 0:
        mnt = mnt[-1] + mnt[:-1]
        exp = exp + 1

    # Adjust the exponent to account for removing a bit from the
    # mantissa string.
    exp = exp - 1

    # Add 127 to the exponent to account for the IEEE encoding.
    exp = exp + 127

    # Validate exponent range.
    if (exp > 255) or (exp < 0):
        raise ValueError("exp is out of bounds")

    # Build and return the binary string.
    result = sign_char + format(exp, "08b") + mnt
    if len(result) != 32:
        raise ValueError("something is wrong....")

    return result


if __name__ == "__main__":
    print(mpfr_to_float(gmpy2.mpfr("0.1")))

免责声明#1:这应该是对@Stefan Pochmann的答案的评论,但我认为代码示例会有所帮助。

免责声明#2:我维持gmpy2。