2015-10-17 12 views
7

Tôi đã mảng và chức năng NumPy sau:Đánh giá chức năng sử dụng mảng NumPy trả inf và nan

import numpy 
import scipy.special 

i = numpy.linspace(0, 500, 501, dtype = int) 

def func(x, n): 
    return scipy.special.eval_hermite(n, x) 

Tôi đánh giá chức năng cho mọi phần tử trong mảng NumPy tôi i sử dụng hai appraoches khác nhau:

Phương pháp 1:

hermites = func(0, i) 

phương pháp 2:

hermites = [func(0, idx) for idx in i] 

Hai phương pháp tiếp cận dẫn đến hai câu trả lời khác nhau. Chúng khác nhau vì sau phần tử 50, cách tiếp cận bắt đầu trả lại infnan. Phương pháp tiếp cận 2 cũng không cung cấp giá trị chính xác cho mọi thành phần của i. Tuy nhiên, nó có thể tính toán nhiều hơn. Phương pháp 2 không thành công cho i >= 64.

Cả hai cách tiếp cận cho tôi câu trả lời trong cùng khoảng thời gian (0,7 s cho len(i) = 15000, được xác định bằng cách sử dụng timeit). Những gì tôi không hiểu là những kết quả khác nhau. Điều này là do tôi đã học cách tránh for loops trong python càng nhiều càng tốt. Đây không phải là trường hợp này lần này.

Ý tưởng rằng nó phải làm với bộ nhớ cũng vượt qua tâm trí của tôi. Tuy nhiên, việc đánh giá một phần tử đơn lẻ, tức là print func(0, 64) cũng trả về 0. (bằng với đầu ra của phương pháp).

Điều gì đang xảy ra?

Trả lời

5

Đây là một lỗi trong scipy được tạo ra bởi các quy tắc đúc thỉnh thoảng đáng ngạc nhiên của "ufuncs" của numpy. Vấn đề là, trong phiên bản scipy 0,16 trở lên, khi đối số đầu tiên của eval_hermite là một số nguyên mảng và thứ hai là một vô hướng số nguyên, kiểu dữ liệu của giá trị trả về là điểm nổi chính xác đơn (numpy.float32). Khi đối số thứ hai là một giá trị dấu phẩy động 64 bit, kiểu trả về là numpy.float64. Giá trị lớn nhất có thể được biểu diễn bằng float32 nhỏ hơn nhiều so với giá trị float64, vì vậy khi đối số thứ hai là số nguyên, thì eval_hermite sẽ tràn vào vô hạn sớm hơn nhiều.

Ví dụ, đây là với scipy 0.16.0 và 1.10.1 NumPy:

In [26]: from scipy.special import eval_hermite 

Lưu ý rằng kiểu dữ liệu của giá trị trả về là float32:

In [27]: eval_hermite([20, 50, 100, 200], 0) 
Out[27]: 
array([ 6.70442586e+11,    -inf,    inf, 
        inf], dtype=float32) 

Nếu đối số thứ hai là điểm nổi, loại trả về là float64 và các giá trị lớn có thể được biểu diễn:

In [28]: eval_hermite([20, 50, 100, 200], 0.0) 
Out[28]: 
array([ 6.70442573e+011, -1.96078147e+039, 3.06851876e+093, 
     8.45055019e+216]) 

Công việc xung quanh mã của bạn là luôn đảm bảo rằng đối số thứ hai cho eval_hermite là một giá trị dấu phẩy động.Ví dụ,

hermites = func(0.0, i) 

Vấn đề này đã được cố định trong phiên bản phát triển scipy (xem https://github.com/scipy/scipy/pull/4896), do đó scipy 0,17 không nên có vấn đề này khi nó được phát hành.

+0

Chúng ta có nên chỉnh sửa tiêu đề không? Phần thú vị của câu hỏi không phải là về "tại sao inf và nan", nhưng "tại sao không truyền mảng và sử dụng listcomp cho phần tử iterate bởi phần tử trả về cùng một kết quả?" – DSM

+0

Đạt được kết quả tốt hơn sau khi nâng cấp lên scipy 0.16.0. Tuy nhiên, bây giờ cho 'i> = 270' tôi lại lấy' inf' hoặc 'nan'. Lỗi này đã hoàn toàn chưa (tất cả có thể 'i') đã được sửa trong phiên bản phát triển scipy? Và có cách nào để có được phiên bản này không? –

+0

Đối với 'i> = 270', giá trị của đa thức Hermite tại' x = 0' lớn hơn có thể được biểu diễn bằng các giá trị dấu phẩy động 64 bit, do đó, 'inf' được mong đợi. Đối với 'i> = 300', tôi nhận được' nan'; Tôi đã không nhìn vào nó, nhưng tôi nghi ngờ một số mã kết thúc lên làm 'inf - inf'. –

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