C类型到PARI/GP的分数值问题

2024-09-26 22:51:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经编写了一个代码来比较sympyPARI/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

Tags: inresfloatcomparisonlongprintnumbersp1
1条回答
网友
1楼 · 发布于 2024-09-26 22:51:50

PARI/C类型的系统功能非常强大,还可以以用户定义的精度工作。因此,PARI/C需要使用自己的类型系统,例如参见PARI类型的实现

在PARI/C世界中,所有这些内部类型都作为指向long的指针处理。不要被这个愚弄了,但是类型与长时间无关。它最好被认为是一个索引或句柄,表示一个内部表示对调用方隐藏的变量

因此,无论何时在PARI/C world和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的精度有限(例如,在stackoverflow上搜索浮点精度)

因此,如果您想使用定义的精度,我建议使用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转换回double。但这同样适用,因为使用浮点数会降低精度。这里的一个解决方案是将结果转换为字符串,并在输出中显示带有字符串的列表

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,你可以将你的公式从

formular

transformed

相关问题 更多 >

    热门问题