2013-08-30 56 views
10

Tôi đã chơi bản dài gấp đôi của C99 quad precision. Đó là sự hiểu biết của tôi rằng (nền tảng cụ thể) numpy hỗ trợ long double và 128bit nổi.Numpy longdouble số học dường như không ở trong thời gian dài gấp đôi với chuyển đổi

Tôi đã chạy qua một thứ mà tôi không thể giải thích được.

Given:

>>> import numpy as np 

Tính một con số đó sẽ đòi hỏi nhiều hơn 64 bit nhưng ít hơn 128 bit để biểu diễn như một số nguyên:

>>> 2**64+2 
18446744073709551618   # note the '8' at the end 
>>> int(2**64+2) 
18446744073709551618   # same obviously 

Nếu tôi calculate cùng một số trong C99 128 hơi dài gấp đôi, tôi nhận được 18446744073709551618.000000

Bây giờ, nếu tôi sử dụng đôi dài gấp gáp:

>>> a=np.longdouble(2) 
>>> b=np.longdouble(64) 
>>> a**b+a 
18446744073709551618.0    # all good... 

gì về những kết quả không chính xác:

>>> np.longdouble(2**64+2) 
18446744073709551616.0    # Note '6'; appears 2**64 not done in long double 
>>> np.longdouble(int(2**64+2)) 
18446744073709551616.0    # can't force the use of a Python long 
>>> n=int(2**64+2) 
>>> np.longdouble(n) 
18446744073709551616.0 
>>> np.longdouble(18446744073709551618) 
18446744073709551616.0    # It really does not want to do '8' at the end 

Nhưng, công trình này:

>>> np.longdouble(2**64)+2 
18446744073709551618.0 

Câu hỏi: Liệu NumPy có vấn đề chuyển đổi các giá trị một cách chính xác vào đôi lâu? Có điều gì tôi đang làm không chính xác?

+0

Bạn đã cố gắng thực hiện tương tự trong C? Mã mà bạn đã liên kết không * không * làm những gì bạn đang cố gắng thực hiện với phần mềm. Trước tiên, hãy cố gắng tính toán '2 ** 64 + 2' làm số nguyên và * sau đó * gán nó thành' số double dài'. (Tôi có nghĩa là một cái gì đó như: 'dài dài val = (1 << 64) + 2; dài gấp đôi res = (dài gấp đôi) val') – Bakuriu

+0

@ Bakuriu: Vâng, tôi đã cố gắng trong C. Có, tôi đã cố gắng' n = int (2 ** 64 + 2); np.longdouble (n) 'mà vẫn không thêm 2. – dawg

+1

Sử dụng biểu thức' n = (2 ** x + 2); np.longdouble (n) == n' sẽ trả về false cho 'x> 53'. Có vẻ như một điểm kỳ lạ. – Daniel

Trả lời

9

Bạn đang cố thực hiện chuyển đổi loại giữa các loại không thể chuyển đổi trực tiếp. Hãy nhìn vào ngăn xếp:

#0 0x00002aaaaab243a0 in PyLong_AsDouble() 
    from libpython2.7.so.1.0 
#1 0x00002aaaaab2447a in ??() 
    from libpython2.7.so.1.0 
#2 0x00002aaaaaaf8357 in PyNumber_Float() 
    from libpython2.7.so.1.0 
#3 0x00002aaaae71acdc in MyPyFloat_AsDouble (obj=0x2aaaaae93c00) 
    at numpy/core/src/multiarray/arraytypes.c.src:40 
#4 0x00002aaaae71adfc in LONGDOUBLE_setitem (op=0x2aaaaae93c00, 
    ov=0xc157b0 "", ap=0xbf6ca0) 
    at numpy/core/src/multiarray/arraytypes.c.src:278 
#5 0x00002aaaae705c82 in PyArray_FromAny (op=0x2aaaaae93c00, 
    newtype=0x2aaaae995960, min_depth=<value optimized out>, max_depth=0, 
    flags=0, context=<value optimized out>) 
    at numpy/core/src/multiarray/ctors.c:1664 
#6 0x00002aaaae7300ad in longdouble_arrtype_new (type=0x2aaaae9938a0, 
    args=<value optimized out>, __NPY_UNUSED_TAGGEDkwds=<value optimized out>) 
    at numpy/core/src/multiarray/scalartypes.c.src:2545 

Như bạn có thể thấy, Python long (không giới hạn độ chính xác số nguyên) 2**64 + 2 đang được chuyển đổi sang float (ví dụ: 64-bit kép), mà mất độ chính xác; phao sau đó được sử dụng để khởi tạo đôi dài nhưng độ chính xác đã bị mất.

Vấn đề là đôi 128 bit không phải là một kiểu gốc Python, do đó, long không có chuyển đổi riêng cho nó, chỉ với 64 bit đôi. Nó có thể là có thể cho NumPy để phát hiện tình trạng này và thực hiện chuyển đổi của riêng mình bằng cách sử dụng long C API, nhưng có thể khá phức tạp cho lợi ích tương đối ít (bạn chỉ có thể làm số học trong np.longdouble từ đầu).

+3

Đó là một lỗi tiềm tàng lén lút, phải không? – dawg

+1

@dawg đó là lý do tại sao [tài liệu sần sần] (http://docs.scipy.org/doc/numpy-dev/user/basics.types.html#extended-precision) đề xuất _ "kiểm tra mã của bạn với giá trị' 1 + np.finfo (np.longdouble) .eps'. "_ –

2

NumPy không cung cấp độ chính xác quad trên máy x86. Nó cung cấp quyền truy cập vào loại C dài gấp đôi (như được cung cấp bởi môi trường biên dịch; với MSVC này có thể là 64 bit, với GCC nó thường là 80 bit) là np.longdouble. Các loại np.float96 và np.float128 chỉ đơn giản là dài gấp đôi đệm đến 96 hoặc 128 bit (để truy cập bộ nhớ liên kết). Xem the numpy docs. Để có được độ chính xác quad trong numpy bạn cần phải sử dụng một nền tảng phần cứng và trình biên dịch, nơi dài gấp đôi là chính xác quad thực tế.

Mặc dù có thể được hỗ trợ để hỗ trợ độ chính xác quad bằng cách sử dụng hỗ trợ trình biên dịch (GCC's float128) hoặc thư viện bên ngoài, điều này chưa được triển khai. Cũng có thể viết mô-đun có thể nhập của bên thứ ba đã tạo một trong các mô đun này, nhưng điều đó cũng chưa được thực hiện. Lưu ý rằng ngay cả khi sử dụng np.longdouble, nó rất dễ bị mất độ chính xác: ví dụ, toán tử% lực lượng numpy để vượt qua các số của nó thông qua phao nổi, ném đi bất kỳ độ chính xác thêm.

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