1.파이썬 자료구조와 알고리즘

**미아 스타인 지음**


CHAPTER 01 숫자

목차

숫자

부동소수점

복소수

fraction 모듈

decimal 모듈

2진수 , 8진수, 16진수

연습문제

넘파이 패키지

1.1 정수


파이썬에서 정수는 int로 나타내며 불변(immutable)형이다. 불변형 객체는 변수와 객체 참조간에 차이가 없다. 파이썬 정수 크기는 컴퓨터 메모리에 의해 제한된다(C또는 자바 내장컴파일러에 따라 다르다.) 파이썬 정수크기는 적어도 32비트(4바이트)이다. 정수를 나타내는 데 필요한 바이트 수를 확인하려면 파이썬 3.1 이상에서 (정수).bit_length() 메서드를 사용할 수 있다.

(999).bit_length()

= 10

어떤 문자열을 정수로 변환(casting)하거나, 다른 진법의 문자열을 정수(10진법)로 변환하려면 int(문자열, 밑) 메서드를 사용한다.

>>> s = '11'
>>> d = int(s)
>>> print(d)
11

>>> b = int(s,2)
>>> print(b)
3

int 메서드의 밑은 2에서 36사이의 선택적 인수(optional argument)다. 문자열 s에서 밑범위의 숫자를 벗어나는 값을 입력한다면, int 메서드에서 ValueError 예외가 발생한다. 예를 들어 s='12'에 대해 실행하면 예외가 발생한다.

1.2 부동 소수점


IEEE 754는 전기 전자 기술자 협회(IEEE)에서 개발한, 컴퓨터에서 부동소수점을 표현하는 가장 널리 쓰이는 표준이다. 파이썬에서 부동소수점은 float로 나타내며 불변형이다. 단정도(single precision)방식에서 32비트 부동소수점을 나타낼 때 1비트는 부호(sign, 1:양수, 0:음수), 23비트는 유효숫자 자릿수(significant digits ) 혹은 가수(mantissa) , 8비트는 지수(exponent)다.

예를 들어 십진수 -118.625(10)을 32비트 단정도로 표현해보자. 먼저 숫자의 절댓값을 이진수로 변환한다. 부호는 음수이므로 1이다.

118 / 2 = 59 > 0
59  / 2 = 29 > 1
29  / 2 = 14 > 1
14  / 2 = 7  > 1
7   / 2 = 3  > 1
3   / 2 = 1  > 1
0.625 * 2 = 1.250
0.250 * 2 = 0.500
0.500 * 2 = 1.000

즉 1110110.101(2)이다.

그 다음 변환된 이진수를 다음과 같이 정규화한다.(소수점을 왼쪽으로 이동시켜 왼쪽 부분에 1만 남게 한다.)

1110110.101(2) = 1.110110101(2) * 2^6

위의 숫자를 가수부(23비트)에 넣는다. 부족한 자릿수는 0으로 채운다.

11011010100000000000000

지수는 6이므로 바이어스(bias)를 더한다. 즉, 지수6에 127(0111 1111(2))을 더한다. 6(10) + 127(10) = 133(10) = 10000101(2)

이상의 결과를 종합하여 -118.625(10)을 32비트 단정도로 표현한 결과는 다음과 같다.

부호| 지수 | 가수 |

1 | 10000101 | 11011010100000000000000|

배정도(double precision)방식에서는 64비트 부동소수점을 나타낼 때 1비트는 부호, 52비트는 가수, 11비트는 지수로 나타낸다.(단정도 방식일 때 127 (2^7 -1)을 더하고, 배정도 방식일 떄 1023(2^10 -1)을 더한다.)

1.2.1 부동소수점끼리 비교하기


부동소수점은 이진수 분수(binary fraction)로 표현되기 때문에 함부로 비교하거나 빼면 안된다. 2진수는 대개 10진법으로 정확하게 표현할 수 있지만, 2진법으로 표현하기 어려운 숫자도 있다.

(0.1(10) = 0.00110011001100---(2)). 다음과 같은 예를 보자.

Type "help", "copyright", "credits" or "license" for more information.
>>> 0.2 * 3 == 0.6
False
>>> 1.2 - 0.2 == 1.0
True
>>> 1.2 - 0.1 == 1.1
False
>>> 0.1 * 0.1 == 0.01
False

