Part 2는 Part 1에서 배운 파이썬 기본 문법(리스트, 함수, 조건문, 반복문)을 활용하여 고등학교 수학의 핵심 주제 중 하나인 다항식과 방정식을 다루는 방법을 보여줍니다.
Part 2: 파이썬으로 고등학교 수학 정복하기
Chapter 7: 다항식과 방정식 풀이
학습 목표
- 다항식을 파이썬 리스트를 이용하여 표현할 수 있다.
- 주어진 x 값에 대한 다항식의 값을 계산하는 파이썬 함수를 만들 수 있다.
- 이차방정식의 근의 공식을 파이썬 함수로 구현하고 활용할 수 있다.
- 판별식을 이용하여 이차방정식 근의 종류(실근, 중근, 허근)를 판별하는 코드를 작성할 수 있다.
- (심화) 간단한 수치 해법인 이분법(Bisection Method)의 원리를 이해하고, 이를 이용하여 고차방정식의 실근의 근삿값을 구할 수 있다.
1. 문자와 숫자의 만남: 다항식과 방정식
다항식(Polynomial)은 3x² - 5x + 2
와 같이 숫자와 문자(변수)의 거듭제곱으로 이루어진 항들의 합 또는 차로 구성된 식입니다. 다항식은 함수의 기본 형태로, 다양한 수학적 모델링과 문제 해결에 사용됩니다.
방정식(Equation)은 등호(=)를 사용하여 두 식 또는 값이 같음을 나타내는 식입니다. 특히, 3x² - 5x + 2 = 0
과 같이 다항식을 포함하는 방정식을 푸는 것, 즉 등식을 만족시키는 미지수(변수 x
)의 값을 찾는 것은 수학의 중요한 문제입니다. 이 해를 근(root)이라고 합니다.
고등학교 과정에서는 주로 일차방정식, 이차방정식을 다루고, 삼차 이상의 고차방정식의 인수분해나 간단한 해법을 배웁니다. 파이썬은 이러한 다항식을 표현하고, 값을 계산하며, 방정식의 해를 구하는 과정을 돕는 유용한 도구가 될 수 있습니다.
2. 파이썬 리스트로 다항식 표현하기
다항식을 파이썬으로 어떻게 표현할 수 있을까요? 한 가지 간단하고 효과적인 방법은 다항식의 계수(coefficient)들을 내림차순(descending order)으로 리스트에 저장하는 것입니다.
P(x) = 3x² - 5x + 2
=>p = [3, -5, 2]
(x²의 계수, x의 계수, 상수항 순서)Q(x) = x³ + 0x² - 7x - 1
=>q = [1, 0, -7, -1]
(x³의 계수, x²의 계수, x의 계수, 상수항 순서. 없는 항의 계수는 0으로 채움)R(x) = 4x + 8
=>r = [4, 8]
(x의 계수, 상수항)
이 방식은 다항식의 차수를 리스트의 길이 (len(p) - 1
)로 쉽게 알 수 있고, 각 항의 계수를 인덱스를 통해 접근할 수 있다는 장점이 있습니다.
# 다항식 P(x) = 3x^2 - 5x + 2 표현
p_coeffs = [3, -5, 2]
# 다항식 Q(x) = x^3 - 7x - 1 표현
q_coeffs = [1, 0, -7, -1]
print(f"P(x)의 계수: {p_coeffs}")
print(f"Q(x)의 계수: {q_coeffs}")
3. 다항식 값 계산 함수 만들기
다항식의 계수를 리스트로 표현했다면, 주어진 x
값에 대한 다항식의 값 P(x)
를 계산하는 함수를 만들 수 있습니다. 예를 들어 P(x) = 3x² - 5x + 2
에 x=2
를 대입하면 P(2) = 3*(2)² - 5*(2) + 2 = 12 - 10 + 2 = 4
입니다.
이를 계산하는 함수 evaluate_poly(coeffs, x)
를 만들어 봅시다.
def evaluate_poly(coeffs, x):
"""
계수 리스트 coeffs와 값 x를 입력받아 다항식의 값을 계산하여 반환.
coeffs는 내림차순 계수 리스트 (예: [a_n, a_{n-1}, ..., a_1, a_0])
"""
result = 0
degree = len(coeffs) - 1 # 다항식의 차수
for i in range(degree + 1):
# 계수 coeffs[i]는 x^(degree - i) 항의 계수임
term_value = coeffs[i] * (x ** (degree - i))
result = result + term_value
return result
# P(x) = 3x^2 - 5x + 2 (coeffs = [3, -5, 2])
p_coeffs = [3, -5, 2]
# x=2 에서의 값 계산
value_at_2 = evaluate_poly(p_coeffs, 2)
print(f"P(2) = {value_at_2}") # 출력: 4.0 (거듭제곱 결과가 float일 수 있음)
# x=0 에서의 값 계산 (상수항과 같아야 함)
value_at_0 = evaluate_poly(p_coeffs, 0)
print(f"P(0) = {value_at_0}") # 출력: 2.0
# Q(x) = x^3 - 7x - 1 (coeffs = [1, 0, -7, -1])
q_coeffs = [1, 0, -7, -1]
# x=-1 에서의 값 계산 (-1 - 0 + 7 - 1 = 5)
value_q_at_neg1 = evaluate_poly(q_coeffs, -1)
print(f"Q(-1) = {value_q_at_neg1}") # 출력: 5.0
(참고) 호너의 방법 (Horner's Method): 다항식 값을 더 효율적으로 계산하는 방법도 있습니다. P(x) = ((3*x - 5)*x + 2)
와 같이 계산하면 곱셈 횟수를 줄일 수 있습니다.
def evaluate_poly_horner(coeffs, x):
result = 0
for coeff in coeffs:
result = result * x + coeff
return result
print(f"P(2) (Horner) = {evaluate_poly_horner(p_coeffs, 2)}") # 4.0
print(f"Q(-1) (Horner) = {evaluate_poly_horner(q_coeffs, -1)}") # 5.0
4. 이차방정식의 해결사: 근의 공식과 판별식
이차방정식 ax² + bx + c = 0
(단, a ≠ 0
) 의 해(근)는 근의 공식으로 구할 수 있습니다.
근의 공식: x = (-b ± sqrt(b² - 4ac)) / (2a)
여기서 근호 안의 b² - 4ac
를 판별식(Discriminant) 이라고 하며, 보통 D
로 나타냅니다. 판별식의 부호에 따라 이차방정식 근의 종류가 결정됩니다.
D > 0
: 서로 다른 두 실근D = 0
: 중근 (하나의 실근)D < 0
: 서로 다른 두 허근 (고등학교 과정에서는 보통 '실근이 없다'고 표현)
파이썬으로 근의 공식 함수 만들기
Chapter 6에서 함수 만들기를 배웠습니다. 이를 활용하여 이차방정식의 계수 a, b, c
를 입력받아 근을 계산하는 함수를 만들어 봅시다. 제곱근 계산을 위해 math.sqrt
또는 cmath.sqrt
(복소수 지원)가 필요합니다.
import math # 실수 범위 근 계산
import cmath # 복소수 범위 근 계산 (D < 0 인 경우)
def solve_quadratic(a, b, c, use_complex=False):
"""
이차방정식 ax^2 + bx + c = 0 의 근을 계산하여 반환.
use_complex=True 이면 복소수 근까지 계산.
결과는 근을 담은 튜플 또는 리스트로 반환.
"""
if a == 0:
print("오류: a는 0이 될 수 없습니다 (이차방정식이 아님).")
if b != 0:
return (-c / b,) # 일차방정식 해 반환 (튜플)
elif c == 0:
return ("무수히 많은 해",)
else:
return ("해가 없음",)
# 판별식 계산
D = b**2 - 4*a*c
if D > 0: # 서로 다른 두 실근
sqrt_D = math.sqrt(D)
x1 = (-b + sqrt_D) / (2*a)
x2 = (-b - sqrt_D) / (2*a)
print(f"판별식 D = {D} > 0, 서로 다른 두 실근:")
return (x1, x2)
elif D == 0: # 중근
x = -b / (2*a)
print(f"판별식 D = {D} = 0, 중근:")
return (x,) # 하나의 근만 튜플에 담아 반환
else: # D < 0
if use_complex: # 복소수 근 계산 요청 시
sqrt_D_complex = cmath.sqrt(D) # 복소수 제곱근 계산
x1 = (-b + sqrt_D_complex) / (2*a)
x2 = (-b - sqrt_D_complex) / (2*a)
print(f"판별식 D = {D} < 0, 서로 다른 두 허근:")
return (x1, x2)
else: # 복소수 계산 안 함 (고등학교 기본)
print(f"판별식 D = {D} < 0, 실근이 없습니다.")
return None # 실근 없음을 None으로 반환
# 예제 1: x^2 - 5x + 6 = 0 (a=1, b=-5, c=6) -> D=1, 해=2, 3
roots1 = solve_quadratic(1, -5, 6)
print(f"해: {roots1}") # 출력: (3.0, 2.0)
# 예제 2: x^2 - 4x + 4 = 0 (a=1, b=-4, c=4) -> D=0, 해=2 (중근)
roots2 = solve_quadratic(1, -4, 4)
print(f"해: {roots2}") # 출력: (2.0,)
# 예제 3: x^2 + 2x + 5 = 0 (a=1, b=2, c=5) -> D=-16, 실근 없음
roots3 = solve_quadratic(1, 2, 5)
print(f"해: {roots3}") # 출력: None
# 예제 3 (복소수 근 포함):
roots3_complex = solve_quadratic(1, 2, 5, use_complex=True)
print(f"해 (복소수 포함): {roots3_complex}") # 출력: ((-1+2j), (-1-2j)) (j는 허수 단위)
이 함수를 이용하면 어떤 이차방정식이든 쉽게 근을 구할 수 있고, 판별식을 통해 근의 종류도 알 수 있습니다.
5. 고차방정식의 근사 해 찾기: 이분법 (Bisection Method)
삼차 이상의 고차방정식은 일반적인 근의 공식이 없거나 매우 복잡합니다. 인수분해가 쉽게 되지 않는 경우 해를 정확히 구하기 어려울 수 있습니다. 하지만 수치 해법(Numerical Method)을 이용하면 방정식의 실근의 근삿값을 원하는 정밀도까지 구할 수 있습니다.
가장 간단한 수치 해법 중 하나가 이분법(Bisection Method)입니다. 이분법은 사이값 정리(Intermediate Value Theorem)에 기반합니다.
- 사이값 정리: 함수
f(x)
가 닫힌 구간[a, b]
에서 연속이고f(a)
와f(b)
의 부호가 다르면 (f(a) * f(b) < 0
),a
와b
사이에f(c) = 0
인c
(즉, 해)가 적어도 하나 존재한다.
이분법의 아이디어:
해(근)가 존재할 것으로 예상되는 구간
[a, b]
를 설정합니다. 이때f(a)
와f(b)
의 부호는 달라야 합니다 (f(a) * f(b) < 0
).구간의 중점
m = (a + b) / 2
을 계산합니다.f(m)
의 값을 계산합니다.- 만약
f(m)
이 0에 매우 가까우면 (또는 정확히 0이면),m
을 근사 해로 간주하고 종료합니다. - 만약
f(a)
와f(m)
의 부호가 다르면(f(a) * f(m) < 0
), 해는 구간[a, m]
안에 존재합니다. 따라서 새로운 구간으로[a, m]
을 설정합니다 (b = m
). - 만약
f(m)
과f(b)
의 부호가 다르면(f(m) * f(b) < 0
), 해는 구간[m, b]
안에 존재합니다. 따라서 새로운 구간으로[m, b]
를 설정합니다 (a = m
).
- 만약
원하는 정밀도에 도달할 때까지 (즉, 구간의 길이
b - a
가 충분히 작아질 때까지) 2~3 단계를 반복합니다.
파이썬으로 이분법 구현하기
def bisection_method(func, a, b, tolerance=1e-7, max_iterations=100):
"""
이분법을 사용하여 구간 [a, b]에서 함수 func의 근의 근삿값을 찾는다.
tolerance: 원하는 오차 한계 (구간 길이)
max_iterations: 최대 반복 횟수 (무한 루프 방지)
"""
fa = func(a)
fb = func(b)
if fa * fb >= 0:
print(f"오류: 구간 [{a}, {b}]에서 f(a)와 f(b)의 부호가 같거나 0입니다.")
print(f"f({a})={fa}, f({b})={fb}")
return None
for i in range(max_iterations):
m = (a + b) / 2
fm = func(m)
# 종료 조건 1: 중점에서의 함수값이 거의 0인가?
if abs(fm) < tolerance:
print(f"{i+1}회 반복: f(m)이 0에 가까워 종료.")
return m
# 종료 조건 2: 구간의 길이가 충분히 작아졌는가?
if (b - a) / 2 < tolerance:
print(f"{i+1}회 반복: 구간 길이가 충분히 작아져 종료.")
return m
# 구간 갱신
if fa * fm < 0: # 해가 [a, m] 구간에 있음
b = m
fb = fm # fb 값 갱신 (효율성)
else: # 해가 [m, b] 구간에 있음 (fa*fm >= 0 이어야 함)
a = m
fa = fm # fa 값 갱신 (효율성)
# 최대 반복 횟수에 도달한 경우
print(f"경고: 최대 반복 횟수({max_iterations})에 도달했습니다.")
return (a + b) / 2 # 현재까지 찾은 최선의 근사값 반환
# 예제: f(x) = x^3 - x - 2 = 0 의 근 찾기
# f(1) = 1 - 1 - 2 = -2
# f(2) = 8 - 2 - 2 = 4
# 따라서 구간 [1, 2] 안에 근이 존재함
def my_cubic_func(x):
return x**3 - x - 2
root_approx = bisection_method(my_cubic_func, 1, 2)
if root_approx is not None:
print(f"f(x) = x^3 - x - 2 = 0 의 근사 해: {root_approx:.7f}")
# 근삿값을 원래 함수에 대입하여 검증
print(f"f(근사 해) ≈ {my_cubic_func(root_approx):.7f}") # 0에 가까운 값이어야 함
이분법은 비교적 구현이 간단하고 안정적으로 해를 찾을 수 있지만, 수렴 속도가 다른 수치 해법(예: 뉴턴의 방법)에 비해 느릴 수 있습니다. 하지만 고차방정식의 실근의 존재 유무를 확인하고 근삿값을 구하는 강력한 도구입니다.
연습 문제
- 다항식
P(x) = 2x⁴ - 3x² + x - 5
를 계수 리스트로 표현하고,x = -2
에서의 값을evaluate_poly
함수를 이용해 계산하세요. - 이차방정식
3x² + 7x - 6 = 0
의 근을solve_quadratic
함수를 이용해 구하세요. - 이차함수
y = x² - 6x + 9
의 그래프가 x축과 몇 개의 점에서 만나는지 판별식(D
)을 이용하여 확인하고,solve_quadratic
함수로 구한 해와 비교해보세요. - 방정식
cos(x) = x
의 해는 0과 1 사이에 존재합니다. (f(x) = cos(x) - x
로 두고f(0)
와f(1)
의 부호 확인)bisection_method
함수를 이용하여 이 해의 근삿값을 소수점 6자리 정확도로 구해보세요. (힌트:math.cos
사용)
이번 장에서는 파이썬 리스트와 함수를 이용하여 다항식을 표현하고 계산하며, 이차방정식의 해를 구하는 방법을 배웠습니다. 또한, 수치 해법인 이분법을 통해 고차방정식의 근삿값을 구하는 방법도 맛보았습니다. 다음 장에서는 파이썬의 강력한 시각화 도구인 Matplotlib를 이용하여 함수의 그래프를 직접 그려보고 분석하는 방법을 배우겠습니다.
COMMENTS