2015-01-05 2 views
34

에서 발생하는 잘못된 값이 나는 다음과 같은 스크립트를 작성 :NumPy와 부문 : 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 

을하지만이 결과를 얻었고, 오류 발생 :

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

그 것 같다 입력 요소가 너무 작아서 파이썬이 0으로 만들지는 못했지만 실제로는 그 결과가 나옵니다.

어떻게 이런 종류의 문제를 해결할 수 있습니까?

답변

39

해결할 수 없습니다. 단순히 answer1.sum()==0이며 0으로 나누기를 수행 할 수 없습니다.

이 결과는 answer1이 매우 큰 2 개의 음수를 지수화하므로 결과가 0으로 반올림되므로 발생합니다.

nan이 경우 0으로 나눈 값이므로이 경우 반환됩니다. mpmath 같은 고정밀 수학 라이브러리에 대한

  • 이동 :

    이제 당신이 수 문제를 해결합니다. 그러나 그것은 덜 재미 있습니다.

  • 큰 무기 대신 다음과 같이 수학 조작을 수행하십시오.
  • 정확하게 원하는 기능을 수행하는 scipy/numpy 기능을 찾으십시오! @ Warren Weckesser 대답을 확인하십시오.

여기이 문제에 도움이되는 수학 조작 방법을 설명합니다. 우리는 분자에 대한이 있습니다

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))) 

x=3* 1089y=3* 1093 위. 자,이 지수의 인수는 분모의 지수 함수의 인수가 단순히 -z=-3000로 반올림되도록 분모를 들어 당신이 유사하게 진행하지만 log(1+exp(-z+k)) 이미 0로 반올림되는 것을 얻을 수

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

입니다 . 그런 다음 결과는 이미 분자의 첫 번째 숫자 1089와 첫 번째 숫자 1000 즉 (만 2 개 최고의 조건을 유지한다면 당신이 얻을 것이다 결과에 매우 가까운

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

것을 가지고 분모)에 :

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

그것의 위해를 들어,) (볼프람 알파의 용액으로부터 우리가 얼마나 가까운 link을 보자 :

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

위의 지수와 지수의 차이는 +1.7053025658242404e-13이므로 분모에서 작성한 근사값은 문제가 없습니다.

최종 결과는 울프 람 알파에서

'exp(-266.99999385580668) = 1.1050349147204485e-116 

이 (link)

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

하고 다시, 너무 여기 NumPy와 안전하게 사용할 수있다.

+0

을하지만,이 경우 내가 부문의 값을 얻을 필요 2 개의 아주 작은 값. – Heinz

+1

무엇을 의미합니까? – gg349

+0

@Heinz 작은 숫자를 작은 숫자로 나눈 경우를 의미한다고 생각합니다. 이 경우 알고리즘을 변경하여 두 숫자를 모두 스케일링하면 기계적 왜곡을 찾는 것보다 훨씬 낫습니다. 예를 들어, 코드에서 시뮬레이션하려는 분석 방정식의 대수를 취합니다. 작은 숫자가 관련되어있을 때 계산의 안정성에 많은 문제가 있습니다. 가능하다면 그 중 하나를 사용하지 않는 것이 좋습니다. – Mai

7

당신은 사용할 수 있습니다 (@ gg349의 대답에 아이디어를 구현) np.logaddexp :

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 

또는 당신은 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