위의 방식을 해결하기 위해서는 그럼 어떤 방법이 있을까??

`decimal.Decimal`, `math.fsum()`, `round()`, `float.as_integer_ratio()`, `math.is_close()` 함수 혹은 다른 방법을 통해서 실수를 방지할 수 있다. 이 중 가장 추천하는 방법은 `decimal` 표준 라이브러리를 사용한 방법이고 그 외에도 존재하는 관련 함수들을 소개한다.

>>> import decimal

>>> decimal.Decimal('0.2') * 3 == decimal.Decimal('0.6')
True

>>> decimal.Decimal('1.2') - decimal.Decimal('0.1')  == decimal.Decimal('1.1')
True

>>> decimal.Decimal('0.1') * decimal.Decimal('0.1')  == decimal.Decimal('0.01')
True

위와같이 decimal을 활용해서 해결할 수 있다.

그 대신 동등성 테스트(equality test는 사전에 정의된 정밀도 범위 내에서 수행되어야 한다. 예를 들어 unittest 모듈의 assertAlmostEqual() 메서드 같은 접근법을 사용하는 방법이 있다.

>>> def(x,y,places=7):
    return round(abs(x-y), places) == 0
    

또한 부동소수점의 숫자는 메모리에서 비트 패턴으로 비교할 수 있다. 먼저 부호비교를 별도로 처리한다. 두 숫자가 음수이면, 부호를 뒤집고, 숫자를 반전하여 비교한다. 지수 패턴이 같으면 가수를 비교한다.

1.2.2 정수와 부동소수점 메서드


파이썬에서 나누기 연산자 / 는 항상 부동소수점을 반환한다. // 연산자(floor 또는 truncation)를 사용하면

정수를 반환할 수 있다. %연산자(module or remainder)는 나머지를 구한다. divmod(x,y) 메서드는 x를 y로 나눌 때, 몫과 나머지를 반환한다.

divmod(45,6)
45를 6으로 나누면?

>> (7,3)  [몫 : 7 | 나머지 : 3]

round(x,n) 메서드는 n이 음수인 경우, x를 n만큼 반올림한 값을 반환한다. n이 양수인 경우, x를 소수점 이하 n자리로 반올림한 값을 반환한다.

>>> round(100.96,-2)
100.0
>>> round(100.96, 2)
100.96

as_integer_ratio() 메서드는 부동소수점을 분수로 표현한다.

>>> 2.75.as_integer_ratio()
(11, 4)

1.4 fraction 모듈


파이썬에서 분수를 다루려면 fraction 모듈을 사용한다. 다음 코드 예제를 살펴보자.

from fractions import Fraction

def rounding_floats(number1, places):
    return round(number1, places)

def float_to_fractions(number):
    return Fraction(*number.as_integer_ratio())

def get_denominator(number1, number2):
    """ 분모를 반환한다."""
    a = Fraction(number1, number2)
    return a.denominator

def get_numerator(number1,number2):
    """ 분자를 반환한다."""
    a = Fraction(number1, number2)
    return a.numerator

def test_testing_floats():
    number1 = 1.25
    number2 = 1
    number3 = -1
    number4 = 5/4
    number6 = 6
    assert(rounding_floats(number1,number2) == 1.2)
    assert(rounding_floats(number1*10, number3) == 10)
    assert(float_to_fractions(number1) == number4)
    assert(get_denominator(number2, number6) == number6)
    assert(get_numerator(number2, number6) == number2)
    print("테스트 통과!")


if __name__ == "__main__":
    test_testing_floats()
테스트 통과 !

1.5 decimal 모듈


정확한 10진법의 부동소수점 숫자가 필요한 경우, 부동소수점 불변 타입인 decimal.Decimal을 사용할 수 있다. Decimal()메서드는 정수 또는 문자열을 인수로 취한다(파이썬3.1부터 사용할 수 있으며, decimal.Decimal.from_float()메서드로 부동소수점을 decimal.Decimal 타입으로 나타낼 수도 있다.) 이 모듈은 부동소수점의 반올림, 비교, 뺼셈등에서 나타나는 문제를 효율적으로 처리할 수 있다.

>>> sum(0.1 for i in range(10)) == 1.0
False
>>> from decimal import Decimal
>>> sum(Decimal("0.1") for i in range(10)) == Decimal("1.0")
True

decimal 모듈에는 Decimal.exp(x) 같은 내장 함수가 있어 대부분의 경우에 사용할 수 있다.

여기서 x는 decimal.Decimal 객체 타입이다. math와 cmath 모듈에도 exp() 함수가 있지만, 정확도가 필요하다면 decimal 모듈을 사용해야한다.

1.6 2진수, 8진수, 16진수


bin(i) 메서드는 정수i의 2진수 문자열을 반환한다.

>>> bin(999)
'0b1111100111'

oct(i) 메서드는 정수i의 8진수 문자열을 반환한다.

>>> oct(999)
'0o1747'

hex(i) 메서드는 정수i의 16진수 문자열을 반환한다.

>>> hex(999)
'0x3e7'

1.7 연습문제


이 책에서는 연습문제와 해답 코드를 바로 제시하지만, 실력 향상을 위해서는 해답 코드를 바로 읽기 전에 직접 작성해보는 것을 권장한다.

1.7.1 진법 변환

진법을 변환하는 함수를 직접 만들어보자. 다음 코드는 다른 진법의 숫자를 10진수로 변환한다.(2<= base <= 10)

1장 숫자/ 2_convert_to_decimal.py

def convert_to_decimal(number, base):
    multiplier, result = 1, 0
    #multiplier = 1 , result=0
    while number > 0:
        result += number % 10 * multiplier # % = 나머지 
        #result = 1 one
        #result = 1 two
        #result = 1 three
        #result = 9 four
        multiplier *= base
        #base = 2
        #multiplier = 2 one
        #multiplier = 4  two
        #multiplier = 8 three
        #multiplier = 16 four
        number = number // 10 #  // = 몫
        #number = 100
        #number = 10
        #number = 1
        #number = 0

        
    print('multiplier',multiplier)
    print("result",result)
    return result

def test_convert_to_decimal():
    number , base = 1001, 2
    assert(convert_to_decimal(number,base) == 9)
    print("테스트 통과!")

if __name__ == "__main__":
    test_convert_to_decimal()

위 코드의 핵심 부분은 % 연산자다. 반복문을 돌면서 number % 10(base)로 일의 자리 숫자를 하나씩 가져와서 계산한다. 그다음 반복문의 계산을 위해서 number = number // 10을 사용한다. 이와 같은 방법으로 10진수를 다른 진법의 숫자로 변환하는 함수도 만들어보자.

1장_숫자/ 3_convert_from_Decimal.py

def convert_to_decimal(number, base):
    multiplier , result = 1,0

    while number > 0:
        result += number % 2 * multiplier
        #result = result + namerge 
        #result = 10^number + namerge
        # result = 1 
        # result = 1 + 0
        # result = 1 + 0
        # result = 1 +  1 * multi = 1001
        multiplier *= 10
        #multiplier = 10
        #multiplier = 100
        #multiplier = 1000
        #multiplier = 10000
        number = number // 2
        #number = 4
        #number = 2
        #number = 1
        #number = 0

    return result



def test_convert_to_decimal():
    number , base = 9 ,2
    assert(convert_to_decimal(number,base) == 1001)
    print("test 통과!!")




if __name__ == "__main__":
   test_convert_to_decimal()
    

--참고--

산술 연산자 (Arithmetic Operators):

a = 10, b = 20, c = 3 이라 가정한다.

OperatorDescriptionExample

+ 더하기 a + b = 30
- 빼기 a - b = -10
* 곱하기 a * b = 200
/ 나누기 b / a = 2.0
% 나머지 b % a = 0
** 제곱 a ** c = 1000
// a // c = 3

1장_숫자/4_convert_from_Decimal_larger_bases.py


def convert_to_decimal_larger_bases(number,base):
    strings = "0123456789ABCDEFGHIJ"
    result = ""
    while number > 0:
        digit = number % base
        print("digit",digit)
        result = strings[digit] + result
        print("result",result)
        number = number // base
        print("number",number)
    return number

def test_convert_from_decimal_larger_bases():
    number, base = 31, 16
    assert(convert_to_decimal_larger_bases(number, base) == "1F")
    print("테스트 통과!")

if __name__ == "__main__":
        test_convert_from_decimal_larger_bases()
출력값digit 15result Fnumber 1...digit 1result 1Fnumber 0
테스트 통과!

마지막으로 다음 코드는 재귀 함수(recursive function를 사용한 진법 변환이다. 재귀 알고리즘에 대한 내용은 8.2 재귀 알고리즘을 참조한다.)

def convert_dec_to_any_base_rec(number, base):    convertString = "0123456789ABCDEF"    print("number",number)    print("base",base)       if number < base:        print("if")        return convertString[number]    else:        print("else")        return convert_dec_to_any_base_rec(number // base, base)\            + convertString[number % base]       def test_convert_dec_to_any_base_rec():    number = 9     base = 2    assert(convert_dec_to_any_base_rec(number,base) == "1001")    print("테스트 통과!")if __name__ == "__main__":    test_convert_dec_to_any_base_rec()
출력결과number 9base 2elsenumber 4base 2elsenumber 2base 2elsenumber 1base 2if테스트 통과!
풀이과정return convert_dec_to_any_base_rec(4,2) + '1'return convert_dec_to_any_base_rec(2,2) + '0' + '1'return convert_dec_to_any_base_rec(1,2) + '0' + '0' + '1'return constring[1] + '0' + '0' + '1'

1.7.2 최대공약수

다음 코드는 두 정수의 최대공약수 greatest common divisor(GCD)를 계산한다.

1장_숫자/6_finding_gcd.py

def finding_gcd(a, b):    while (b != 0):        result = b        a, b = b, a % b    return resultdef test_finding_gcd():    number1 = 21    number2 = 12    assert(finding_gcd(number1, number2) == 3)    print("테스트 통과")if __name__ == "__main__":    test_finding_gcd()
출력 결과a 12b 9result 12a 9b 3result 9a 3b 0result 3테스트 통과

1.7.3 random 모듈

난수를 생성하는 random모듈의 예제 코드를 살펴보자. 난수이므로 출력 결과는 실행 때마다 다르다.

1장_숫자/7_testing_random.py

import randomdef testing_random():    """ random 모듈 테스트"""    values = [1,2,3,4]    print(random.choice(values))    print(random.choice(values))    print(random.choice(values))    print(random.sample(values,2))    print(random.sample(values,3))    """ values 리스트를 섞는다."""    random.shuffle(values)    print(values)    """0~10의 임의의 정수를 생성한다. """    print(random.randint(0,10))    print(random.randint(0,10))if __name__ == "__main__":    testing_random()

출력결과

root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo# python3 7_testing_random.py434[4, 3][2, 4, 1][2, 4, 3, 1]04

1.7.4 피보나치 수열

피보나치 수열은 첫째 및 둘째 항이 1이며, 그 이후의 모든 항은 바로 앞 두 항의 합인 수열이다.

1 1 2 3 5 8 13 21

다음 코드는 피보나치 수열에서 세 가지 다른 방법으로 n번째 숫자를 찾는다. 재귀 호출을 사용하는 find_fibonacci_seq_rec()함수의 시간복잡도는 O(2n)이고, 반복문을 사용하는 find_fibonacci_seq_iter()함수의 시간복잡도는 O(n)이다. 수식을 사용하는 find_fibonacci_seq_from함수의 시간복잡도는 O(1)이다. (단 70번째 이상 결과에서 정확하지 않다.)

1장_숫자/8_find_fibonacci_seq.py

import mathdef find_fibonacci_seq_iter(n):    if n < 2:return n     a, b = 0, 1    for i in range(n):        a, b = b, a+b    return adef find_fibonacci_seq_rec(n):    if n < 2: return n    return find_fibonacci_seq_rec(n - 1) + find_fibonacci_seq_rec(n - 2)def find_fibonacci_seq_form(n):    sq5 = math.sqrt(5)    phi = ( 1 + sq5) / 2    return int(math.floor(phi ** n / sq5))    #sqrt(x) x의 제곱근을 반환합니다.    #floor 함수는 실수를 입력하면내림하여 정수를 반환하는 함수이다.     #floor은 바닥을 의미한다. 실수의 바닥의 수인 바로 아래 정수로 내림def test_find_fib():    n = 10    assert(find_fibonacci_seq_rec(n) == 55)    assert(find_fibonacci_seq_iter(n) == 55)    assert(find_fibonacci_seq_form(n) == 55)    print("테스트 통과!!")if __name__ == "__main__":    test_find_fib()
테스트 통과!

또한 다음과 같이 제너레이터(generator)를 사용하여 피보나치 수열을 구할 수도 있다. 제너레이터는 파이썬의 시퀸스를 생성하는 객체다. 제너레이터는 파이썬의 시퀸스를 생성하는 객체다. 제너레이터를 이용하며, 전체 시퀸스를 한 번에 메모리에 생성하고 정렬할 필요 없이, 잠재적으로 아주 큰 시퀸스를 순회할 수 있다. 제너레이터를 순회할 때마다 마지막으로 호출된 요소를 기억하고 다음 값을 반환한다. 제너레이터 함수는 yield문을 사용한다. yield문에 대한 내용은 4.2.4 return 대 yield를 참조한다.

1장_숫자/9_find_fibonacci_by_generator.py

def fib_generator():    a, b = 0, 1    while True:        yield b        a, b = b, a+bif __name__ == "__main__":    fg = fib_generator()    for _ in range(10):        print(next(fg), end=" ")
1 1 2 3 5 8 13 21 34 55
NOTE_ 시간 복잡도에 대한 내용은 8장에서 간단히 살펴본다. 여기서 간단히 위키백과 설명을 일부 옮기자면 다음과 같다.(http://ko.wikipedia.org/wiki/시간_복잡도). 이하 이 책의 모든 박스는 옮긴이가 추가한 것이다. 컴퓨터과학에서 알고리즘의 시간복잡도는  입력을 나타내는 문자열 길이의 함수로서 작동하는 알고리즘을 취해 시간을 정량화하는 것이다. 알고리즘의 시간복잡도는 주로 빅-오 표기법을 사용하여 나타내며, 이 빅-오 표기법은 개수와 낮은 차수의 항을 제외시키는 방법이다. 이런 방식으로 표현할 때, (예를 들어 입력크기를 무한대로 입력하여) 시간복잡도를 점근적으로 묘사한다고 말한다. 예시로서, 만약 크기 n의 모든 입력에 대한 알고리즘에 필요한 시간이 최대(어떤 n0보다 크지 않은 모든n에 대하여) 5n^3 + 3n의 식을 가진다면, 이 알고리즘의 점근적 시간복잡도는 O(n^3)이라고 할 수 있다.

1.7.5 소수

다음 예제에서는 세 가지 다른 방법으로 한 숫자가 소수(prime number)인지 판단한다. 소수란 자신보다 작은 두 개의 자연수를 곱하여 만들 수 없는 1보다 큰 자연수다. 즉, 약수로 1과 자기 자신만을 가지는 수다. 첫 번째 함수는 브루트 포스(brute force, 즉 무차별 대입 방법을 사용한다.)

두 번째 함수는 제곱근을 이용한다. m = 루트 n, m*n = n이라고 가정한다. n이 소수가 아니면, n = a * b이므로 m * m = n이라고 가정한다. n이 소수가 아니면, n = a* b이므로 m*m = a*b이다. m은 실수, n,a,b 는 자연수다. 그러면 다음과 같은 세 가지 경우가 있을 수 있따.

1) a > m 이면, b < m2) a = m 이면 b=m3) a<m 이면, b>m

