Ctypes 中的分数值问题到 PARI/GP
Fraction Value Problem in Ctypes to PARI/GP
我已经写了一个代码来比较 sympy
和 PARI/GP
的解决方案,但是当我给出分数值 D=13/12
时,我得到错误,TypeError: int expected instead of float
。
所以我把p1[i] = pari.stoi(c_long(numbers[i - 1]))
改成了p1[i] = pari.stoi(c_float(numbers[i - 1]))
,但是nfroots
没有输出,注意我必须在A,B,C中使用分数, D 小数点后可能需要 $10^10$ 位。
我该如何解决这个问题?
代码如下to download the libpari.dll file, click here -
from ctypes import *
from sympy.solvers import solve
from sympy import Symbol
pari = cdll.LoadLibrary("libpari.dll")
pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.gtopoly.restype = POINTER(c_long)
pari.nfroots.restype = POINTER(POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
#Changed c_long to c_float, but got no output
p1[i] = pari.stoi(c_long(numbers[i - 1]))
return p1
def Quartic_Comparison():
x = Symbol('x')
a=0;A=0;B=1;C=-7;D=13/12 #PROBLEM 1
solution=solve(a*x**4+A*x**3+B*x**2+ C*x + D, x)
print(solution)
V=(A,B,C,D)
P = pari.gtopoly(t_vec(V), c_long(-1))
res = pari.nfroots(None, P)
print("elements as long (only if of type t_INT): ")
for i in range(1, pari.glength(res) + 1):
print(pari.itos(res[i]))
return res #PROBLEM 2
f=Quartic_Comparison()
print(f)
错误是-
[0.158343724039430, 6.84165627596057]
Traceback (most recent call last):
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 40, in <module>
f=Quartic_Comparison()
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 32, in Quartic_Comparison
P = pari.gtopoly(t_vec(V), c_long(-1))
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 20, in t_vec
p1[i] = pari.stoi(c_long(numbers[i - 1]))
TypeError: int expected instead of float
PARI/C 类型系统非常强大,还可以使用用户定义的精度。因此 PARI/C 需要使用自己的类型系统,例如参见PARI 类型的实现 https://pari.math.u-bordeaux.fr/pub/pari/manuals/2.7.6/libpari.pdf.
在 PARI/C 世界中,所有这些内部类型都作为指向 long 的指针处理。不要被这个愚弄了,但是类型与 long 无关。也许最好将其视为索引或句柄,代表一个变量,其内部表示对调用者是隐藏的。
因此,无论何时在 PARI/C 世界和 Python 世界之间切换,您都需要转换类型。
转换被描述为例如在上述 PDF 文件的第 4.4.6 节中。
要将 double 转换为相应的 PARI 类型 (= t_REAL
),因此需要调用转换函数 dbltor
.
同定义
pari.dbltor.restype = POINTER(c_long)
pari.dbltor.argtypes = (c_double,)
一个人可以获得这样的 PARI 向量 (t_VEC
):
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = pari.dbltor(numbers[i - 1])
return p1
用户自定义精度
但是 Python 类型 double
的精度有限(例如在 Whosebug 上搜索浮点精度)。
因此,如果您想以定义的精度工作,我建议您使用 gdiv
。
定义它,例如像这样:
V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12)))
并相应地调整 t_vec
,以获得这些 PARI 数字的向量:
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = numbers[i - 1]
return p1
在这种情况下,您需要使用 realroots
来计算根,请参阅 https://pari.math.u-bordeaux.fr/dochtml/html-stable/Polynomials_and_power_series.html#polrootsreal。
您同样可以使用 rtodbl
将 PARI 类型 t_REAL
转换回双精度类型。但同样适用,因为使用浮点数会降低精度。此处的一种解决方案是将结果转换为字符串并在输出中显示包含字符串的列表。
Python 计划
一个自包含的 Python 考虑到以上几点的程序可能看起来像这样:
from ctypes import *
from sympy.solvers import solve
from sympy import Symbol
pari = cdll.LoadLibrary("libpari.so")
pari.stoi.restype = POINTER(c_long)
pari.stoi.argtypes = (c_long,)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.cgetg.argtypes = (c_long, c_long)
pari.gtopoly.restype = POINTER(c_long)
pari.gtopoly.argtypes = (POINTER(POINTER(c_long)), c_long)
pari.dbltor.restype = POINTER(c_long)
pari.dbltor.argtypes = (c_double,)
pari.rtodbl.restype = c_double
pari.rtodbl.argtypes = (POINTER(c_long),)
pari.realroots.restype = POINTER(POINTER(c_long))
pari.realroots.argtypes = (POINTER(c_long), POINTER(POINTER(c_long)), c_long)
pari.GENtostr.restype = c_char_p
pari.GENtostr.argtypes = (POINTER(c_long),)
pari.gdiv.restype = POINTER(c_long)
pari.gdiv.argtypes = (POINTER(c_long), POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
precision = c_long(38)
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = numbers[i - 1]
return p1
def quartic_comparison():
x = Symbol('x')
a = 0
A = 0
B = 1
C = -7
D = 13 / 12
solution = solve(a * x ** 4 + A * x ** 3 + B * x ** 2 + C * x + D, x)
print(f"sympy: {solution}")
V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12)))
P = pari.gtopoly(t_vec(V), -1)
roots = pari.realroots(P, None, precision)
res = []
for i in range(1, pari.glength(roots) + 1):
res.append(pari.GENtostr(roots[i]).decode("utf-8")) #res.append(pari.rtodbl(roots[i]))
return res
f = quartic_comparison()
print(f"PARI: {f}")
测试
控制台上的输出如下所示:
sympy: [0.158343724039430, 6.84165627596057]
PARI: ['0.15834372403942977487354358292473161327', '6.8416562759605702251264564170752683867']
旁注
问题中并没有真正问到,但以防万一你想避免 13/12 你可以将你的公式从
到
我已经写了一个代码来比较 sympy
和 PARI/GP
的解决方案,但是当我给出分数值 D=13/12
时,我得到错误,TypeError: int expected instead of float
。
所以我把p1[i] = pari.stoi(c_long(numbers[i - 1]))
改成了p1[i] = pari.stoi(c_float(numbers[i - 1]))
,但是nfroots
没有输出,注意我必须在A,B,C中使用分数, D 小数点后可能需要 $10^10$ 位。
我该如何解决这个问题?
代码如下to download the libpari.dll file, click here -
from ctypes import *
from sympy.solvers import solve
from sympy import Symbol
pari = cdll.LoadLibrary("libpari.dll")
pari.stoi.restype = POINTER(c_long)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.gtopoly.restype = POINTER(c_long)
pari.nfroots.restype = POINTER(POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
#Changed c_long to c_float, but got no output
p1[i] = pari.stoi(c_long(numbers[i - 1]))
return p1
def Quartic_Comparison():
x = Symbol('x')
a=0;A=0;B=1;C=-7;D=13/12 #PROBLEM 1
solution=solve(a*x**4+A*x**3+B*x**2+ C*x + D, x)
print(solution)
V=(A,B,C,D)
P = pari.gtopoly(t_vec(V), c_long(-1))
res = pari.nfroots(None, P)
print("elements as long (only if of type t_INT): ")
for i in range(1, pari.glength(res) + 1):
print(pari.itos(res[i]))
return res #PROBLEM 2
f=Quartic_Comparison()
print(f)
错误是-
[0.158343724039430, 6.84165627596057]
Traceback (most recent call last):
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 40, in <module>
f=Quartic_Comparison()
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 32, in Quartic_Comparison
P = pari.gtopoly(t_vec(V), c_long(-1))
File "C:\Users\Desktop\PARI Function ellisdivisible - Copy.py", line 20, in t_vec
p1[i] = pari.stoi(c_long(numbers[i - 1]))
TypeError: int expected instead of float
PARI/C 类型系统非常强大,还可以使用用户定义的精度。因此 PARI/C 需要使用自己的类型系统,例如参见PARI 类型的实现 https://pari.math.u-bordeaux.fr/pub/pari/manuals/2.7.6/libpari.pdf.
在 PARI/C 世界中,所有这些内部类型都作为指向 long 的指针处理。不要被这个愚弄了,但是类型与 long 无关。也许最好将其视为索引或句柄,代表一个变量,其内部表示对调用者是隐藏的。
因此,无论何时在 PARI/C 世界和 Python 世界之间切换,您都需要转换类型。
转换被描述为例如在上述 PDF 文件的第 4.4.6 节中。
要将 double 转换为相应的 PARI 类型 (= t_REAL
),因此需要调用转换函数 dbltor
.
同定义
pari.dbltor.restype = POINTER(c_long)
pari.dbltor.argtypes = (c_double,)
一个人可以获得这样的 PARI 向量 (t_VEC
):
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = pari.dbltor(numbers[i - 1])
return p1
用户自定义精度
但是 Python 类型 double
的精度有限(例如在 Whosebug 上搜索浮点精度)。
因此,如果您想以定义的精度工作,我建议您使用 gdiv
。
定义它,例如像这样:
V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12)))
并相应地调整 t_vec
,以获得这些 PARI 数字的向量:
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = numbers[i - 1]
return p1
在这种情况下,您需要使用 realroots
来计算根,请参阅 https://pari.math.u-bordeaux.fr/dochtml/html-stable/Polynomials_and_power_series.html#polrootsreal。
您同样可以使用 rtodbl
将 PARI 类型 t_REAL
转换回双精度类型。但同样适用,因为使用浮点数会降低精度。此处的一种解决方案是将结果转换为字符串并在输出中显示包含字符串的列表。
Python 计划
一个自包含的 Python 考虑到以上几点的程序可能看起来像这样:
from ctypes import *
from sympy.solvers import solve
from sympy import Symbol
pari = cdll.LoadLibrary("libpari.so")
pari.stoi.restype = POINTER(c_long)
pari.stoi.argtypes = (c_long,)
pari.cgetg.restype = POINTER(POINTER(c_long))
pari.cgetg.argtypes = (c_long, c_long)
pari.gtopoly.restype = POINTER(c_long)
pari.gtopoly.argtypes = (POINTER(POINTER(c_long)), c_long)
pari.dbltor.restype = POINTER(c_long)
pari.dbltor.argtypes = (c_double,)
pari.rtodbl.restype = c_double
pari.rtodbl.argtypes = (POINTER(c_long),)
pari.realroots.restype = POINTER(POINTER(c_long))
pari.realroots.argtypes = (POINTER(c_long), POINTER(POINTER(c_long)), c_long)
pari.GENtostr.restype = c_char_p
pari.GENtostr.argtypes = (POINTER(c_long),)
pari.gdiv.restype = POINTER(c_long)
pari.gdiv.argtypes = (POINTER(c_long), POINTER(c_long))
(t_VEC, t_COL, t_MAT) = (17, 18, 19) # incomplete
precision = c_long(38)
pari.pari_init(2 ** 19, 0)
def t_vec(numbers):
l = len(numbers) + 1
p1 = pari.cgetg(c_long(l), c_long(t_VEC))
for i in range(1, l):
p1[i] = numbers[i - 1]
return p1
def quartic_comparison():
x = Symbol('x')
a = 0
A = 0
B = 1
C = -7
D = 13 / 12
solution = solve(a * x ** 4 + A * x ** 3 + B * x ** 2 + C * x + D, x)
print(f"sympy: {solution}")
V = (pari.stoi(A), pari.stoi(B), pari.stoi(C), pari.gdiv(pari.stoi(13), pari.stoi(12)))
P = pari.gtopoly(t_vec(V), -1)
roots = pari.realroots(P, None, precision)
res = []
for i in range(1, pari.glength(roots) + 1):
res.append(pari.GENtostr(roots[i]).decode("utf-8")) #res.append(pari.rtodbl(roots[i]))
return res
f = quartic_comparison()
print(f"PARI: {f}")
测试
控制台上的输出如下所示:
sympy: [0.158343724039430, 6.84165627596057]
PARI: ['0.15834372403942977487354358292473161327', '6.8416562759605702251264564170752683867']
旁注
问题中并没有真正问到,但以防万一你想避免 13/12 你可以将你的公式从
到