问题描述
我正在玩一些 RSA 加密计算,其中之一正在计算
very-large-number**(1/3)
其中非常大的数字是 100 位数字。我需要最后的结果为十六进制才能得到最终结果。
我已经尝试了通常的 float.hex() hex(int(n)) 甚至一些从这里提出的解决方案 Dealing with very large hex numbers in python
但我得到的结果要么是科学格式(xx.xxxx+40),要么输出的后半部分全是 0(我知道这是不正确的)
示例:
>>> n=14887716705766614226302331656748546195328906880296894322596715261404953788693951344841626882745910926946567107240171862117
>>> ct=n**(1/3)
>>> ct.hex()
'0x1.212d39ed89671p+134'
>>> print(ct)
2.4600430019674926e+40
>>> print(ct.hex())
0x1.212d39ed89671p+134
hex(int(ct))
'0x484b4e7b6259c400000000000000000000'
>>> int(ct)
24600430019674926067273894051435979472896
那么我如何得到十六进制值呢?来自 hex(int(ct)) 的第一部分)0x484b4e7b6259c) 是正确的,所以这似乎表明精度错误。
我也尝试过 numpy:
>>> import numpy as np
>>> x=np.longdouble(14887716705766614226302331656748546195328906880296894322596715261404953788693951344841626882745910926946567107240171862117)
>>> float_formatter='{e:f}'.format
>>> np.set_printoptions(formatter={'float_kind':float_formatter},precision=128)
>>> ct=np.cbrt(x)
>>> np.cbrt(x)
2.4600430019675053399e+40
>>> print(ct)
2.4600430019675053399e+40
编辑: 计算的实际结果应该是: 24600430019675053398291607284547696341373 在十六进制之前应该变成 0x484B4E7B625A2D53644D2D64644F72317D 作为十六进制
解决方法
问题在于,虽然 Python 整数是多精度数,但浮点数只是 64 位 IEEE 754 浮点数,并且精度限制为 15 或 16 位十进制数字。
这意味着浮点 n ** (1/3)
操作只会给出一个近似值。
但是你可以使用牛顿法找到方程 x**3 = n 的更准确的解:
def sqr3(n):
s0 = int(n ** (1/3))
s1 = 0
while True:
s1 = s0 + (n - s0 **3) // 2 // s0 // s0
if s1 ** 3 == n:
break
if (s0 - 1 <= s1 <= s0 + 1):
# should search further whether s0 or s1 (or maybe next iteration)
# would be the best one...
break
s0 = s1
return s1
它给出了 sqr3(n)
: 24600430019675053398291607284547696341373
这是精确的解决方案。
快速检查现有的online converter,您的两个输出实际上是相同的数字
'0x484b4e7b6259c400000000000000000000'
等于
24600430019674926067273894051435979472896