세 가지 경우 모두 min(a,b) <= m이다. 따라서 m까지의 수를 검색한다면 적어도 하나의 n과 나누어 떨어지는 수를 발견할 것이고, 이것은 n이 소수가 아님을 보여주기에 충분하다.


1장_숫자/10_finding_prime.py -이해필요

import mathimport randomdef finding_prime(number):    num = abs(number)    if num < 4 : return True    for x in range(2,num):        if num % x == 0:            return False    return Truedef finding_prime_sqrt(number):    num = abs(number)    if num < 4 : return True     for x in range(2, int(math.sqrt(num)) + 1):        if number % x == 0:            return False    return Truedef finding_prime_fermat(number):    if number <= 102:        for a in range(2, number):            if pow(a, number-1, number) != 1:                return False            return True     else:        for i in range(100):            a = random.randint(2,number - 1)            if pow(a, number -1, number) != 1:                return False        return Truedef test_finding_prime():    number1 = 17    number2 = 20    assert(finding_prime(number1) is True)    assert(finding_prime(number2) is False)    assert(finding_prime_sqrt(number1) is True)    assert(finding_prime_sqrt(number2) is False)    assert(finding_prime_fermat(number1) is True)    assert(finding_prime_fermat(number2) is False)    print("테스트 통과!")if __name__ == "__main__":    test_finding_prime()    

