본문 바로가기
컴퓨터

[파이썬03]피보나치 수열

by Oh 선생 2019. 12. 27.

3장 피보나치 수열

0. Introduction

지금까지 파이썬의 입출력, 조건, 제어문, 함수 등을 간략하게 배웠습니다. 사실 이것 말고도 시퀀스형 자료라던가 배워야 할 것들이 많은데 그렇게 하나하나 배워가다간 아무래도 재미가 없기 쉽습니다. 원래 코딩은 뭔가 흥미로운 프로젝트를 돌리면서 배워야 금방 늘거든요. 그래서 이번엔 조금 난이도가 높더라도, 피보나치 수열에 대한 코드를 몇 가지 짜보겠습니다.

1. 피보나치 수열 개관

티스토리 블로그는 수식 넣은 글 쓰기가 힘들다. 캡처로 대체. 

2. 피보나치 수열 만들기

, 코딩을 통해 피보나치 수열을 생성해봅시다. 이제 제법 뭐 하는 것 같죠?

def  fibo(n):
    if n==1:
        return [1]
    if n==2:
        return [1,1]
    #n>2
    a=1
    b=1
    series=[a,b]
    for i in range(n-2):
        c=a+b
        series.append(c)
        a=b
        b=c
    return series
try:
    n=int(input('피보나치 수열을 몇 항까지 만들까요?:'))
    print(fibo(n))
except ValueError:
    print('잘못된 입력입니다. 프로그램을 종료합니다.')

프로그램의 실행결과는 다음과 같습니다.

코드를 해석해봅시다.

def fibo(n):
    if n==1:
        return [1]
    if n==2:
        return [1,1]
    a=1
    b=1
    series=[a,b]
    for i in range(n-2):
        c=a+b
        series.append(c)
        a=b
        b=c
    return series

이 부분은 피보나치 수열을 생성하는 함수 fibo(n)을 정의하는 부분입니다. fibo()n을 집어넣었죠? 함수의 값이 n에 의해 결정될 때 fibo(n)과 같은 방식으로 작성해줍니다. return은 함수의 값으로 무엇을 할당할 것인가를 설정하는 구문입니다. 이 경우 만약 n1이라면, [1]이라는걸 fibo(1)의 값으로 돌려주는 겁니다. 그런데 [1]이 뭔지 모르겠죠?

[1]리스트라고 하는 자료형을 말합니다. 지금까지 다룬 정수, 문자, 실수 등의 자료형이 한 개의 값만을 담고 있는 자료형이라면, 리스트는 여러 개의 값을 담을 수 있는 자료형이라고 보면 됩니다. 주머니라고 생각하세요. [1]은 그 주머니에 1만 담아둔 겁니다. 만약 n=2일 떈 어떻게 하라고 하나요? [1,1]을 반환하라 하고 있습니다. 여기까지는 피보나치 수열의 1, 2번째 항을 직접 만들어 반환해주고 있는 겁니다. 그런데 천년만년 그럴 순 없잖아요. 3이상의 n에 대해서는 그 다음 부분에 의해 피보나치 수열을 만듭니다.

우선 a=1, b=1을 통해 수열의 초항 2개를 결정해줍니다. 그리고 series=[a,b]라는 구문을 통해 series라는 변수에 [a,b]라는 두 수를 담은 리스트를 할당해주는 거지요. 이때 series에는 리스트 [1,1]이 들어 있는 겁니다.

이제 for i in range(n-2)를 봅시다. i를 몇 번 반복하나요? n-2번 반복합니다. 왜냐하면 앞의 두 항 1, 1은 이미 series 리스트에 들어있기 때문입니다. 이제 실제로 뭘 반복하나 봅시다. c=a+b는 앞의 두 항으로 결정되는 새로운 항을 말합니다. 그리고 series.append(c)series라는 리스트에 c라는 원소를 더 넣으라는 명령어입니다. 리스트에는 (리스트명).append(대상) 과 같은 형식을 통해 새로운 원소를 집어넣을 수 있습니다.

