부분적분 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""부분적분 검증.
문서: 14.부분적분 (예시, 표 방법, 예제, 활용, 카드 C1~C3), 4.연습문제/14.적분 계산 예제 사다리
주장 1: 원시함수 — (x-1)e^x, (x²-2x+2)e^x, x ln x - x, e^x(sin x - cos x)/2, x sin x + cos x, (1/2)e^{x²}의
도함수가 각각의 피적분함수와 같다(수치 미분).
주장 2: 카드 C2 ∫_1^e ln x = 1.
주장 3: ∫_0^∞ x^n e^{-x} dx = n! (n = 0..6, [0, 60]에서 수치 적분).
주장 4: 푸리에 계수 ∫_{-π}^{π} x sin(kx) dx = 2π(-1)^{k+1}/k (k = 1..6).
주장 5: 사다리 — ∫ x cos x, ∫_0^1 x e^{x²} = (e-1)/2, ∫ x² e^x, ∫_1^e x ln x = (e²+1)/4,
변형 ∫_0^π e^x sin x = (e^π + 1)/2, ∫_0^{π/2} x sin x = 1.
"""
import math
def d(f, x, h=1e-6):
return (f(x + h) - f(x - h)) / (2 * h)
def simpson(f, a, b, n=20000):
dx = (b - a) / n
s = f(a) + f(b) + 4 * sum(f(a + i * dx) for i in range(1, n, 2)) + 2 * sum(f(a + i * dx) for i in range(2, n, 2))
return s * dx / 3
def main():
pairs = [
(lambda x: (x - 1) * math.exp(x), lambda x: x * math.exp(x)),
(lambda x: (x * x - 2 * x + 2) * math.exp(x), lambda x: x * x * math.exp(x)),
(lambda x: x * math.log(x) - x, math.log),
(lambda x: math.exp(x) * (math.sin(x) - math.cos(x)) / 2, lambda x: math.exp(x) * math.sin(x)),
(lambda x: x * math.sin(x) + math.cos(x), lambda x: x * math.cos(x)),
(lambda x: 0.5 * math.exp(x * x), lambda x: x * math.exp(x * x)),
(lambda x: x * x / 2 * math.log(x) - x * x / 4, lambda x: x * math.log(x)),
]
for F, f in pairs:
for x in (0.5, 1.3, 2.2):
assert abs(d(F, x) - f(x)) < 1e-5 * max(1, abs(f(x)))
print("[OK] 주장 1·카드 C1·C3: 원시함수 7개")
assert abs(simpson(math.log, 1, math.e) - 1) < 1e-10
print("[OK] 주장 2·카드 C2: ∫_1^e ln x = 1")
for n in range(7):
v = simpson(lambda x: x ** n * math.exp(-x), 0, 60, 60000)
assert abs(v - math.factorial(n)) < 1e-8 * math.factorial(n)
print("[OK] 주장 3: ∫_0^∞ xⁿe^{-x} = n!")
for k in range(1, 7):
v = simpson(lambda x: x * math.sin(k * x), -math.pi, math.pi)
assert abs(v - 2 * math.pi * (-1) ** (k + 1) / k) < 1e-9
print("[OK] 주장 4: 푸리에 계수")
assert abs(simpson(lambda x: x * math.exp(x * x), 0, 1) - (math.e - 1) / 2) < 1e-10
assert abs(simpson(lambda x: x * math.log(x), 1, math.e) - (math.e ** 2 + 1) / 4) < 1e-10
assert abs(simpson(lambda x: math.exp(x) * math.sin(x), 0, math.pi) - (math.exp(math.pi) + 1) / 2) < 1e-8
assert abs(simpson(lambda x: x * math.sin(x), 0, math.pi / 2) - 1) < 1e-10
print("[OK] 주장 5: 사다리의 정적분 값")
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()