2015-01-05 28 views
34

Tôi đã viết kịch bản sau đây:phận NumPy với RuntimeWarning: giá trị không hợp lệ gặp phải trong double_scalars

import numpy 

d = numpy.array([[1089, 1093]]) 
e = numpy.array([[1000, 4443]]) 
answer = numpy.exp(-3 * d) 
answer1 = numpy.exp(-3 * e) 
res = answer.sum()/answer1.sum() 
print res 

Nhưng tôi có kết quả này và với các lỗi xảy ra:

nan 
C:\Users\Desktop\test.py:16: RuntimeWarning: invalid value encountered in double_scalars 
    res = answer.sum()/answer1.sum() 

Nó có vẻ là rằng yếu tố đầu vào là quá nhỏ mà python biến chúng thành số không, nhưng thực sự bộ phận có kết quả của nó.

Cách giải quyết loại sự cố này?

Trả lời

39

bạn không thể giải quyết. Chỉ cần answer1.sum()==0 và bạn không thể thực hiện phân chia bằng 0.

Điều này xảy ra vì answer1 là số mũ của 2 số âm, rất lớn, do đó kết quả được làm tròn thành 0.

nan được trả lại trong trường hợp này do chia cho 0.

Bây giờ để giải quyết vấn đề của bạn, bạn có thể:

  • đi cho một thư viện cho toán học chính xác cao, như mpmath. Nhưng điều đó ít thú vị hơn.
  • thay thế cho vũ khí lớn hơn, thực hiện một số thao tác toán học, như được mô tả chi tiết bên dưới.
  • hãy sử dụng chức năng scipy/numpy được điều chỉnh phù hợp với những gì bạn muốn! Hãy xem câu trả lời của @Warren Weckesser.

Ở đây tôi giải thích cách thực hiện một số thao tác toán học giúp giải quyết vấn đề này. Chúng tôi có mà cho tử số:

exp(-x)+exp(-y) = exp(log(exp(-x)+exp(-y))) 
       = exp(log(exp(-x)*[1+exp(-y+x)])) 
       = exp(log(exp(-x) + log(1+exp(-y+x))) 
       = exp(-x + log(1+exp(-y+x))) 

nơi trên x=3* 1089y=3* 1093. Bây giờ, các đối số của hàm mũ này là

-x + log(1+exp(-y+x)) = -x + 6.1441934777474324e-06

Đối với các mẫu bạn có thể tiến hành tương tự nhưng được rằng log(1+exp(-z+k)) đã được làm tròn đến 0, do đó các đối số của hàm mũ tại mẫu số chỉ đơn giản là làm tròn đến -z=-3000 . Sau đó bạn có mà kết quả của bạn là

exp(-x + log(1+exp(-y+x)))/exp(-z) = exp(-x+z+log(1+exp(-y+x)) 
            = exp(-266.99999385580668) 

mà là đã rất gần với kết quả mà bạn sẽ nhận được nếu bạn đã giữ chỉ 2 điều kiện hàng đầu (tức là số đầu tiên 1089 trong tử số và số đầu tiên 1000 ở mẫu số):

exp(3*(1089-1000))=exp(-267) 

Vì lợi ích của nó, chúng ta hãy xem cách giữa chúng ta là từ các giải pháp của Wolfram alpha (link):

Log[(exp[-3*1089]+exp[-3*1093])/([exp[-3*1000]+exp[-3*4443])] -> -266.999993855806522267194565420933791813296828742310997510523 

Sự khác biệt giữa số này và số mũ trên là +1.7053025658242404e-13, vì vậy phép tính xấp xỉ mà chúng tôi thực hiện tại mẫu số là tốt.

Kết quả cuối cùng là

'exp(-266.99999385580668) = 1.1050349147204485e-116 

Từ Wolfram Alpha là (link)

1.105034914720621496.. × 10^-116 # Wolfram alpha. 

và một lần nữa, nó là an toàn để sử dụng NumPy đây quá.

+0

Nhưng trong trường hợp này tôi cần phải nhận được giá trị của các bộ phận bởi 2 giá trị rất nhỏ. – Heinz

+1

Ý của bạn là gì? – gg349

+0

@Heinz Tôi nghĩ rằng bạn có nghĩa là trường hợp trong đó một số nhỏ được chia cho một số nhỏ. Trong trường hợp đó thay đổi thuật toán của bạn để mở rộng cả hai con số lên là tốt hơn nhiều so với việc tìm kiếm xoắn cơ học. Ví dụ, lấy logarit của các phương trình phân tích mà mã của bạn đang cố gắng mô phỏng. Có nhiều vấn đề với tính ổn định của tính toán khi có số lượng nhỏ. Sẽ tốt hơn nếu bạn không có bất kỳ thứ gì trong số họ nếu có thể. – Mai

7

Bạn có thể sử dụng np.logaddexp (mà thực hiện ý tưởng trong câu trả lời @ gg349 của):

In [33]: d = np.array([[1089, 1093]]) 

In [34]: e = np.array([[1000, 4443]]) 

In [35]: log_res = np.logaddexp(-3*d[0,0], -3*d[0,1]) - np.logaddexp(-3*e[0,0], -3*e[0,1]) 

In [36]: log_res 
Out[36]: -266.99999385580668 

In [37]: res = exp(log_res) 

In [38]: res 
Out[38]: 1.1050349147204485e-116 

Hoặc bạn có thể sử dụng scipy.misc.logsumexp:

In [52]: from scipy.misc import logsumexp 

In [53]: res = np.exp(logsumexp(-3*d) - logsumexp(-3*e)) 

In [54]: res 
Out[54]: 1.1050349147204485e-116 
Các vấn đề liên quan