그리고 다음 줄에선 a=b, b=c를 통해 ab에 다시 지금 만들어진 수열의 마지막 항 2, 즉 새로운 항을 만들 때 사용될 항들을 할당해주고 있는 겁니다. 이해되나요? 처음엔 a=1, b=1이고, 그래서 c=2를 만들었다면, 그 다음엔 12를 이용해서 3을 만들어야 하잖아요. 그래서 a=1(=b), b=2(=c)로 수를 바꿔주는 겁니다. 그리고 마지막엔 return series를 통해 함수의 값으로 series 리스트를 반환해주는 거구요.

try:
    n=int(input('피보나치 수열을 몇 항까지 만들까요?:'))
    print(fibo(n))
except ValueError:
    print('잘못된 입력입니다. 프로그램을 종료합니다.')

try except 구문은 처음 보지요? 사실 이 부분은 생략해도 좋은 부분입니다만, 교육 목적상 넣어뒀습니다. try-except 구문은 이상이 없을 땐 try 이후의 코드를 실행하고, 이상이 있을 땐 except 이후의 코드를 실행하도록 하는 구문입니다. try: 이후에는 피보나치수열을 몇 항까지 만들지 물어보고, 이를 정수로 바꿔서 n에 저장하고 있지요. 그리고 앞서 만든 fibo함수에 n을 대입해 series를 반환받고, 그 내용을 print하는 코드입니다. except 이후에는 에러의 종류를 적어둡니다. ValueErrorn에 문자열 등을 넣어 에러가 났을 때 뜨는 에러메시지 입니다. 이 경우엔 ValueError가 뜬다면 잘못된 입력입니다. ...’ 가 뜨도록 작성된 겁니다.

 

3. 피보나치 수열의 연속된 두 항의 비

, 이번엔 피보나치 수열의 연속된 두 항의 비를 구해봅시다.

def  fibo(n):
    if n==1:
        return [1]
    if n==2:
        return [1,1]
    #n>2
    a=1
    b=1
    series=[a,b]
    for i in range(n-2):
        c=a+b
        series.append(c)
        a=b
        b=c
    return series
try:
    n=int(input('피보나치 수열을 몇 항까지 만들까요?:'))
    print(fibo(n))
except ValueError:
    print('잘못된 입력입니다. 프로그램을 종료합니다.')
else:
    rr=fibo(n)
    ratio=[0]
    for i in range(n-1):
       ratio.append(rr[i+1]/rr[i])
    print('피보나치 수열=',rr)
    print('이웃하는 두 항 사이의 비=',ratio)

윗 부분은 앞서 만든 코드와 다르지 않습니다. else: 이후의 부분만 설명하겠습니다.

rr이라는 변수에 fibo함수로 만들어진 series리스트를 대입해줍니다. 그리고 두 항의 비를 저장할 ratio라는 리스트를 ratio=[0] 명령어를 통해 만들어줍니다. 항이 n개면, 두 항의 비는 n-1번 만들 수 있겠지요? ratio라는 리스트에 rr[i+1]/rr[i] 명령어를 통해 두 항의 비를 넣어주고 있는 겁니다. 그리고 인쇄를 해주는 거지요.

여기에서 rr[i+1]이 뭔지 모르겠지요? 이는 rr이라는 리스트에서, i+1번째 원소를 가져오라는 명령어입니다. rr[i]i번째 원소를 가져오라는 거구요. 그러면 rr[i+1]/rr[i]가 두 항의 비를 만든다는 게 이해가 되지요?

else, try-except-else 문에서 사용된 겁니다. try를 일단 하고, ValueError가 생기면 except를 실행하고, 별일 없으면 else 뒤를 이어서 실행하라는 명령입니다. 실행 화면은 다음과 같습니다.

두 항의 비가 거의 1.618에 가까워지는 게 눈에 보이지요? , 그런데 이렇게 수치로만 나타내면 아무래도 보기가 영 좋지 않습니다. 이번에는 이웃하는 두 항의 비를 그래프로(!) 나타내어 봅시다.

