7회 실험 · 적분의 정의#

이 실험

짝 서술

7회 · 적분의 정의

실험 목록

1층 정의 계산 · 2층 scipy 대조 · 3층 정확한 식 · 분할 무관성 · 무작위 분할 · 그림

PART I에서 가장 중요한 실험이다. 세 층을 모두 쓴다.

Hide code cell source

# 공통 준비 — 색 규약과 한글 글꼴을 맞춘다
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp

from calc_viz import 상합하합, 함수그리기, 계단함수그리기, 무대, , 
from calc_style import 한글글꼴설정

글꼴 = 한글글꼴설정()

f = lambda x: x**2      # 이 회차의 대상
a, b = 0.0, 1.0

실험 1 (1층) — 정의를 그대로 옮긴 계산#

7회 (7.13)을 코드로 옮긴다. \([0,1]\)\(n\)등분하고 각 부분구간에서 최솟값과 최댓값을 높이로 하는 계단함수의 적분을 구한다.

# [7회] 상합과 하합
# 목적 : 정의에 따라 계산한다
# 층  : 1층
# 주의 : n 을 무한대로 보내지 않는다. 모든 n 이 유한하다

머리 = ["n", "하합 L_n", "상합 U_n", "차이 U_n − L_n", "b³/n"]
 = [7, 16, 16, 18, 16]
print(" ".join((, w) for , w in zip(머리, )))

for n_ in (2, 5, 10, 50, 200, 1000):
    ,  = 상합하합(f, a, b, n_)
     = [n_, f"{:.10f}", f"{:.10f}", f"{ - :.10f}", f"{b**3 / n_:.10f}"]
    print(" ".join((항목, w) for 항목, w in zip(, )))
      n         하합 L_n         상합 U_n     차이 U_n − L_n             b³/n
      2     0.1250000000     0.6250000000       0.5000000000     0.5000000000
      5     0.2400000000     0.4400000000       0.2000000000     0.2000000000
     10     0.2850000000     0.3850000000       0.1000000000     0.1000000000
     50     0.3234000000     0.3434000000       0.0200000000     0.0200000000
    200     0.3308375000     0.3358375000       0.0050000000     0.0050000000
   1000     0.3328335000     0.3338335000       0.0010000000     0.0010000000

차이가 (7.17)이 말하는 \(b^3/n\)과 정확히 일치한다. \(n=10\)에서 \(L_{10}=0.285\), \(U_{10}=0.385\)이며 이는 1회에서 계산한 값과 같다.

실험 2 (2층) — scipy로 대조한다#

우리가 정의에 따라 계산한 값이 맞는지 독립적으로 확인한다.

# [7회] scipy 의 수치 구적법으로 대조한다
# 목적 : 우리가 정의에 따라 계산한 값이 맞는지 독립적으로 확인한다
# 층  : 2층
# 주의 : quad 는 구간을 나누어 함숫값을 표본으로 더하는 방법이다.
#        우리가 정의한 것과 같은 계열의 계산이며, 부정적분을 쓰지 않는다.

from scipy.integrate import quad

, 오차 = quad(lambda t: t**2, a, b)
print(f"scipy.integrate.quad 의 값 : {:.12f}")
print(f"quad 가 보고한 오차 한계   : {오차:.3e}")

,  = 상합하합(f, a, b, 1000)
print(f"\n우리 계산 (n=1000)")
print(f"  하합 {:.12f}")
print(f"  상합 {:.12f}")
print(f"  quad 의 값이 두 값 사이에 있는가 : { <  < }")
scipy.integrate.quad 의 값 : 0.333333333333
quad 가 보고한 오차 한계   : 3.701e-15

우리 계산 (n=1000)
  하합 0.332833500000
  상합 0.333833500000
  quad 의 값이 두 값 사이에 있는가 : True

quad 는 되고 integrate 는 안 되는 이유

scipy.integrate.quad는 구간을 나누어 함숫값을 표본으로 더한다. 우리가 정의 14에서 정의한 것과 같은 계열의 계산이다. 그래서 이 강의에서 쓴다.

반면 sympy.integrate는 다른 경로로 답을 낸다. 이 함수는 먼저 도함수가 \(f\)가 되는 함수를 찾고, 그 함수의 양 끝값의 차를 구한다. 이 강의에서는 이 방법을 쓰지 않는다. 도함수를 아직 정의하지 않았기 때문이다.

두 함수가 같은 답을 준다는 것과 같은 경로로 온다는 것은 다른 이야기이다.

실험 3 (3층) — 정확한 식#