페르마의 소정리

위키백과, 우리 모두의 백과사전.

[수론](https://ko.wikipedia.org/wiki/수론)에서, **페르마의 소정리**(Fermat小定理, [영어](https://ko.wikipedia.org/wiki/영어): Fermat’s little theorem)는 어떤 수가 [소수](https://ko.wikipedia.org/wiki/소수_(수론))일 간단한 [필요 조건](https://ko.wikipedia.org/wiki/필요_조건)에 대한 정리이다. 추상적으로, [소수](https://ko.wikipedia.org/wiki/소수_(수론)) 크기의 [유한체](https://ko.wikipedia.org/wiki/유한체) 위의 [프로베니우스 사상](https://ko.wikipedia.org/wiki/프로베니우스_사상)[항등 함수](https://ko.wikipedia.org/wiki/항등_함수)임을 의미한다.

p가 소수이고 a가 정수라고 하자. 페르마의 소정리에 따르면 , 법p에서 a^p와  a는 서로 합동이다.a^p = a (mod p)위 식은 p | a일 때 자명하게 성립한다. 만약 p !| a일 경우 양변을 약분하여 다음과 같이쓸 수 있다.a^(p-1) = 1 (mod b)를 만족하면서 소수가 아닌 b를, a를 밑수로 하는 카마이클 수라고 부른다.

다음 코드는 random 모듈을 사용하여 n비트 소수를 생성한다. 3을 입력하면, 5(101(2)) 또는 7(111(2))의 결과가 나온다.

1장_숫자/11_generate_prime.py


import mathimport randomimport sysdef finding_prime_sqrt(number):    num = abs(number)    if num < 4:        return True    for x in range(2, int(math.sqrt(num) + 1)):        if number % x == 0:            return False    return True def generate_prime(number=3):    while 1:        p = random.randint(pow(2, number -2), pow(2,number-1)-1)        p = 2 * p + 1        if finding_prime_sqrt(p):            return pif __name__ == "__main__":    if len(sys.argv) < 2:        print("usage: generate_prime.py number")        sys.exit()    else:        number = int(sys.argv[1])        print(generate_prime(number))
root@DESKTOP-JPGB0S5:/mnt/d/Mastering-Python-Design-Patterns-Second-Edition/algo# python3.6 11_generate_prime.py  35 or 7

1.8 넘파이 패키지

넘파이는 파이썬 프로그래밍 언어의 확장 패키지이며, 대규모의 다차원 배열 및 행렬을 지원한다.

또한 배열 연산에 쓰이는 수학 함수 라이브러리를 제공한다.

넘파이 배열은 임의의 차원(dimension)을 가진다. 넘파이 모듈의 array 메서드를 사용하여

'시퀸스의 시퀸스(리스트 또는 튜플)'를 2차원 넘파이 배열로 생성할 수 있다.

np.array( ((11,12,13), (21,22,23), (31,32,33)) )
import numpy as np


def testing_numpy():
    """ test many features of numpy"""

ax = np.numpy([1,2,3])
ay = np.array([3,4,5])
print(ax)
print(ax * 2)
print(ax + 10)
print(np.sqrt(ax))
print(np.cos(ax))
print(ax-ay)
print(np.where(ax<2, ax, 10))


m = np.matrix([ax,ay,ax])
print(m)
print(m.T)

grid1 = np.zeros(shape=(10,10), dtype=float)
grid2 = np.ones(shape=(10,10), dtype=float)
print(grid1)
print(grid2)
print(grid1[1]+10)
print(grid2[:,2]*2)

if __name__ == "__main__":
    testing_numpy()

넘파이 배열은 파이썬 리스트보다 훨씬 더 효율적이다. 다음 테스트 결과를 살펴보자(ㄲ)

import numpy
import time

def trad_version():
    t1 = time.time()
    X = range(10000000)
    Y = range(10000000)
    Z = []
    for i in range(len(X)):
        Z.append(X[i] + Y[i])
    return time.time() - t1

def numpy_version():
    t1 = time.time()
    X = numpy.arange(10000000)
    Y = numpy.arange(10000000)
    Z = X + Y
    return time.time() - t1

if __name__ == "__main__":
    print(trad_version())
    print(numpy_version())
    
21.062912225723267 <리스트>
0.11400818824768066 <넘파이>

+ Recent posts