23회 실험 · 제한이 답을 정한다#
이 실험
짝 서술 |
|
확인하는 것 |
제한 구간을 벗어나면 \(\arcsin(\sin x)\ne x\)가 되는 것을 본다. 도함수의 부호가 제한 구간에서 나온다는 것을 확인한다. 원의 넓이를 두 방법으로 구한다 |
이 노트북의 주제는 관례가 답을 바꾼다는 것이다.
서술 파트 1절이 “제한 구간은 관례이다”라고 했고 2절이 “부호를 확인하지 않으면 정해지지 않는다”고 했다. 두 말이 추상적으로 들리는데, 코드는 그 관례를 어겼을 때 나오는 값을 실제로 보여 준다.
1절이 \(\arcsin(\sin\pi)=0\)을 출력한다. 2절은 \(\cos(\arcsin x)\)가 언제나 양수인 것을 확인하고, 다른 구간을 골랐다면 어떻게 되는지를 나란히 놓는다.
5절이 이 회차의 결말이다. 20회 실험이 원 없이 \(\pi\)를 구했는데, 여기서는 그 \(\pi\)가 원의 넓이로 돌아온다.
서술 파트의 내용 |
여기서 확인하는 방법 |
|---|---|
1절이 구간을 넓히면 순단조가 깨지는 것을 본다 |
|
제한 구간을 잊는 실수 |
1절이 \(\arcsin(\sin x)\)를 세 점에서 계산한다 |
부호 확인 |
2절이 \(\cos(\arcsin x)\)의 부호를 본다 |
3절이 차분몫과 공식을 대조한다 |
|
4절이 상합·하합으로 \(\pi/4\)를 좁힌다 |
|
5절이 미분해 되돌린다 |
|
5절이 두 방법으로 넓이를 구한다 |
0. 준비#
# The integral of definition 7, used to check answers against the formulas
def lower_upper(f, a, b, n, samples=200):
points = np.linspace(a, b, n + 1)
left = points[:-1].reshape(n, 1)
right = points[1:].reshape(n, 1)
values = f(left + (right - left)
* np.linspace(0.0, 1.0, samples).reshape(1, samples))
return (float(np.sum(values.min(axis=1) * np.diff(points))),
float(np.sum(values.max(axis=1) * np.diff(points))))
1. 제한이 없으면 역함수가 없다#
보조정리 14이 \(\sin\)을 \(\left[-\frac{\pi}{2},\frac{\pi}{2}\right]\)에서만 순증가라고 했다. 구간을 넓히면 어떻게 되는지 본다.
# Strictly increasing on the restricted interval, and not on a wider one
for lo, hi, label in ((-np.pi / 2, np.pi / 2, "[-pi/2, pi/2]"),
(-np.pi, np.pi, "[-pi, pi]"),
(0.0, 2 * np.pi, "[0, 2pi]")):
grid = np.linspace(lo, hi, 4000)
rising = bool(np.all(np.diff(np.sin(grid)) > 0))
print(f"sin strictly increasing on {label:>16} : {rising}")
sin strictly increasing on [-pi/2, pi/2] : True
sin strictly increasing on [-pi, pi] : False
sin strictly increasing on [0, 2pi] : False
첫 줄만 참이다. 나머지 두 구간에서는 서로 다른 두 점이 같은 값을 가지므로 17회 정의 34의 조건이 깨진다.
그 결과가 무엇인지 본다.
# arcsin(sin x) returns x only inside the restricted interval
print(f"{'x':>12} {'sin x':>14} {'arcsin(sin x)':>16} {'equals x':>10}")
print("-" * 56)
for v in (0.5, 1.5, np.pi, 3.0, -2.0):
back = np.arcsin(np.sin(v))
print(f"{v:>12.6f} {np.sin(v):>14.9f} {back:>16.9f} "
f"{str(abs(back - v) < 1e-12):>10}")
x sin x arcsin(sin x) equals x
--------------------------------------------------------
0.500000 0.479425539 0.500000000 True
1.500000 0.997494987 1.500000000 True
3.141593 0.000000000 0.000000000 False
3.000000 0.141120008 0.141592654 False
-2.000000 -0.909297427 -1.141592654 False
\(x=\pi\)에서 \(\arcsin(\sin\pi)=0\)이다. \(\pi\)가 아니다.
\(\sin\pi = 0\)이고 \(\arcsin 0 = 0\)이므로 그렇게 된다. \(\arcsin\)은 제한 구간 안의 값만 돌려주므로 \(\pi\)를 돌려줄 수 없다.
반대 방향은 다르다.
# The other direction holds everywhere on [-1, 1]
print(f"{'y':>8} {'sin(arcsin y)':>16} {'equals y':>10}")
print("-" * 38)
for y in (-1.0, -0.4, 0.0, 0.7, 1.0):
back = np.sin(np.arcsin(y))
print(f"{y:>8} {back:>16.12f} {str(abs(back - y) < 1e-12):>10}")
y sin(arcsin y) equals y
--------------------------------------
-1.0 -1.000000000000 True
-0.4 -0.400000000000 True
0.0 0.000000000000 True
0.7 0.700000000000 True
1.0 1.000000000000 True
17회 (17.1)의 두 등식이 정의역이 다른 이유가 이것이다. \(f^{-1}(f(x))=x\)는 \(x\)가 제한된 정의역에 있어야 하고, \(f(f^{-1}(y))=y\)는 \(y\)가 치역에 있으면 된다.
가는 선이 제한 없는 \(\sin\)이다. 그 부분까지 뒤집으면 한 \(y\)에 여러 \(x\)가 대응하므로 함수가 되지 않는다.
2. 부호가 답을 정한다#
서술 파트 2절이 \(\cos(\arcsin x) = \sqrt{1-x^2}\)에서 양의 근호를 택하는 근거가 제한 구간이라고 했다.
# cos(arcsin x) is always the positive root, because arcsin lands in [-pi/2, pi/2]
print(f"{'x':>7} {'arcsin x':>12} {'cos of it':>14} {'+sqrt(1-x^2)':>15} {'same':>6}")
print("-" * 60)
for v in (-0.9, -0.2, 0.4, 0.95):
p = np.arcsin(v)
left = np.cos(p)
right = np.sqrt(1 - v ** 2)
print(f"{v:>7} {p:>12.6f} {left:>14.9f} {right:>15.9f} "
f"{str(abs(left - right) < 1e-12):>6}")
x arcsin x cos of it +sqrt(1-x^2) same
------------------------------------------------------------
-0.9 -1.119770 0.435889894 0.435889894 True
-0.2 -0.201358 0.979795897 0.979795897 True
0.4 0.411517 0.916515139 0.916515139 True
0.95 1.253236 0.312249900 0.312249900 True
\(\arcsin x\)가 언제나 \(\left[-\frac{\pi}{2},\frac{\pi}{2}\right]\) 안에 있고 그 구간에서 \(\cos \ge 0\)이므로 셋째 열이 양수이다.
다른 구간을 골랐다면 부호가 반대가 된다. \(\left[\frac{\pi}{2},\frac{3\pi}{2}\right]\)에서도 \(\sin\)은 순단조이므로 역함수가 있다.
# The other conventional choice: sin restricted to [pi/2, 3pi/2] is decreasing
def other_arcsin(y):
# solve sin(t) = y with t in [pi/2, 3pi/2]
return np.pi - np.arcsin(y)
print(f"{'x':>7} {'other inverse':>15} {'cos of it':>14} {'sign':>7}")
print("-" * 48)
for v in (-0.9, -0.2, 0.4, 0.95):
p = other_arcsin(v)
print(f"{v:>7} {p:>15.6f} {np.cos(p):>14.9f} "
f"{'negative' if np.cos(p) < 0 else 'positive':>7}")
x other inverse cos of it sign
------------------------------------------------
-0.9 4.261362 -0.435889894 negative
-0.2 3.342951 -0.979795897 negative
0.4 2.730076 -0.916515139 negative
0.95 1.888357 -0.312249900 negative
넷째 열이 모두 음수이다. 그 구간을 골랐다면 (23.3)의 부호가 반대였을 것이다.
\(\arcsin\)과 \(\arccos\)의 도함수가 부호만 다른 것도 확인해 둔다. 서술 파트가 그 둘의 합이 상수라고 했다.
# arcsin + arccos is constant, as cor-18-constant-diff predicts
for v in (-0.9, -0.3, 0.0, 0.5, 0.99):
total = np.arcsin(v) + np.arccos(v)
print(f"x = {v:>6} arcsin + arccos = {total:.15f}")
print()
print(f"pi/2 = {np.pi / 2:.15f}")
x = -0.9 arcsin + arccos = 1.570796326794897
x = -0.3 arcsin + arccos = 1.570796326794897
x = 0.0 arcsin + arccos = 1.570796326794897
x = 0.5 arcsin + arccos = 1.570796326794897
x = 0.99 arcsin + arccos = 1.570796326794897
pi/2 = 1.570796326794897
3. 도함수를 대조한다#
정리 77의 세 공식을 차분몫과 맞춘다.
# Difference quotients against the formulas of thm-23-inverse-deriv
def difference_quotient(f, p, step=1e-6):
return (f(p + step) - f(p - step)) / (2 * step)
print("arcsin")
print(f"{'x':>8} {'quotient':>17} {'1/sqrt(1-x^2)':>17} {'difference':>12}")
print("-" * 58)
for v in (-0.8, -0.3, 0.0, 0.5, 0.9):
q = difference_quotient(np.arcsin, v)
formula = 1.0 / np.sqrt(1 - v ** 2)
print(f"{v:>8} {q:>17.9f} {formula:>17.9f} {abs(q - formula):>12.2e}")
arcsin
x quotient 1/sqrt(1-x^2) difference
----------------------------------------------------------
-0.8 1.666666667 1.666666667 1.09e-11
-0.3 1.048284837 1.048284837 3.64e-11
0.0 1.000000000 1.000000000 1.67e-13
0.5 1.154700538 1.154700538 2.65e-11
0.9 2.294157339 2.294157339 1.72e-10
# The same for arctan, whose formula has no square root
print("arctan")
print(f"{'x':>8} {'quotient':>17} {'1/(1+x^2)':>17} {'difference':>12}")
print("-" * 58)
for v in (-2.0, -0.5, 0.0, 1.0, 5.0):
q = difference_quotient(np.arctan, v)
formula = 1.0 / (1 + v ** 2)
print(f"{v:>8} {q:>17.9f} {formula:>17.9f} {abs(q - formula):>12.2e}")
arctan
x quotient 1/(1+x^2) difference
----------------------------------------------------------
-2.0 0.200000000 0.200000000 5.75e-12
-0.5 0.800000000 0.800000000 4.75e-12
0.0 1.000000000 1.000000000 3.33e-13
1.0 0.500000000 0.500000000 4.11e-11
5.0 0.038461539 0.038461538 4.81e-11
\(\arctan\)의 도함수에는 근호가 없다. 유리함수이다. 그래서 (23.5)의 둘째 식이 유리함수의 적분에 삼각함수의 역함수를 답으로 준다.
4. π/4 를 두 방법으로#
(23.6)이 \(\int_0^1\frac{dx}{1+x^2} = \frac{\pi}{4}\)라고 했다. 7회의 방식으로 좁혀 맞춘다.
# Trapping the integral between step-function sums
print(f"{'n':>8} {'lower':>15} {'upper':>15} {'width':>11}")
print("-" * 52)
for n in (10, 100, 1000, 10000):
low, high = lower_upper(lambda t: 1.0 / (1 + t ** 2), 0.0, 1.0, n)
print(f"{n:>8} {low:>15.9f} {high:>15.9f} {high - low:>11.2e}")
print()
print(f"arctan 1 = {np.arctan(1.0):.12f}")
print(f"pi / 4 = {np.pi / 4:.12f}")
n lower upper width
----------------------------------------------------
10 0.759981497 0.809981497 5.00e-02
100 0.782893997 0.787893997 5.00e-03
1000 0.785148122 0.785648122 5.00e-04
10000 0.785373163 0.785423163 5.00e-05
arctan 1 = 0.785398163397
pi / 4 = 0.785398163397
왼쪽에는 삼각함수가 없다. 피적분함수가 유리함수이고 상합과 하합은 유리수 연산뿐이다. 그런데 그 값이 \(\pi/4\)이다.
\(\arctan 1 = \frac{\pi}{4}\)인 근거는 \(\tan\frac{\pi}{4}=1\)이고, 서술 파트가 배각공식으로 그것을 얻었다.
# tan(pi/4) = 1, from the double-angle identity the narrative derives
quarter = np.pi / 4
print(f"sin(pi/4) = {np.sin(quarter):.12f}")
print(f"1/sqrt(2) = {1 / np.sqrt(2):.12f}")
print(f"cos(pi/4) = {np.cos(quarter):.12f}")
print(f"tan(pi/4) = {np.tan(quarter):.12f}")
sin(pi/4) = 0.707106781187
1/sqrt(2) = 0.707106781187
cos(pi/4) = 0.707106781187
tan(pi/4) = 1.000000000000
배각공식 (23.7)도 확인한다.
# (23.7): cos^2 t = (1 + cos 2t) / 2
theta = sp.Symbol("theta", real=True)
print("cos^2 t - (1 + cos 2t)/2 =",
sp.simplify(sp.cos(theta) ** 2 - (1 + sp.cos(2 * theta)) / 2))
cos^2 t - (1 + cos 2t)/2 =
0
5. 원의 넓이#
정리 78을 확인한다. 서술 파트가 치환 정리를 쓰지 않고 원시함수를 확인한 뒤 정리 64를 직접 썼다.
먼저 (23.8)의 원시함수를 미분해 되돌린다.
# (23.8): differentiate the primitive back, on the open interval
G = (x * sp.sqrt(1 - x ** 2) + sp.asin(x)) / 2
print("G =", G)
print("G' =", sp.simplify(sp.diff(G, x)))
print("equals sqrt(1 - x**2) :",
sp.simplify(sp.diff(G, x) - sp.sqrt(1 - x ** 2)) == 0)
G = x*sqrt(1 - x**2)/2 + asin(x)/2
G' = sqrt(1 - x**2)
equals sqrt(1 - x**2) : True
이제 두 끝값의 차를 구한다.
# The fundamental theorem, applied to G on [-1, 1]
top = G.subs(x, 1)
bottom = G.subs(x, -1)
print("G(1) =", top, "=", float(top))
print("G(-1) =", bottom, "=", float(bottom))
print("difference =", sp.simplify(top - bottom), "=", float(top - bottom))
print("pi / 2 =", f"{np.pi / 2:.15f}")
G(1) = pi/4 = 0.7853981633974483
G(-1) = -pi/4 = -0.7853981633974483
difference = pi/2 = 1.5707963267948966
pi / 2 = 1.570796326794897
정의로도 확인한다. 상합과 하합이 그 값을 가두어야 한다.
# The same number, from step functions
half_disc = lambda t: np.sqrt(np.maximum(1 - t ** 2, 0.0))
low, high = lower_upper(half_disc, -1.0, 1.0, 20000)
print(f"lower sum {low:.9f}")
print(f"upper sum {high:.9f}")
print(f"pi / 2 {np.pi / 2:.9f}")
print(f"traps it {low <= np.pi / 2 <= high}")
lower sum 1.570695739
upper sum 1.570895739
pi / 2 1.570796327
traps it True
두 경로가 만난다. 위는 원시함수를 미분해 확인한 뒤 두 값을 뺀 것이고, 아래는 이만 개의 계단 넓이를 더한 것이다.
오른쪽 그림에서 조각을 늘리면 상합과 하합의 차가 줄어든다. 그 차가 \(0\)으로 가는 것이 7회 정의 15이 요구하는 것이다.
마치며#
\(\sin\)은 \(\left[-\frac{\pi}{2},\frac{\pi}{2}\right]\)에서만 순증가했고, 그 밖으로 넓히면 순단조가 깨졌다. \(\arcsin(\sin\pi)\)가 \(\pi\)가 아니라 \(0\)이었다.
\(\cos(\arcsin x)\)가 네 점 모두에서 양수였고, \(\left[\frac{\pi}{2},\frac{3\pi}{2}\right]\)로 제한한 다른 역함수에서는 모두 음수였다. (23.3)의 부호는 관례가 정한 것이다.
차분몫이 세 공식과 \(10^{-10}\) 안에서 맞았다.
\(\int_0^1\frac{dx}{1+x^2}\)을 상합과 하합으로 \([0.785373,\ 0.785423]\)까지 좁혔고 \(\pi/4\)가 그 안에 있었다. 왼쪽에는 삼각함수가 없는데 오른쪽에 \(\pi\)가 있다.
그리고 \(\int_{-1}^{1}\sqrt{1-x^2}\,dx\)를 두 방법으로 구해 \(\pi/2\)를 얻었다. 20회 실험이 원 없이 \(\pi\)를 구했는데, 여기서 그 수가 원의 넓이로 돌아왔다.
서술 파트의 내용 |
이 노트북의 코드 |
|---|---|
1절 세 구간의 |
|
제한 구간을 잊는 실수 |
1절 |
(17.1)의 두 등식 |
1절 두 방향 표 |
부호 확인 |
2절 |
\(\arcsin+\arccos\)가 상수 |
2절 다섯 점에서 같은 값 |
3절 두 차분몫 표 |
|
4절 상합·하합과 |
|
4절 |
|
5절 |
|
5절 |
더 해 볼 것#
1절의
other_arcsin으로 3절의 차분몫 표를 다시 뽑아 보자. 도함수의 부호가 어떻게 달라지는가. 그것이 서술 파트 2절의 부호 확인과 어떻게 이어지는가.4절의 적분 구간을 \([0,\sqrt3]\)으로 바꾸면 값이 얼마인가. \(\arctan\sqrt3\)이 무엇인지 짐작할 수 있는가.
5절의
lower_upper에서np.maximum을 빼면 무슨 일이 일어나는가. 왜 그 보호가 필요한지, 그것이 서술 파트의 「왜 치환으로 계산하지 않았는가」 상자와 어떻게 이어지는지 적어 보자.\(\int_{-1}^{1}\sqrt{1-x^2}\,dx\)를 \(x=\sin\theta\) 치환으로 계산해 보자. sympy 는 답을 주는가. 서술 파트가 그 경로를 쓰지 않은 이유를 다시 읽어 보자.
짝이 되는 서술