2017-11-17 47 views
0

리만 합계를 사용하여 근사값을 근사화하고 Python에서 matplotlib를 사용하여 그래프를 그릴 수있는 프로그램을 작성했습니다. x 축의 위와 아래에 같은 면적을 가진 함수의 경우, 결과 영역은 0이되어야하지만, 프로그램은 아주 작은 숫자를 출력합니다.파이썬 리먼 합계는 양수 및 음수 영역에 대해 0을 반환하지 않습니다.

다음 코드는 홀수 함수 f (x) = x^3을 -1에서 1로 그래프로 표시하므로 영역은 0이어야합니다. 대신 내 코드는 1.68065561477562 e^-15로 근사합니다.

이 문제의 원인은 무엇입니까? delta_x, x 또는 y의 반올림 오류입니까? 저는 값을 0으로 반올림 할 수 있다는 것을 압니다. 그러나 이것을 해결할 다른 문제가 있는지 궁금합니다.

나는 delta_x에 대해 Decimal.decimal 클래스를 사용해 보았지만 훨씬 작은 숫자가 있습니다.

파이썬 코드 :

import matplotlib.pyplot as plt 
import numpy as np 

# Approximates and graphs integral using Riemann Sum 


# example function: f(x) = x^3 
def f_x(x): 
    return x**3 

# integration range from a to b with n rectangles 
a, b, n = -1, 1, 1000 

# calculate delta x, list of x-values, list of y-values, and approximate area under curve 
delta_x = (b - a)/n 

x = np.arange(a, b+delta_x, delta_x) 

y = [f_x(i) for i in x] 

area = sum(y) * delta_x 

# graph using matplotlib 
fig = plt.figure() 
ax = fig.add_subplot(111) 
ax.plot(x, y) 
ax.bar(x, y, delta_x, alpha=.5) 
plt.title('a={}, b={}, n={}'.format(a, b, n)) 
plt.xlabel('A = {}'.format(area)) 
plt.show() 

답변

1

계산중인 내용이 본래의 의미에서 리만 (Riemann) 적분이 아님을 알아야합니다. 간격을 n 개의 저장소로 나누지 만 n+1 개의 저장소 (여기서는 n = 1000이지만 len(x) == 1001)를 합합니다. 따라서 결과는 예상 한 것과 거의 같을 수 있지만 확실히 거기에 도달하는 좋은 방법은 아닙니다.

Riemann sum을 사용하면 간격을 n bin으로 나눈 다음 n bin의 값을 합계합니다. 왼쪽 리만 합계, 오른쪽 리만 합계를 계산할지 또는 중간 점을 계산 할지를 선택할 수 있습니다. 중간 합계 이미 좋은 결과를 제공하는 동안

import numpy as np 

def f_x(x): 
    return x**3 

# integration range from a to b with n rectangles 
a, b, n = -1, 1, 1000 

delta_x = (b - a)/float(n) 

x_left = np.arange(a, b, delta_x) 
x_right = np.arange(a+delta_x, b+delta_x, delta_x) 
x_mid = np.arange(a+delta_x/2., b+delta_x/2., delta_x) 

print len(x_left), len(x_right), len(x_mid)   ### 1000 1000 1000 


area_left = f_x(x_left).sum() * delta_x 
area_right = f_x(x_right).sum() * delta_x 
area_mid = f_x(x_mid).sum() * delta_x 

print area_left  # -0.002 
print area_right # 0.002 
print area_mid  # 1.81898940355e-15 

, 대칭 기능은,

print 0.5*(area_right+area_left) # 1.76204537072e-15 

이를도 n을 선택하고 왼쪽과 오른쪽 합계의 평균을 좋은 생각 일 것입니다

이제 numpy.arange은 자체적으로 약간의 오류가 있음을 유의해야합니다.더 나은 선택은 0 실제로 floating point inaccuracies 전적으로되지 않는 이유

print area_left  # -0.002 
print area_right # 0.002 
print area_mid  # 8.52651282912e-17 
print 0.5*(area_right+area_left) # 5.68121938382e-17 

5.68121938382e-17은 0 이유에 꽤 가까운 산출 numpy.linspace

x_left = np.linspace(a, b-delta_x, n) 
x_right = np.linspace(a+delta_x, b, n) 
x_mid = np.linspace(a+delta_x/2., b-delta_x/2., n) 

사용하는 것입니다.

그 유명한 예는이 동작은 단순히 리만 통합 1E-17와 같은 정도의 동일한 에러를 도입하는 것을 보여 0 대신 5.5e-17 결과 0.1 + 0.2 - 0.3 것이다.

+0

예를 들어 홀수 개의 하위 구간 만 사용한다면 충분히 재미있을 것입니다. 왼쪽 리만의 합을 '1'에서 '1 + delta_x'로 바꾸는 것은'-1-delta_x/2 '를'1 + delta_x/2'로 바꾸어서 대칭을 유지합니다. – eugenhu

0

코드는 나에게 유효 할 것으로 보인다. 은 f_x이며, arange의 두 번째 인수에 delta_x을 추가하여 1000 개의 하위 간격을 갖는 근사 오류를 나타냅니다. 불행히도, 나는 반올림 오류가 여기에 있다고 생각합니다.

1

예, 이것은 부동 소수점 부정확성 때문입니다.

np.arange()은 정수가 아닌 단계 크기를 사용할 때 어떻게 반올림되는지에 따라 np.linspace()이 더 적합 할 수 있습니다. numpy.arange() 문서에서

:

비정 공정을 사용하여, 예컨대 0.1로, 결과는 종종 일치하지 않을 것이다. 이러한 경우에는 linspace를 사용하는 것이 좋습니다.

+0

문제의 코드에 여기에서 설명한 정확성보다 심각한 결함이 있지만 이것은 원칙적으로 정확합니다. 내 대답을 보라. – ImportanceOfBeingErnest