극좌표와 매개변수 곡선 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""극좌표와 매개변수 곡선 검증.
문서: 17.극좌표와 매개변수 곡선 (예시, 정의, 예제, 카드 C1~C3)
주장 1: (-1, √3)은 극좌표 (2, 2π/3), 극좌표 (3, π/6)은 (3√3/2, 3/2).
주장 2: (r, θ)와 (r, θ + 2πk)는 같은 점이다.
주장 3: (2 cos t, 2 sin t)와 (2 cos 2t, 2 sin 2t)는 모두 x² + y² = 4 위에 있고, 둘째가 두 배 빠르다.
주장 4: 선형 보간 P + t(Q - P)에서 (0, 0) -> (4, 2)의 t = 0.25는 (1, 0.5), t = 0.5는 (2, 1).
주장 5: 포물선 운동 (vt cos α, vt sin α - ½gt²)는 v = 20, α = 45°, g = 9.8에서 약 40.8 m 떨어진 곳에 떨어진다 (v² sin 2α / g).
"""
import math
def to_polar(x, y):
return math.hypot(x, y), math.atan2(y, x)
def main():
r, t = to_polar(-1, math.sqrt(3))
assert math.isclose(r, 2) and math.isclose(t, 2 * math.pi / 3)
x, y = 3 * math.cos(math.pi / 6), 3 * math.sin(math.pi / 6)
assert math.isclose(x, 3 * math.sqrt(3) / 2) and math.isclose(y, 1.5)
print("[OK] 주장 1·카드 C1")
for k in (-3, -1, 1, 5):
assert math.isclose(2 * math.cos(1 + 2 * math.pi * k), 2 * math.cos(1)) and math.isclose(2 * math.sin(1 + 2 * math.pi * k), 2 * math.sin(1))
print("[OK] 주장 2: 각에 2πk를 더해도 같은 점")
for i in range(1000):
t = i / 100
p1 = (2 * math.cos(t), 2 * math.sin(t)); p2 = (2 * math.cos(2 * t), 2 * math.sin(2 * t))
assert math.isclose(p1[0] ** 2 + p1[1] ** 2, 4) and math.isclose(p2[0] ** 2 + p2[1] ** 2, 4)
h = 1e-6
speed = lambda f, t: math.dist(f(t + h), f(t)) / h
f1 = lambda t: (2 * math.cos(t), 2 * math.sin(t)); f2 = lambda t: (2 * math.cos(2 * t), 2 * math.sin(2 * t))
assert math.isclose(speed(f1, 0.3), 2, rel_tol=1e-5) and math.isclose(speed(f2, 0.3), 4, rel_tol=1e-5)
print("[OK] 주장 3·카드 C2: 같은 원, 속력 2와 4")
lerp = lambda P, Q, t: (P[0] + t * (Q[0] - P[0]), P[1] + t * (Q[1] - P[1]))
assert lerp((0, 0), (4, 2), 0.25) == (1, 0.5) and lerp((0, 0), (4, 2), 0.5) == (2, 1)
print("[OK] 주장 4·카드 C3: 선형 보간")
v, a, g = 20, math.radians(45), 9.8
T = 2 * v * math.sin(a) / g
xr = v * T * math.cos(a)
assert math.isclose(xr, v * v * math.sin(2 * a) / g) and f"{xr:.1f}" == "40.8"
yT = v * T * math.sin(a) - 0.5 * g * T * T
assert abs(yT) < 1e-9
print(f"[OK] 주장 5: 사거리 {xr:.2f} m")
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()