수치는 \(L_{1000} = 0.3328335\)라고 알려 주지만, 그 값이 \(1/3\)에서 정확히 얼마나 떨어져 있는지는 말해 주지 않는다. 기호로 계산하면 7회 (7.15)의 식이 그대로 나온다.

# [7회] 상합과 하합의 정확한 식
# 목적 : n 에 대한 식으로 두 값을 쓰고, 오차의 형태를 확인한다
# 층  : 3층
# 금지 : sp.integrate 와 sp.limit 을 쓰지 않는다

from calc_sym import 균등분할_상합하합, 보이기, x, n, b as b기호

하합, 상합 = 균등분할_상합하합(x**2, x, 0, b기호, 증가함수=True)
보이기("L_n", sp.expand(하합))
보이기("U_n", sp.expand(상합))
보이기("U_n − L_n", sp.simplify(상합 - 하합))
L_n =
 3 ⎛   2          ⎞
b ⋅⎝2⋅n  - 3⋅n + 1⎠
───────────────────
          2        
       6⋅n         
  LaTeX: \frac{b^{3} \left(2 n^{2} - 3 n + 1\right)}{6 n^{2}}

U_n =
 3 ⎛   2          ⎞
b ⋅⎝2⋅n  + 3⋅n + 1⎠
───────────────────
          2        
       6⋅n         
  LaTeX: \frac{b^{3} \left(2 n^{2} + 3 n + 1\right)}{6 n^{2}}

U_n − L_n =
 3
b 
──
n 
  LaTeX: \frac{b^{3}}{n}

\(b=1\)로 두고 \(1/3\)과의 거리를 본다.

# [7회] 적분값과 하합·상합의 거리
# 목적 : 어떤 유한한 n 에서도 하합이 적분값과 같아지지 않음을 식으로 확인한다
# 층  : 3층
# 주의 : 부호 판정은 인수분해한 식의 분자와 분모를 보고 한다

L1 = sp.expand(하합.subs(b기호, 1))
U1 = sp.expand(상합.subs(b기호, 1))

차1 = sp.factor(sp.simplify(sp.Rational(1, 3) - L1))
차2 = sp.factor(sp.simplify(U1 - sp.Rational(1, 3)))

보이기("1/3 − L_n", 차1)
보이기("U_n − 1/3", 차2)

m = sp.Symbol("m", positive=True, integer=True)
print(f"1/3 − L_n 이 n ≥ 1 에서 양수인가 : {sp.ask(sp.Q.positive(차1.subs(n, m)))}")
print(f"U_n − 1/3 이 n ≥ 1 에서 양수인가 : {sp.ask(sp.Q.positive(차2.subs(n, m)))}")
1/3 − L_n =
3⋅n - 1
───────
    2  
 6⋅n   
  LaTeX: \frac{3 n - 1}{6 n^{2}}

U_n − 1/3 =
3⋅n + 1
───────
    2  
 6⋅n   
  LaTeX: \frac{3 n + 1}{6 n^{2}}
1/3 − L_n 이 n ≥ 1 에서 양수인가 : True
U_n − 1/3 이 n ≥ 1 에서 양수인가 : True

두 식의 분모는 \(6n^2\)으로 양수이고 분자는 각각 \(3n-1\)\(3n+1\)이므로, \(n \ge 1\)에서 둘 다 양수이다. 즉 어떤 유한한 \(n\)에 대해서도 \(L_n \ne 1/3\)이고 \(U_n \ne 1/3\)이다.

적분값 \(1/3\)은 하합들의 최소상계이지 어떤 하합의 값이 아니다.

실험 4 (1층) — 분할 무관성#

정리 19을 수치로 확인한다. 같은 계단함수를 두 분할로 계산한다.

# [7회] 분할 무관성
# 목적 : 계단함수의 적분이 어떤 분할로 계산해도 같은 값이 되는지 확인한다
# 층  : 1층
# 주의 : 분할 B 는 분할 A 의 세분이다. 값이 같아야 한다

def 계단함수적분(분할점, 높이들):
    """7회 (7.1) 을 그대로 옮긴다."""
    return float(np.sum(np.asarray(높이들) * np.diff(분할점)))

분할A = np.array([0.0, 0.5, 1.0]);            높이A = [2.0, 5.0]
분할B = np.array([0.0, 0.2, 0.5, 0.8, 1.0]);  높이B = [2.0, 2.0, 5.0, 5.0]

