在python中将大(十进制模块)浮点转换为二进制表示?

在python中将大(十进制模块)浮点转换为二进制表示?,python,math,Python,Math,因此,我试图从python decimal模块定义的十进制数中获取长序列位,目前是: Decimal('3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303

因此,我试图从python decimal模块定义的十进制数中获取长序列位,目前是:

Decimal('3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303820')
(顺便说一句,圆周率仅为200位。)

我希望整个过程以二进制表示,因此我可以将其转换为十六进制数数组,表示3以下的所有内容

有什么办法吗?我一直在浏览这个模块,但它似乎只提供了严格的十进制函数。

它可以用

有关
mpfr
类型支持的格式选项的详细信息,请使用
help(gmpy2.mpfr()


免责声明:我维护gmpy2。

我为这次碰撞表示歉意,但是对于仍然需要回答这个问题的任何人(使用十进制),可以编写自己的转换方法。它的效率不高,但如果在生成二进制数字时临时提高精度,它就足够精确了。任何基(大于1)中的数字都只是给定基幂的系数。下面的注释代码概述了将任何数字从十进制转换为任何其他基数(当然,如果新基数大于1)的整个过程。该算法适用于任何支持对数和浮点数的任意精度python模块

from decimal import *

def convert_base(x, new_base, preferred_digits=200):
    # ensure that x and new_base both have arbitrary precision
    x = Decimal(x)
    new_base = Decimal(new_base)

    # compute the log floor of x -- this is the exponent of the power of new_base of which the leading digit of x (in base new_base) is the coefficient
    # for example: pi in base 10 is 3.14159... but in base 2 it's 1*2 + 1*1 + 0*0.5 + ... which means exponent=1 because that sum starts with 2 raised to the power of exponent=1 (1*2^1 + ...)
    # further, log(pi) = 1.65... which means the floor is floor(log(pi)) = 1, so again, p=1.
    # in other words, exponent represents the largest exponent on the power of new_base where the power of new_base is less than or equal to the given x.
    exponent = (x.log10()/Decimal(new_base).log10()).__floor__()

    # we need a copy of this value to return it
    largest_exponent = exponent

    # start at the value of x
    # we will work our way down to 0, or get very close to it
    # ideally, we'll come up with a sufficient number of digits
    v = x
    
    # the list of digits that this function will return after populating it
    digits = []

    # keep decreasing v until it's extremely close to 0 (such that it becomes 0 with the provided precision) or the number of digits we generate reaches or exceeds our preferred_digits
    while v > 0 and len(digits) < preferred_digits:
        # the current power of new_base
        power = new_base ** exponent

        # compute the coefficient of the power (this is the next digit to add to digits)
        # we want this to be an integer, so we'll floor it
        coefficient = int(v / power)
        digits.append(coefficient)

        # since v is a sum of powers of new_base, we can now subtract power * coefficient from v, and we'll be left with the exact same problem as before, but we have obtained one digit
        # so we just rinse and repeat until we have enough digits, or all that there are in the converted representation
        v -= power * coefficient

        # to continue the process, we must make sure that the power of new_base is decreasing (so we increment p, the exponent of new_base, as power has -p as the exponent)
        # the whole point of using -p as the exponent to find the power of the new_base is to use multiplication in this loop instead of division (so it's slightly faster)
        exponent -= 1

    # we return digits, but also the largest exponent so we know where to put the "point" in the number
    # every number in any base is represented by a mantissa and an exponent.  here, largest_exponent is the exponent of the number's representation in base new_base
    # digits are part of the mantissa, so we've essentially converted x into base new_base
    return digits, largest_exponent


# we can also convert back to decimal from any base
# we just sum the products of the digits and the corresponding powers of from_base, based on exponent
def convert_to_decimal(digits, exponent, from_base):
    # again, from_base can have arbitrary precision
    from_base = Decimal(from_base)

    # start with a zero sum
    # this sum will yield our original x that we passed to convert_base()
    x = 0

    # create a copy of the exponent, but we do this so we don't have to modify the argument of the function itself (just a good practice)
    p = exponent

    # now we iterate over the digits, decreasing exponent (p) each time
    for d in digits:
        # compute the power
        power = from_base ** p

        # multiply by coefficient (current digit)
        product = power * d

        # add to the total sum
        x += product

        # decrease the exponent (p)
        p -= 1

    # the sum is now a decimal representation of number that has the given mantissa (digits) and exponent (exponent) in the given base (from_base)
    return x




digits, exponent = convert_base(Decimal('3.1415926535'), 2)

print(digits)
print(exponent)

reconverted = convert_to_decimal(digits, exponent, 2)

print(reconverted)

# some rounding errors of course, but that's nearly impossible to avoid
# one simple workaround is to temporarily increase the digits of precision by 2 or 3 digits for the conversion processes

希望这有帮助

Decimal
避开了以二进制存储数字的常规惯例,从而避免了浮点运算的复杂性,所以我想你想要什么二进制表示法?二进制中的十进制('3.14')
是什么?您想用“二进制”表示法做什么?您想实现自己的大数和算术计算格式吗?对于从10阶到200阶的数字,您想要什么“二进制”格式即使是
mpmath
bigfloat
只提供值到字符串的转换,除了IEEE单格式和双格式之外,我找不到任何任意精度的浮点到二进制表示。您必须在这里提出自己的解决方案。@MartijnPieters使用
gmpy2
可以很容易地做到这一点。我也添加了一个答案。@casevh:那大概是一个专有的表述吧。
from decimal import *

def convert_base(x, new_base, preferred_digits=200):
    # ensure that x and new_base both have arbitrary precision
    x = Decimal(x)
    new_base = Decimal(new_base)

    # compute the log floor of x -- this is the exponent of the power of new_base of which the leading digit of x (in base new_base) is the coefficient
    # for example: pi in base 10 is 3.14159... but in base 2 it's 1*2 + 1*1 + 0*0.5 + ... which means exponent=1 because that sum starts with 2 raised to the power of exponent=1 (1*2^1 + ...)
    # further, log(pi) = 1.65... which means the floor is floor(log(pi)) = 1, so again, p=1.
    # in other words, exponent represents the largest exponent on the power of new_base where the power of new_base is less than or equal to the given x.
    exponent = (x.log10()/Decimal(new_base).log10()).__floor__()

    # we need a copy of this value to return it
    largest_exponent = exponent

    # start at the value of x
    # we will work our way down to 0, or get very close to it
    # ideally, we'll come up with a sufficient number of digits
    v = x
    
    # the list of digits that this function will return after populating it
    digits = []

    # keep decreasing v until it's extremely close to 0 (such that it becomes 0 with the provided precision) or the number of digits we generate reaches or exceeds our preferred_digits
    while v > 0 and len(digits) < preferred_digits:
        # the current power of new_base
        power = new_base ** exponent

        # compute the coefficient of the power (this is the next digit to add to digits)
        # we want this to be an integer, so we'll floor it
        coefficient = int(v / power)
        digits.append(coefficient)

        # since v is a sum of powers of new_base, we can now subtract power * coefficient from v, and we'll be left with the exact same problem as before, but we have obtained one digit
        # so we just rinse and repeat until we have enough digits, or all that there are in the converted representation
        v -= power * coefficient

        # to continue the process, we must make sure that the power of new_base is decreasing (so we increment p, the exponent of new_base, as power has -p as the exponent)
        # the whole point of using -p as the exponent to find the power of the new_base is to use multiplication in this loop instead of division (so it's slightly faster)
        exponent -= 1

    # we return digits, but also the largest exponent so we know where to put the "point" in the number
    # every number in any base is represented by a mantissa and an exponent.  here, largest_exponent is the exponent of the number's representation in base new_base
    # digits are part of the mantissa, so we've essentially converted x into base new_base
    return digits, largest_exponent


# we can also convert back to decimal from any base
# we just sum the products of the digits and the corresponding powers of from_base, based on exponent
def convert_to_decimal(digits, exponent, from_base):
    # again, from_base can have arbitrary precision
    from_base = Decimal(from_base)

    # start with a zero sum
    # this sum will yield our original x that we passed to convert_base()
    x = 0

    # create a copy of the exponent, but we do this so we don't have to modify the argument of the function itself (just a good practice)
    p = exponent

    # now we iterate over the digits, decreasing exponent (p) each time
    for d in digits:
        # compute the power
        power = from_base ** p

        # multiply by coefficient (current digit)
        product = power * d

        # add to the total sum
        x += product

        # decrease the exponent (p)
        p -= 1

    # the sum is now a decimal representation of number that has the given mantissa (digits) and exponent (exponent) in the given base (from_base)
    return x




digits, exponent = convert_base(Decimal('3.1415926535'), 2)

print(digits)
print(exponent)

reconverted = convert_to_decimal(digits, exponent, 2)

print(reconverted)

# some rounding errors of course, but that's nearly impossible to avoid
# one simple workaround is to temporarily increase the digits of precision by 2 or 3 digits for the conversion processes
from mpmath import *

def convert_base(x, new_base, preferred_digits=200):
    x = mpf(x)
    new_base = mpf(new_base)
    exponent = int(floor(log(x)/log(new_base)))
    largest_exponent = exponent
    v = x
    digits = []
    while v > 0 and len(digits) < preferred_digits:
        power = new_base ** exponent
        coefficient = int(v / power)
        digits.append(coefficient)
        v -= power * coefficient
        exponent -= 1
    return digits, largest_exponent

def convert_to_decimal(digits, exponent, from_base):
    from_base = mpf(from_base)
    x = 0
    p = exponent
    for d in digits:
        power = from_base ** p
        product = power * d
        x += product
        p -= 1
    return x



digits, exponent = convert_base(mpf('3.1415926535'), 2)

print(digits)
print(exponent)

reconverted = convert_to_decimal(digits, exponent, 2)

print(reconverted)

# still some rounding errors with mpmath, but they're not displayed because it's smart
import timeit

decimal_time = timeit.timeit('using_decimal.convert_base(3.1415926535, 2, 200)', number=10000, setup='import using_decimal')
mpmath_time = timeit.timeit('using_mpmath.convert_base(3.1415926535, 2, 200)', number=10000, setup='import using_mpmath')

print(f'decimal time: {decimal_time} seconds')
print(f'mpmath time: {mpmath_time} seconds')
print('Speed improvement: {:+.1f}%'.format((decimal_time-mpmath_time)*100./mpmath_time))
decimal time: 4.2381332 seconds
mpmath time: 3.4054762 seconds
Speed improvement: +24.5%