1-6-2. 함수호출로 계산시간을 단축해보기.
함수호출은
여러번 어떤 내용을 불러들이거나 저장해
시간이 오래걸리는 작업들을 해결해 나가는 작업을 다룹니다.
재귀 함수에 함수호출 적용해보기
재귀 : 자기 자신을 호출하는 것
자기 자신을 호출하여 연산을 진행하는 함수를 의미합니다.
중학교 수학시간에 배운 적 있는 팩토리얼을 재귀함수를 통해 표현하기
팩토리얼 수학 식
[n! = n * (n-1) * (n-2) * … * (n-(n-2)) * 1]
# 함수 선언 def factorial(n): # n이 0일 때 1을 반환 if n == 0: return 1 else: return n * factorial(n-1) # 함수 호출하기 print("1!:", factorial(1)) print("3!:", factorial(3)) print("100!:", factorial(100))
재귀 함수 문제
재귀함수는 특정한 상황(매우 많은 반복 처리)
이면 너무 많은 반복을 실행하는 것이 문제가 될 수 있습니다.
def fibonacci(n): if n== 1: return 1 elif n == 2: return 1 else: result = fibonacci(n-1) + fibonacci(n-2) print(result) return result print(fibonacci(50))
위의 코드를 실행해 보면
컴퓨터는 엄청나게 많은 연산을 하는것이 보이는데
빠르게 결과를 주지 못하는 것을 알 수 있습니다.
이와 관련된 내용을 확인해보기 위해
몇 번의 계산을 컴퓨터가 진행하는지 확인해보기
# 함수호출 counter = 0 def fibonacci(n): # 어떤 피보나치 수를 구하는지 출력 print("fibonacci({})를 구합니다.".format(n)) global counter counter += 1 if n== 1: return 1 elif n == 2: return 1 else: return fibonacci(n-1) + fibonacci(n-2) fibonacci(35) print("fibonacci(35) 계산에 활용된 덧셈 수는 {}번입니다.".format(counter))
위의 코드도 오랜 시간을 소비하여 덧셈을 한 횟수를 계산하여 줍니다.
피보나치 수열이 각각의 피보나치 수열을 덧셈을 한 번씩
이미 했던 계산이 있더라도 계산 회수가 엄청나게 많이 늘어나게 됩니다.
메모화
재귀함수의 위와 같은 문제로
읽기 쉽게 코드를 작성할 수 있으면서
같은 값은 한 번만 계산하도록 코드를 만들면
계산 속도 역시도 빨라질 것입니다.
# 메모 변수 선언 dictionary = { 1: 1, 2: 1 } def fibonacci(n): if n in dictionary: return dictionary[n] else: output = fibonacci(n-1) + fibonacci(n-2) dictionary[n] = output return output print("fibonacci(50): ", fibonacci(50)) print(dictionary)
메모화를 사용하면 곧바로 값이 출력될만큼 연산이 줄어들게됩니다.
dictionary를 출력해보면 어떤 값들이 연산에 사용되었는지가 출력됩니다.
조기 리턴
과거 프로그래밍에는 변수는
반드시 앞 쪽에 몰아서 선언하고
리턴은 반드시 뒤에서 해얗나느 규칙이있었지만
요즘에는 필요할 때 하면 된다는 식으로 변경되었습니다.
과거의 함수 흐름의 끝에 리턴을 적기 위해 코드를 작성하였지만
이제 흐름 중간에 return 키워드를 사용하는 것을 조기리턴이라고 합니다.
조기 리턴 예시
def fibonacci(n): if n in dictionary: # 메모되어 있으면 메모된 값 리턴 return dictionary[n] #메모 안되어있으면 값을 계산 output = fibonacci(n-1) + fibonacci(n-2) dictionary[n] = output return output
위와 같이 if 와 else를 사용하여
흐름을 명확히 구분하기 보다
이후 코드를 실행하는 상황을 막아
return을 해준 뒤
else를 없이 코드를 사용할 수 있도록
만들어주는 방식입니다.