print(f"분할 A ({len(분할A)-1}개 구간) : {계단함수적분(분할A, 높이A):.8f}")
print(f"분할 B ({len(분할B)-1}개 구간) : {계단함수적분(분할B, 높이B):.8f}")
print(f"같은가 : {계단함수적분(분할A, 높이A) == 계단함수적분(분할B, 높이B)}")
분할 A (2개 구간) : 3.50000000
분할 B (4개 구간) : 3.50000000
같은가 : True

실험 5 (1층) — 무작위 분할#

정의 14\(n\)등분에 대한 것이 아니라 모든 계단함수에 대한 것이다. 등분이 아닌 분할로도 \(1/3\)을 가둘 수 있는지 확인한다.

# [7회] 무작위 분할로도 같은 결과
# 목적 : 정의가 n 등분에 의존하지 않음을 확인한다
# 층  : 1층
# 주의 : seed 를 고정하므로 결과는 매번 같다

def 임의분할상합하합(f, a, b, n, seed, 표본수=200):
    r = np.random.default_rng(seed)
    내부 = np.sort(r.uniform(a, b, n - 1))
    분할점 = np.concatenate([[a], 내부, [b]])
    최소, 최대 = [], []
    for k in range(len(분할점) - 1):
        표본 = np.linspace(분할점[k], 분할점[k + 1], 표본수)
        최소.append(f(표본).min())
        최대.append(f(표본).max())
     = np.diff(분할점)
    return float(np.sum(np.array(최소) * )), float(np.sum(np.array(최대) * ))

for seed in (0, 1, 2):
    ,  = 임의분할상합하합(f, a, b, 300, seed)
    print(f"seed {seed} | 하합 {:.8f}  상합 {:.8f} | 1/3 이 사이에 있는가 : { < 1/3 < }")
seed 0 | 하합 0.33016211  상합 0.33652890 | 1/3 이 사이에 있는가 : True
seed 1 | 하합 0.33034011  상합 0.33634365 | 1/3 이 사이에 있는가 : True
seed 2 | 하합 0.32996709  상합 0.33672710 | 1/3 이 사이에 있는가 : True

실험 6 (1층) — 그림#

파란 몸통이 하합 \(L_n\)이고 그 위의 주황 띠가 차이 \(U_n - L_n\)이다.

# [7회] 상합과 하합의 그림
# 목적 : 차이에 해당하는 부분이 어디인지 눈으로 확인한다
# 층  : 1층
# 주의 : 세 그림 모두 유한한 n 에 대한 것이다

그림, 축들 = plt.subplots(1, 3, figsize=(13, 4.3))
for , n_ in zip(축들, (4, 10, 40)):
    계단함수그리기(, f, a, b, n_, 위치="위")
    계단함수그리기(, f, a, b, n_, 위치="아래")
    함수그리기(, f, a, b)
    ,  = 상합하합(f, a, b, n_)
    무대(, a, b, f"n = {n_}\n하합 {:.4f} / 상합 {:.4f}", y범위=(0, 1.1))

plt.tight_layout()
plt.show()
../_images/566b60ebbb1058358f2a7e8ccca9d36734dc8198fa745ce2527ae80d055227c2.png

\(n\)이 커지면 주황 띠가 얇아진다. 띠 전체의 넓이가 (7.17)의 \(b^3/n\)이다.

확인할 것

  1. 실험 3의 \(L_n\) 식에 \(n=1000\)을 대입한 값이 실험 1의 수치와 일치하는지 확인하자.

  2. 실험 3에서 \(1/3 - L_n\)의 식을 인수분해하고, \(n\ge1\)에서 양수인지 부호를 판정하자.

  3. 실험 2에서 quad의 값이 하합과 상합 사이에 있는지 확인하자.

  4. \(n\)을 아무리 키워도 하합이 \(1/3\)과 같아지는 일이 있는가. 실험 3의 식에서 판정하자.

네 번째 항목이 이 회차의 요점이다

\[ \frac{1}{3} - L_n = \frac{3n-1}{6n^2} \]

이며 \(n \ge 1\)에서 항상 양수이다. 따라서 어떤 \(n\)에 대해서도 \(L_n \ne 1/3\)이다.

적분값 \(1/3\)은 하합들의 최소상계로 정의된 것이지 어떤 하합의 값이 아니다. 5회에서 최소상계가 집합에 속하지 않을 수 있다고 한 것이 여기서 실제로 일어난다.

이 구분이 무너지면 적분을 “무한히 잘게 나눈 합”으로 읽게 된다. 정의 14에는 그런 과정이 없다.

짝이 되는 서술

7회 · 적분의 정의