import matplotlib.pyplot as plt
def  fibo(n):
    if n==1:
        return [1]
    if n==2:
        return [1,1]
    a=1
    b=1
    series=[a,b]
    for i in range(n-2):
        c=a+b
        series.append(c)
        a=b
        b=c
    return series
try:
    n=int(input('피보나치 수열을 몇 항까지 만들까요?:'))
    print(fibo(n))
except ValueError:
    print('잘못된 입력입니다. 프로그램을 종료합니다.')
else:
    rr=fibo(n)
    ratio=[0]
    for i in range(n-1):
       ratio.append(rr[i+1]/rr[i])
    print('피보나치 수열=',rr)
    plt.plot(range(n),ratio)
    plt.xlabel('No.')
    plt.ylabel('Ratio')
    plt.title('Ratio between consecutive Fibonacci numbers')
    plt.axis([0,len(ratio),1.0,2.2])
    plt.show()

실행결과는 다음과 같습니다.

이런 창과 함께

 

이런 그래프가 뜰 겁니다. 값이 1.6에 수렴하는 게 눈에 보이죠?

 이번에도 모르는 코드가 많이 나왔을 겁니다. 첫 줄부터 봅시다. import matplotlib.pyplot as plt 는 파이썬에서 그래프를 사용할 수 있게 만들어주는 라이브러리인 matplotlib에서 pyplot을 파이썬으로 불러오라는 명령어입니다. 그런데 라이브러리를 사용할 땐 항상 그 이름을 불러줘야 하기 때문에, pyplotplt라는 별명으로 부르도록 하겠다는 명령어입니다. 파이썬은 기본 쉘에서 제공하지 않는 추가 기능이 있으면 import문을 통해 해당 라이브러리를 불러와 그에 속한 명령어를 실행시킬 수 있도록 만들어져 있습니다. 여러분이 필요로 하는 어지간한 라이브러리는 이미 다 개발되어 있으니, 관심 있으면 해당 라이브러리를 심도 있게 공부하면 됩니다.

    plt.plot(range(n),ratio)
    plt.xlabel('No.')
    plt.ylabel('Ratio')
    plt.title('Ratio between consecutive Fibonacci numbers')
    plt.axis([0,len(ratio),1.0,2.2])
    plt.show()

나머진 대체로 비슷비슷한데, 뒤에 추가된 이 부분이 궁금할겁니다. plot 명령어는 pyplot에 담겨진 명령어입니다. 그래서 이때는 pylot의 별명인 plt뒤에 사용해야 합니다. plt.plot(range(n),ratio)x, y값을 각각 range(n)ratio에서 가져와서 점을 찍고 선으로 이으라는 명령어입니다. x값을 담당하는 range(n)에는 0, 1, 2, 3, ..., n-1까지의 수가 들어있고, y값을 담당하는 ratio에는 두 항의 비율이 순서대로 들어있겠지요. 그걸 점으로 찍고 선으로 연결하는 명령어가 plot입니다.

xlabelylabel은 어떤 명령언지 감이 올겁니다. x, y축의 이름을 달아주는 명령어입니다. title은 제목을 달아주는 거구요. axis는 축을 담당하는 명령어입니다. 구체적인 내용은 스스로 이것저것 수를 바꿔보면서 알아보세요. plot을 통해 그래프를 그리더라도, show를 하지 않으면 화면에 나타나지 않습니다. 마지막 줄은 그래프를 화면에 띄우기 위한 명령어입니다.

plot에 대한 설명은 다른 강의를 통해 여러 번 접할 수 있을 겁니다. 일단 오늘은 피보나치 수열을 주로 다뤄 봅시다. 마지막 연습 문제는 명확한 답이 존재하는 문제입니다. 답은 4613732에요. 풀어봅시다!

 

연습문제: (Euler 프로젝트 2) 400만 이하의 피보나치수열 중 짝수인 것을 찾아 그 합을 구하시오.

피보나치. 

댓글0