Convert very large base number n to bytes
I have a very large number in a database n
( n
user supplied) stored as an array with each element representing a digit. u[0]
- the highest digit, u[1]
- the second largest, u[-1]
- the least significant digit, and so on. Leading zeros are understood to be meaningless: for example, if n
is 8, it is [0, 0, 0, 4, 7, 3]
equivalent [4, 7, 3]
and both are (473) in base 8 or 315 in base 10, either 13B
in hexadecimal, or [1, 59]
as a byte array.
I want to convert this to an array of bytes that match the base-256 representation of the same number with minimal leading zeros. I have the following code:
def base_n_to_byte_array(digits, from_base):
""" Converts a base n number to a byte array.
:param digits: Digits of the number, starting from highest.
:param from_base: Base in which the number is given.
"""
x = 0
n = len(digits)
for i in range(0, len(digits)):
x += digits[i] * int(math.pow(from_base, n - i - 1))
min_length = max(math.ceil(math.log(x, 256)), 1)
byte_array = x.to_bytes(min_length, byteorder='big')
return byte_array
This works for smaller numbers (several hundred digits). However, it turns out to be math.pow
quite limited, for example if we use base 8 math.pow(8, 341)
is the highest cardinality I can get while math.pow(8,342)
failing with OverflowError: math range error
.
I know that the general way to work with large numbers is to represent them as floating points, but in this case, I use this code to encode / decode binaries into alternate representations (like trytes). Therefore, if less significant bytes change due to loss of precision, most of the data will be corrupted, so I cannot use a rough calculation of the cardinality - I need the result to be accurate.
How can I solve this problem? Is there a version math.pow
that doesn't overflow? Is there a better database conversion algorithm that I am overlooking?
source to share
Is there a version
math.pow
that doesn't overflow?
Try using the built-in exponent operator **
. AFAIK doesn't have the same limitations as math.pow
.
>>> math.pow(8,342)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: math range error
>>> 8**342
719077253944926363091722076315609893447190791576922629093720324630930703222003852530833909289630144084480455519485573430635159075257666489971389722557896497511071573699461941105208878404984376477812331808340023075352602729369851525895652442163308948653402042738345192959788983753918865219341425318496896548864L
source to share