2009-01-08 95 views
9

我有一個c函數,它返回一個long double。我想從使用ctypes的python調用這個函數,它大部分工作。設置so.func.restype = c_longdouble的竅門 - 除了python的浮點類型是c_double,所以如果返回的值大於double,但是在long double的範圍內,python仍然將inf作爲返回值。我在一個64位的處理器和sizeof(long double)是16.long double return和ctypes

有關繞過此(如使用十進制類或numpy)而不修改c代碼的任何想法?

+0

我想要做類似的事情併發布了一個問題[here](http://stackoverflow.com/questions/25380004/how-do-i-force-usage-of-long-doubles-with-cython),現在意識到我基本上有同樣的問題。 @Autoplectic,我可以知道你最終做了什麼嗎? – Abhinav 2014-08-19 17:02:50

回答

1

我不確定不修改C代碼就可以做到。 ctypes似乎對long double的支持確實不好 - 你不能像數字一樣操縱它們,你所能做的只是在Python的本地類型之間來回轉換它們。

你甚至不能使用字節數組作爲返回值而不是c_longdouble,因爲ABI - 浮點數值不會返回到%eax寄存器或堆棧中,就像正常的返回值一樣,重新通過硬件特定的浮點寄存器。

0

如果您需要高精度浮點數,請查看GMPY。

GMPY是一個C編碼的Python擴展模塊,它封裝了GMP庫以提供給Python代碼快速多精度算法(整數,有理數和浮點數),隨機數生成,高級數理論函數等等。

GMP包含高級浮點算術函數(mpf)。如果C類型'double'不能爲應用程序提供足夠的精度,則這是GMP函數類別。這個類別大約有65個功能。

1

如果你有一個函數返回的c_longdouble一個子類,它會返回封裝領域對象ctypes的,而不是轉化爲蟒蛇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個位數估計原來是爲英特爾處理器,其中只有尾數的64位long double計算過分樂觀,應使用。 %a而不是%e/f/g如果您打算轉換爲不基於十進制表示的格式)。