2009-01-08 32 views
9

tôi có hàm c trả về số long double. Tôi muốn gọi chức năng này từ python sử dụng ctypes, và nó chủ yếu là hoạt động. thiết lập so.func.restype = c_longdouble hiện các trick - ngoại trừ loại trăn của python là một c_double vì vậy nếu giá trị trả lại lớn hơn một đôi, nhưng cũng trong giới hạn của một đôi dài, python vẫn được inf như giá trị trả lại. Tôi đang sử dụng bộ vi xử lý 64 bit và sizeof(long double) là 16.lợi nhuận gấp đôi dài và ctypes

bất kỳ ý tưởng nào về việc này (ví dụ: sử dụng lớp thập phân hoặc gumpy) mà không sửa đổi mã c?

+0

Tôi muốn làm điều gì đó tương tự và đăng câu hỏi [ở đây] (http://stackoverflow.com/questions/25380004/how-do-i-force-usage-of-long-doubles-with-cython), và bây giờ nhận ra rằng tôi về cơ bản cùng một vấn đề bạn đã làm. @Autoplectic, tôi có thể biết những gì bạn cuối cùng đã làm? – Abhinav

Trả lời

1

Tôi không chắc chắn bạn có thể làm điều đó mà không sửa đổi mã C. ctypes dường như có hỗ trợ thực sự xấu cho long double s - bạn không thể thao tác chúng như số ở tất cả, tất cả những gì bạn có thể làm là chuyển đổi chúng qua lại giữa kiểu gốc float Python.

Bạn thậm chí không thể sử dụng mảng byte làm giá trị trả về thay vì c_longdouble, vì ABI - giá trị dấu phẩy động không được trả lại trong thanh ghi %eax hoặc trên ngăn xếp như giá trị trả về bình thường, chúng ' được chuyển qua thanh ghi dấu chấm động phần cứng cụ thể.

0

Nếu bạn cần điểm nổi chính xác cao, hãy xem GMPY.

GMPY là một mô-đun mở rộng Python mã hóa C, bao bọc thư viện GMP để cung cấp mã số nhanh đa cấp mã Python (số nguyên, lý trí và float), tạo số ngẫu nhiên, hàm số lý thuyết nâng cao và hơn thế nữa.

GMP chứa hàm số học dấu phẩy động cấp cao (mpf). Đây là loại chức năng GMP để sử dụng nếu loại C 'double' không cung cấp đủ độ chính xác cho một ứng dụng. Có khoảng 65 chức năng trong thể loại này.

1

Nếu bạn có hàm trả về lớp con của c_longdouble, nó sẽ trả về đối tượng trường bao bọc ctypes thay vì chuyển đổi thành trăn float. Sau đó, bạn có thể trích xuất các byte từ này (ví dụ: memcpy thành một mảng c_char) hoặc chuyển đối tượng sang một hàm C khác để xử lý tiếp. Hàm snprintf có thể định dạng nó thành một chuỗi để in hoặc chuyển đổi thành một kiểu số python có độ chính xác cao.

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) 

Output:

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 

(Lưu ý rằng ước tính của tôi là 35 chữ số chính xác hóa ra là quá lạc quan cho long double tính toán trên bộ xử lý Intel, trong đó chỉ có 64 bit của mantissa Bạn nên sử dụng. %a thay vì %e/f/g nếu bạn có ý định chuyển đổi sang định dạng không dựa trên đại diện thập phân.)

Các vấn đề liên quan