9

我有 ac 函数,它返回一个long double. 我想使用 ctypes 从 python 调用这个函数,它主要工作。设置so.func.restype = c_longdouble可以解决问题——除了python的浮点类型是a c_double,所以如果返回值大于双精度,但在长双精度范围内,python仍然将inf作为返回值。我在 64 位处理器上,sizeof(long double)是 16 岁。

在不修改c代码的情况下解决这个问题(例如使用十进制类或numpy)有什么想法吗?

4

3 回答 3

1

我不确定您是否可以在不修改 C 代码的情况下做到这一点。ctypes 似乎对 s 的支持真的很差——你根本不能像数字一样操纵它们,你所能做的就是在原生Python 类型long double之间来回转换它们。float

您甚至不能使用字节数组而不是 a 作为返回值c_longdouble,因为 ABI - 浮点值%eax不像正常返回值那样在寄存器或堆栈中返回,它们是通过硬件传递的 -特定的浮点寄存器。

于 2009-01-08T06:56:41.987 回答
1

如果您有一个函数返回 的子类c_longdouble它将返回 ctypes 包装的字段对象,而不是转换为 python float。然后,您可以从中提取字节(memcpy例如,使用 c_char 数组)或将对象传递给另一个 C 函数以进行进一步处理。该snprintf函数可以将其格式化为字符串,以便打印或转换为高精度python数字类型。

import ctypes
libc = ctypes.cdll['libc.so.6']
libm = ctypes.cdll['libm.so.6']

class my_longdouble(ctypes.c_longdouble):
    def __str__(self):
        size = 100
        buf = (ctypes.c_char * size)()
        libc.snprintf(buf, size, '%.35Le', self)
        return buf[:].rstrip('\0')

powl = libm.powl
powl.restype = my_longdouble
powl.argtypes = [ctypes.c_longdouble, ctypes.c_longdouble]

for i in range(1020,1030):
    res = powl(2,i)
    print '2**'+str(i), '=', str(res)

输出:

2**1020 = 1.12355820928894744233081574424314046e+307
2**1021 = 2.24711641857789488466163148848628092e+307
2**1022 = 4.49423283715578976932326297697256183e+307
2**1023 = 8.98846567431157953864652595394512367e+307
2**1024 = 1.79769313486231590772930519078902473e+308
2**1025 = 3.59538626972463181545861038157804947e+308
2**1026 = 7.19077253944926363091722076315609893e+308
2**1027 = 1.43815450788985272618344415263121979e+309
2**1028 = 2.87630901577970545236688830526243957e+309
2**1029 = 5.75261803155941090473377661052487915e+309

(请注意,我对 35 位精度的估计结果对于long double英特尔处理器上的计算过于乐观,因为英特尔处理器只有 64 位尾数。如果您打算转换为%a不基于十进制表示。)%efg

于 2015-03-11T18:21:36.197 回答
0

如果您需要高精度浮点,请查看 GMPY。

GMPY是一个 C 编码的 Python 扩展模块,它包装了 GMP 库,为 Python 代码提供快速多精度算术(整数、有理数和浮点数)、随机数生成、高级数论函数等。

GMP包含高级浮点算术函数 ( mpf)。如果 C 类型 `double' 没有为应用程序提供足够的精度,这是 GMP 函数类别。此类别中大约有 65 个函数。

于 2009-01-08T07:08:54.100 回答