파이썬으로 팩토리얼 알고리즘 구현하기
def facto(num):
result = 1
for i in range(num, 0, -1):
result = result * i
return result
팩토리얼이란 무엇일까?
팩토리얼은 1부터 어떤 숫자까지의 모든 숫자의 곱을 뜻한다.
표기는 숫자 + ! 로 표시한다.
표기법
2! -> 1 x 2 = 2
3! -> 1 x 2 x 3 = 6
4! -> 1 x 2 x 3 x 4 = 24
5! -> 1 x 2 x 3 x 4 x 5 = 120
위와 같이 된다.
읽을 때는 2팩토리얼, 3팩토리얼, 4팩토리얼... 이라고 읽는다.
주의점
팩토리얼에서 주의할 점이 몇 가지가 있는데,
첫째. 팩토리얼은 무조건 양의 정수만 취급한다.
둘째. 0! (0 팩토리얼)은 1이다.
셋째. 1! (1 팩토리얼)도 1이다.
위 세 가지만 명심하면 된다.
처음 배울 때 두번째 세번째 조항이 나는 상당히 거슬렸다.
아니 수학인데, 이렇게 예외를 두는게 어디있어?
2!는 1 x 2이고 3!은 1 x 2 x 3이니까 1!은 그냥 1인건 이해하지만,
0!은 0이어야지 왜 1인데! 이게 말이 돼?
... 라고 수학에 대해 1도 모르는 나는 생각했다.
도저히 이해가 안가던 나는 0!이 0이 되면 0 x 1 x 2 x 3 ... 를 했을 때 무조건 값이 0이 되어버리는 오류를 막기 위해서 그냥 0!은 1이다 라고 학자들이 임의로 정해놓은 거다 라고 생각했다.
허나... 그건 수학알못인 나의 추측일 뿐, 공식 자체에 근거가 있었다. 어쩐지. 수학이 그렇게 쉬울리가 없지. 아래 링크를 따라 가 보면 어째서 0!이 0이 아닌 1이 되는지 잘 설명되어 있다. (다만 내가 이해를 못했을 뿐)
0!은 왜 1일까? - 사물궁이 잡학지식
팩토리얼(factorial)은 자연수(=양의 정수)의 계승이라고도 합니다. 기호는 느낌표(!)를 사용하고, n이 양의 정수일 때 1부터 n까지의 곱을 n!이라고 합니다. 예를 들어서 3!(=6)은 1×2×3이고, 4!(=24)은 1
samulgoongi.com
0팩토리얼이 왜 1인가를 이해하지 못했다 하더라도 알고리즘을 짜는데는 전혀 상관이 없다.
그러니 바로 알고리즘을 작성해보겠다.
시작
def facto(num):
일단 함수 이름을 facto, 팩토라고 정의하겠다.
어차피 팩토리얼은 무조건 1부터 시작하기 때문에 마지막 값만 받으면 된다.
고로 매개변수는 하나만 준비한다.
num 이라고 이름 지어주었다.
이번에는 for 대신 while을 쓰겠다. 둘 중 무엇을 써도 상관없다.
다만 팩토리얼의 특성상 while이 더 어울린다고 생각해서 나는 while을 쓰는 것 뿐이다. (이는 사람마다 다를 것)
5!을 풀어쓰면 1 x 2 x 3 x 4 x 5 이지만, 5 x 4 x 3 x 2 x 1 로도 쓸 수 있다.
굳이 이렇게 순서를 거꾸로 쓰는 것은 재귀함수를 설명할 때 이해하기 편해서인데, 이 부분은 나중에 이야기하겠다. 지금은 그냥 아 거꾸로 해도 상관없지~ 라는 마음으로 임하자.
def facto(num):
while num > 0:
위 코드는 num이 0보다 큰 동안 계속 반복한다. 즉 num이 0이 되는 순간 반복이 끝난다.
def facto(num):
result = num
while num > 0:
아뿔싸, 계산을 시작하려고 보니 결과값을 담을 곳이 없다.
while문 밖에서 result 변수를 선언하고 num을 담아준다. 계산을 num부터 시작할 것이기 때문이다.
5팩토리얼이라면 5 x 4 x 3 x 2 x 1 이 되도록.
def facto(num):
result = 1
while num > 0:
num = num - 1 # 계산1
result = result * num # 계산2
그리고 이제 num은 1씩 깎아준다. 그리고 result에 1 깎인 num, 여기서는 4를 곱해준다.
현재 result = 5 * 4 가 된다.
이것을 계속해서 num이 1이 되었을 때는
result = 5 * 4 * 3 * 2 * 1 * 0 이 되게 된다.
num이 1일 때 0을 곱하기 때문에, 결과값이 0으로 도로아미타불이 되는 문제가 생긴다.
해결하는 방법은 여러가지가 있겠으나,
num이 0이 되는 순간, 곱하기 전에 그냥 반복문을 탈출하기로 하자.
그래서 아래처럼 탈출구문을 사이에 끼워준다.
def facto(num):
result = num
while num > 0:
num = num - 1 # 계산1
# 바로 여기 <num이 0이면 곱셈하기 전에 탈출하라>
if num == 0:
break
result = result * num # 계산2
마지막으로 계산이 끝난 result를 반환해주면 되겠다.
def facto(num):
result = num
while num > 0:
num = num - 1 # 계산1
# 바로 여기 <num이 0이면 탈출하라>
if num == 0:
break
result = result * num # 계산2
return result
실행해보자.
실행결과
print(facto(5))
120
print(facto(6))
720
잘 작동한다.
for문으로 짜기
이번에는 for문을 활용해서 짜보자.
result는 보통 초기화 할 때 0을 주지만, 이렇게 곱셈을 해야 할 때는 1을 주어야 한다.
그래야 전체 결과가 0이 되지 않는다.
# result 초기값을 1로 준 경우
def facto(num):
result = 1
for i in range(num, 0, -1):
result = result * i
return result
result를 1로 주는 게 약간 변칙?처럼 느껴져 뭔가 찜찜하다면 아래처럼 짤 수도 있다.
result에 num값을 주고 시작하는 것이다.
그러면 for문의 범위가 조금 지저분해지긴 한다.
이래나 저래나 오작동 없이 값만 잘 나오면 된다. (쑻)
# result 초기값을 num으로 준 경우
def facto(num):
result = num
for i in range(num - 1, 0, -1):
result = result * i
return result
위 두 코드는 그냥 맥락의 차이일 뿐 결과는 동일하다.
num부터 시작해서 0까지 1씩 차감하며 내려가는데, range()의 특성상 마지막값 0은 포함하지 않으므로 자연스레 1에서 반복이 끝나게 된다.
따라서 5 x 4 x 3 x 2 x 1 이 된다.
이렇게 저렇게 다양한 방법으로 짜보았다. 본인이 마음에 드는 스타일로 짜면 되겠다.