2009-01-08 12 views
9

मेरे पास एक सी फ़ंक्शन है जो long double देता है। मैं इस फ़ंक्शन को ctypes का उपयोग करके अजगर से कॉल करना चाहता हूं, और यह ज्यादातर काम करता है। सेटिंग so.func.restype = c_longdouble चाल है - सिवाय इसके कि पाइथन का फ्लोट प्रकार c_double है, इसलिए यदि लौटा हुआ मूल्य डबल से बड़ा होता है, लेकिन लंबे समय तक की सीमा के भीतर अच्छी तरह से पाइथन अभी भी वापसी मूल्य के रूप में inf हो जाता है। मैं 64 बिट प्रोसेसर पर हूं और sizeof(long double) 16 है।लंबे डबल रिटर्न और ctypes

सी कोड को संशोधित किए बिना इस पर प्राप्त करने के बारे में कोई विचार (उदा। दशमलव वर्ग या numpy का उपयोग कर)?

+0

मैं ऐसी ही कुछ करना चाहते हैं बल्कि और एक प्रश्न पोस्ट [यहां] (http://stackoverflow.com/questions/25380004/how-do-i-force-usage-of-long-doubles-with-cython), और अब एहसास हुआ कि मेरे पास अनिवार्य रूप से वही समस्या है जो आपने किया था। @Autoplectic, क्या मुझे पता चलेगा कि आपने अंततः क्या किया? – Abhinav

उत्तर

1

मुझे यकीन नहीं है कि आप सी कोड को संशोधित किए बिना ऐसा कर सकते हैं। प्रतीत होता है कि long double एस के लिए वास्तव में खराब समर्थन है - आप उन्हें संख्याओं की तरह कुशल नहीं बना सकते हैं, आप जो भी कर सकते हैं वह देशी float पायथन प्रकार के बीच उन्हें आगे और पीछे परिवर्तित कर सकता है।

तुम भी एक c_longdouble के बजाय वापसी मान के रूप में एक बाइट सरणी, एबीआई की वजह से उपयोग नहीं कर सकते - फ्लोटिंग प्वाइंट मूल्यों %eax रजिस्टर में या सामान्य वापसी मान की तरह ढेर पर वापस नहीं कर रहे हैं, वे ' हार्डवेयर-विशिष्ट फ़्लोटिंग-पॉइंट रजिस्टरों के माध्यम से पारित किया गया।

0

यदि आपको उच्च परिशुद्धता फ़्लोटिंग पॉइंट की आवश्यकता है, तो जीएमपीवाई पर एक नज़र डालें।

GMPY एक सी-कोडेड अजगर विस्तार मॉड्यूल है कि अजगर कोड तेजी से multiprecision अंकगणित (पूर्णांक, तर्कसंगत, और नाव), यादृच्छिक संख्या पीढ़ी, उन्नत नंबर-सैद्धांतिक काम करता है, और अधिक करने के लिए प्रदान करने के लिए जीएमपी पुस्तकालय लपेटता है।

GMP में उच्च स्तरीय फ़्लोटिंग-पॉइंट अंकगणितीय फ़ंक्शन (mpf) शामिल हैं। यह जीएमपी फ़ंक्शन श्रेणी का उपयोग करने के लिए है यदि सी प्रकार 'डबल' किसी एप्लिकेशन के लिए पर्याप्त सटीकता नहीं देता है। इस श्रेणी में लगभग 65 कार्य हैं।

1

आप एक समारोह c_longdouble की एक उपवर्ग वापसी है, तो यह बजाय एक अजगर float में कनवर्ट करने से ctypes क्षेत्र वस्तु लिपटे वापस आ जाएगी। इसके बाद आप इस से बाइट निकाल सकते हैं (memcpy के साथ c_char सरणी में, उदाहरण के लिए) या ऑब्जेक्ट को आगे की प्रक्रिया के लिए किसी अन्य सी फ़ंक्शन पर पास करें। snprintf फ़ंक्शन इसे उच्च-परिशुद्धता पायथन संख्यात्मक प्रकार में प्रिंटिंग या रूपांतरण के लिए स्ट्रिंग में प्रारूपित कर सकता है।

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 यदि आप किसी ऐसे स्वरूप दशमलव प्रतिनिधित्व पर आधारित नहीं है कन्वर्ट करने के लिए करना चाहते हैं।)

संबंधित मुद्दे