━━━━ ◇ ━━━━
따라하며 배우는 파이썬과 데이터 과학/PART 1. 파이썬 기초체력 다지기

Chapter 03. 연산자로 계산을 해 보자

이번 시간의 목차

1. 파이썬에서의 수식이란

2. 연산자 그 첫 번째, 산술 연산자

3. 연산자 그 두 번째, 할당 연산자

4. 연산자 그 세 번째, 비교 연산자

5. 연산자 그 네 번째, 논리 연산자

6. 연산자 그 다섯 번째, 비트 연산자

7. 연산자에도 우선순위가 있다!

8. random 모듈과 math 모듈

9. 마무리

 

 

 

자, 가자! 파이썬의 세계로!


 

파이썬에서의 수식이란

 

  우리는 그동안 살면서 수많은 수식을 접했을 것이다. 당장 수학책을 펼치기만 해도 수식이 없는 페이지가 없고, 더 나아가 물리학에서 어떤 운동이나 일에 대한 방정식, 경제학에서 수요 함수 등… 없는 곳이 없다고 할 정도이다. 

 

 물론 파이썬에도 수식은 존재한다. 하지만 수학에서의 수식과는 조금 다른 개념이다. 컴퓨터 과학 분야에서의 수식(Expression)하나의 값으로 평가될 수 있는 표현을 의미한다. 좀 더 정확하게 말하자면 피연산자들과 연산자의 조합이다. 이때 연산자(Operator)는 어떤 연산을 나타내는 기호를 의미하고, 피연산자(Operand) 연산의 대상이 되는 숫자나 변수를 의미한다. 

 

 

 연산자는 이전 시간에서도 보았듯 계산, 즉 산술을 위한 것만 있는 것은 아니다. 이번 시간에는 다양한 연산자에 대해서 알아보도록 하자. 

 


 

연산자 그 첫 번째, 산술 연산자

 

 우선 가장 익숙할 산술 연산자에 대해 알아보자. 

크게 어려운 건 없다. 덧셈, 뺄셈, 곱셈, 나눗셈과 나머지 및 지수 연산을 실행하는 연산자가 있다. 

 

연산자 기호 사용 예시 결과값 
덧셈 + 11 + 2 13
뺄셈 - 11 - 2 9
곱셈 * 11 * 2 22
나눗셈(실수) / 11 / 2 5.5
나눗셈(정수 나눗셈의 몫) // 11 // 2 5
나머지 % 11 % 2 1
지수(거듭제곱) ** 11 ** 2 121

 

 이때 나눗셈 연산자 / 와  // 를 잘 구분해서 써야 한다. / 는 소수점 아래, 즉 실수 범위까지 나눗셈을 하지만 // 는 나머지를 버리고 정수 몫만을 반환해준다. 

 

 사칙연산은 그렇다 쳐도, 나머지 연산자(%)와 지수 연산자(**)는 생소할지도 모른다. 

나머지 연산자는 생각보다 컴퓨터 과학에서 중요하게 쓰이는 연산자이다. 잘만 이용하면 짝수나 홀수도 쉽게 구분할 뿐만 아니라 소수(약수가 1과 자신 뿐인 수)도 구분할 수 있고, 단위 변환도 쉽게 이뤄낼 수 있다. 짧은 예시로 정수의 홀짝을 구분해보자. 어떤 수를 2로 나누어서 나머지가 0이라면 짝수일 것이고, 나머지가 1이라면 홀수가 될 것이다. 따라서 아래처럼 코드를 작성하면 홀수인지 짝수인지 쉽게 알 수 있을 것이다. 

 

number = int(input('정수를 입력하시오: '))
print(number % 2)       #0을 출력하면 짝수, 1을 출력하면 홀수가 된다.
 
정수를 입력하시오 : 28
0
cs

 

 지수 연산자는 앞의 수를 밑으로, 뒤의 숫자를 지수로 올려 계산해준다. 지수 연산자는 곱셈이나 나눗셈 연산자보다 우선순위가 높다. 또, 다른 연산자들과 달리 오른쪽에서 왼쪽으로 계산되기 때문에 지수 연산자를 쓸 때는 이 두 점을 주의해야 한다. 

 

>>> 2 ** 5       #2의 5
32 
>>> 10 * 2 ** 3  #10 * 2 * 2 * 2
80
>>> 2 ** 2 ** 4  #2의 16제곱 
65536
cs

 

 또 지수로는 실수도 올릴 수 있기 때문에 제곱근도 쉽계 계산할 수 있다. 

피타고라스 정리(c² = a² + b²)를 조금 손봐주면 c = (a² + b²) ^ ½ 를 얻을 수 있다. 간단한 예시로 사용자로부터 밑변과 높이 값을 받아서 그 삼각형의 빗변을 구하는 프로그램을 써 보자. 

 

= float(input('밑변의 길이는: '))
= float(input('높이의 길이는: '))
= (a * b) ** (1/2)
print('빗변의 길이는', c, '입니다.')
cs

 

 이때 지수로 2분의 1을 주고 싶다면 꼭 괄호 속에 넣어서 입력하도록 하자. / 는 나눗셈 연산자이므로 ** 보다 우선순위가 낮아 괄호를 써 주지 않으면 지수로 1이 올라가 버린다. 2분의 1 대신 0.5를 넣으면 괄호를 쓸 필요는 없다. 어쨌든, 위의 코드를 실행시키면 아래와 같은 결과가 나온다. 

 

밑변의 길이는: 3
높이의 길이는: 4
빗변의 길이는 5.0 입니다.
cs

 


 

연산자 그 두 번째, 할당 연산자

 

 할당 연산자? 어디서 많이 들어본 이름이 아닌가? 

그렇다. 우리는 이미 할당 연산자를 하나 알고 있다. 변수를 선언할 때 쓰는 = 가 바로 그 할당 연산자(Assignment Operator)이다. 명심하자. 프로그래밍의 세계에서 = 는 '같다' 라는 뜻이 아니라 왼쪽에 오른쪽 데이터를 저장한다는 뜻이다. 왼쪽은 항상 값을 저장할 수 있는 변수여야 하고, 오른쪽은 값을 표현하는 숫자나 문자, 변수, 혹은 수식이 와야 한다. 만약 이게 거꾸로 오게 된다면…

 

>>> 10 = x + y
SyntaxError: cannot assign to literal
cs

 

이렇게 오류를 일으킨다. 

 

 이미 2장에서 설명했듯, 한 번에 여러 변수를 선언해서 동시에 여러 값을 줄 수도 있다. 이때 쓰이는 할당문을 동시 할당문(Simultaneous Assignment)이라 하고, 한 번에 여러 변수를 선언해서 동일한 값을 주는 건 다중 할당문(Multiple Assignment)이라 한다. 

 

>>> x = y = 10      #같은 값을 주면 다중 할당문
>>> x, y
(1010)
>>> x, y = 2030   #동시에 다른 값을 주면 동시 할당문
>>> x, y
(2030)
cs

 

 그렇다면 할당 연산자는 이것 뿐인가? 

아니! 앞에서 설명한 산술 연산자와 결합해서 쓰이는 복합 할당 연산자라는 할당 연산자가 또 존재한다. 

 

연산자 사용 방법 의미
+= a += 10 a = a + 10
-= a -= 10 a = a - 10
*= a *= 10 a = a * 10
/=  a /= 10 a = a / 10
//= a //= 10 a = a // 10
%=  a %= 10 a = a % 10
**=  a **= 10 a = a ** 10

 

 당연하겠지만 복합 할당 연산자를 쓰기 전에는 a 자리에 들어갈 변수를 선언해 두어야 한다. 

꼭 이런 복합 할당 연산자를 쓰지 않아도 산술 연산자와 할당 연산자를 써서 코딩할 수 있지만, 의미 정도는 알아 두어야 다른 사람의 코드를 문제 없이 읽을 수 있으니 알아두도록 하자. 

 


 

연산자 그 세 번째, 비교 연산자

 

 비교 연산자(Comparison Operator)는 수치 데이터를 담고 있는 두 개의 피연산자를 대상으로 '크다'와 '작다' 같은 크기 관계를 살피고 그 결과로 True 또는 False를 반환한다. True와 False는 2장에서 이미 한 번 언급했는데, 부울형(Bool)이라는 자료형이다. 

 

연산자 설명 a = 100 이고 b = 200일 때
== 두 피연산자의 값이 같으면 True를 반환 a == b는 False
!= 두 피연산자의 값이 다르면 True를 반환 a != b는 True
> 왼쪽 피연산자가 오른쪽 피연산자보다 클 때 True를 반환 a > b는 False
< 왼쪽 피연산자가 오른쪽 피연산자보다 작을 때 True를 반환 a < b는 True
>= 왼쪽 피연산자가 오른쪽 피연산자보다 크거나 같을 때 True를 반환 a >= b는 False
<= 왼쪽 피연산자가 오른쪽 피연산자보다 작거나 같을 때 True를 반환 a <= b는 True

 

p>>> a, b = 100200
>>> a >= b
False
>>> a => b
SyntaxError: invalid syntax
>>> a > = b
SyntaxError: invalid syntax
cs

 

 앞에서 = 는 '같다' 라는 뜻이 아니라는 것은 이미 설명했다. 이제 진짜 '같다' 라는 의미를 가진 연산자가 나왔다. 간단하게 =를 연속해서 두 번, ==로 써 주면 된다. 이때 이 연산자 사이에 공백을 넣어서는 안 된다. 이는 != 나 >=, <= 도 마찬가지이다. 이 묶음 자체가 하나의 연산자이기 때문에 공백이 포함되어선 안 되고, 두 문자의 순서가 바뀌어도 안 된다

 


 

연산자 그 네 번째, 논리 연산자

 

 논리 연산자(Logical Operator)는 and, or, not 연산을 통해 True 또는 False 중 하나의 값을 갖는 부울 값을 반환한다. 부울 자료형 자체는 True나 False가 끝이라 단순하지만, 다른 자료형도 부울 자료형이 될 수 있음을 알아 두어야 한다. 숫자 자료형의 경우 0은 False, 0을 제외한 다른 모든 수는 True로 바꿀 수 있다. 문자열의 경우에는 빈 문자열은 False, 빈 문자열을 제외한 모든 문자열은 True로 간주된다.

 

>>> 10 > 20       #10은 20보다 작으므로 거짓임.
False
>>> 100 < 200     #100은 200보다 작으므로 참임.
True
>>> bool(10)      #0이 아닌 값이므로 True
True
>>> bool(-1)
True
>>> bool(0)       #0은 False
False
>>> bool(None)    #값이 없어도 False
False
>>> bool('')      #빈 문자열도 False
False
>>> bool('bool')
True
cs

 

 중간에 있는 'None' 은 값이 없다는 뜻을 지닌 키워드이다. 이처럼 0과 None, 그리고 빈 문자열에 대해서 False를 반환하는 것을 보니 0이나 비어 있는 것은 False, 0이 아닌 값이나 무언가가 들어있는 것은 True로 간주된다는 것을 알 수 있다. 

 

 이런 부울 자료형에 대해 적용할 수 있는 것이 논리 연산이다. 

 

연산자 의미
and y x와 y중 거짓(False)이 하나라도 있으면 거짓이 되며 모두 참(True)인 경우에만 참이다.
or y x나 y중에서 하나라도 참이면 참이 되며, 모두 거짓일 때만 거짓이 된다. 
not x x가 참이면 거짓, x가 거짓이면 참이 된다.

 

 x와 y에 대한 논리 연산 결과를 간략하게 정리해보면 아래와 같다. 

 

 


 

연산자 그 다섯 번째, 비트 연산자

 

  연산자에는 산술 연산자와 논리 연산자처럼 연산의 대상이 되는 데이터 값을 가지고 처리하는 연산자 뿐만 아니라 정보의 비트(Bit) 단위로 처리가 이루어지는 연산도 있다. 

 

 비트는 0과 1로 구성된 2진수의 한자리를 말하는데, 파이썬에서 정수 데이터형에 대해서 비트 단위로 조작이 가능하다. 이때 쓰는 연산자를 비트 연산자(Bit Operator) 또는 비트 단위 연산자(Bitwise Operator)라고 한다. 

 

연산자 의미 설명
& 비트 단위 AND 두 개의 피연산자의 해당 비트가 모두 1이면 1, 아니면 0
| 비트 단위 OR 두 피연산자의 해당 비트 중 하나라도 1이면 1, 아니면 0
^ 비트 단위 XOR 두 개의 피연산자의 해당 비트 값이 같으면 0, 아니면 1
~ 비트 단위 NOT 0은 1로 만들고, 1은 0으로 만든다.
<< 비트 단위 왼쪽으로 이동 지정된 개수만큼 모든 비트를 왼쪽으로 이동시킨다.
>> 비트 단위 오른쪽으로 이동 지정된 개수만큼 모든 비트를 오른쪽으로 이동시킨다.

 

 비트 연산자는 위와 같은 것들이 있다. 

어떤 정수의 이진수 값을 확인하고 싶으면 bin() 함수를 사용하면 된다. 한 번 연습해보자. 

 

>>> bin(9)      #9(10)의 2진수 형식(00001001)
'0b1001'
>>> bin(10)     #10(10)의 2진수 형식(00001010)
'0b1010'
>>> bin(9 & 10#두 2진수를 비교해서 모두 1이면 1, 아니면 0
'0b1000'
>>> bin(9 | 10#두 2진수를 비교해서 하나라도 1이면 1, 아니면 0
'0b1011'
>>> bin(~9)     #모든 비트를 바꾸면 2의 보수에 의해 -10(10)이다.
'-0b1010'
 
>>> 9 ^ 10      #비트를 비교해서 같으면 0, 아니면 1. 결과는 3
3
>>> bin (9 ^ 10#3의 2진수값은 (00000011)
'0b11'
>>> 9 << 1      #9(10)의 2진수 형식을 왼쪽으로 한 비트 이동
18
>>> bin(9 << 1#00001001을 왼쪽으로 한 비트 밀었으므로 
'0b10010'
>>> 9 >> 2      #오른쪽으로 두 비트 
2
>>> bin(9 >> 2)
'0b10'
cs

 

 ^ 연산자는 해당 비트의 값이 같으면 0, 아니면 1을 반환하는 XOR 연산을 비트 단위로 수행한다. 지금은 이를 활용하는 방법에 익숙하지 않겠지만, 이 연산은 데이터 교환이나 특정 부분을 제거할 때 유용하게 사용된다. 

 

 또, << 연산자와 >> 연산자는 지정된 수만큼 모든 비트를 왼쪽 또는 오른쪽으로 이동시킨다. 이때 이동시키고 남은 자리에는 0을 넣게 된다. 비트가 한 칸 왼쪽으로 이동하면 정수는 2배의 값을 가지게 되고, 한 칸 오른쪽으로 이동하면 // 2 연산을 한 결과가 될 것이다. 이런 연산을 쉬프트(Shift) 연산이라 한다.

 

 이 연산자는 복합 할당 연산자로서 사용할 수도 있다. 

 

연산자 사용 예시 의미
&= a &= 10 a = a & 10
|=  a |= 10 a = a | 10
^= a ^= 10 a = a ^ 10
<<= a <<= 10 a = a << 10
>>= a >>= 10 a = a >> 10

 

연산자에도 우선순위가 있다!

 

 좀 뜬금없지만 2 + 2 * 2 를 계산하면 몇이 나오는가? 무심코 8이라고 대답하기 쉽지만, 사칙연산에서는 곱하기와 나누기를 먼저 해야 하기 때문에 답은 6이 된다. 이렇게 우선순위(Precedence)가 있기 때문에 연산할 때에는 순서를 조심해야 한다. 

 

 이때까지 살펴본 연산자에도 우선순위가 존재한다. 산술 연산자의 우선순위로만 따지면 아래와 같다. 간단하게 사칙연산의 우선순위에 지수가 추가되었다고 생각하면 된다.

 

 

우선순위대로 연산하지 않고 다른 순서로 하고 싶은 경우에는 수학처럼 먼저 하고 싶은 연산에 괄호를 써 주면 된다. 

 

 아래는 파이썬에서 사용되는 중요한 연산자에 대한 우선순위를 정리한 표이다. 이 모든 걸 일일이 기억하기는 힘드니, 우선순위가 헷갈릴 때에는 먼저 하고 싶은 연산에 괄호를 씌워주는 것도 좋다. 

연산자 설명
** 지수 연산자
~, +(단항), -(단항) 단항 연산자
*, /, //, % 곱셈, 나눗셈, 나머지 연산자
+, - 덧셈, 뺄셈
>>, << 비트 이동 연산자
& 비트 AND 연산자
^, | 비트 XOR 연산자, 비트 OR 연산자
<=, <, >, >= 비교 연산자
==, != 동등 연산자
=, %=, /=, //=, -=, +=, *=, **= 할당 연산자, 복합 할당 연산자
is, is not 아이덴티티 연산자
in, not in 소속 연산자
not, or, and 논리 연산자 

 

random 모듈과 math 모듈

 

 파이썬에는 개발자들이 프로그램을 쉽게 작성할 수 있도록 다양한 내장함수가 제공된다. 앞서 살펴봤던 print(), imput(), int(), str() 등을 포함해서 70여 가지 이상이 있다. 이 뿐만 아니라 표준 라이브러리에서 터틀 그래픽, 난수 생성기와 다양한 수학 함수 등의 기능을 제공한다. 이번에는 그 난수 생성기인 random 모듈과 수학 함수를 제공하는 math 모듈에 대해 간단하게 알아보자. 

 

 random 모듈은 임의의 수를 생성하거나, 어떤 리스트나 튜플 내의 요소를 무작위로 섞거나 선택하는 함수를 포함한다. 이 중 대표적인 함수 몇 가지를 써 보자. 

 

>>> import random                    #random 모듈을 불러온다.
>>> random.random()                  #0 이상 1 미만의 임의의 실수 생성
0.5636551720885258
>>> random.random()                  #매번 다른 실수를 생성해준다.
0.14049721316673058
>>> random.randint(17)             #1 이상 7 이하의 임의의 정수 생성
2
>>> random.randrange(7)              #0 이상 7 미만의 임의의 정수 생성
4
>>> random.randrange(0102)       #0 이상 10 미만의 수에서 
2                                    #2씩 건너뛴 수 중 임의의 정수 생성
>>> Alist = [1020304050]     #여러 값을 가지는 리스트
>>> random.shuffle(Alist)            #Alist의 순서를 섞는다.
>>> Alist
[2040305010]                 #섞였다! 
>>> random.choice(Alist)             #Alist의 원소 중 무작위로 하나를 고른다.
40
cs

 

math 모듈은 원주율 π, 자연상수 e 등 상수 값과 실수의 절대값, sin(), cos() 등의 다양한 수학 함수를 포함하고 있다. 역시 대표적인 예시 몇 가지를 살펴보도록 하자.

 

>>> import math                 #math 모듈을 불러온다.
>>> math.pow(23)              #2의 3제곱
8.0
>>> math.fabs(-99)              #-99의 실수 절대값
99.0
>>> math.log(e)                 #자연 상수 e를 부를 때는 
Traceback (most recent call last):
  File "<pyshell#23>", line 1in <module>
    math.log(e)
NameError: name 'e' is not defined
>>> math.log(math.e)            #math.e 로 불러오자.
1.0                             #log(x)는 밑이 e, 진수가 x다.
>>> math.log(10010)           #log(x, y)는 밑이 y, 진수가 x다.
2.0
>>> math.pi                     #마찬가지로 원주율 파이는
3.141592653589793               #math.pi 로 불러오자.
>>> math.sin(math.pi / 2.0)
cs

 

 이보다 더 많은 함수가 있으니, 잘 쓰면 다양한 문제 풀이의 열쇠로 작용할 것이다. 


 

마무리

 

 이번 시간에는 수식과 다양한 연산자, 우선순위, 그리고 random 모듈과 math 모듈에 대해 알아보았다. 

마지막으로 3장의 심화 문제 3.4, 3.6, 3.7, 3.9, 3.10을 풀어보고 마치도록 하자. 해답 코드는 접은글에 적어두었다. 늘 그렇지만 코딩에는 정답이 없기 때문에 접은글 속의 해답은 참고만 하도록 하자. 

 

3.4: 사용자로부터 입력받은 정수 값 n이 0에서 100의 범위 안에 있는 짝수인지 그렇지 않으지를 판단하는 코드를 작성하여 다음과 같은 결과가 나타나도록 하시오.

정수를 입력하세요 : 120
입력된 정수는 0에서 100의 범위 안에 있는 짝수인가요? False
정수를 입력하세요 : 88
입력된 정수는 0에서 100의 범위 안에 있는 짝수인가요? True
cs
더보기
number = int(input('정수를 입력하세요 : '))
print('입력된 정수는 0에서 100의 범위 안에 있는 짝수인가요?'
      number % 2 == 0 and 0 <= number <= 100)
cs

 

 

3.6: 사용자로부터 2개의 정수 a와 b를 입력으로 받은 다음 a를 b로 나눈 몫과 나머지를 다음과 같이 출력하시오.

정수 a를 입력하시오 : 202
정수 b를 입력하시오 : 50
/ b 의 몫 : 4
/ b 의 나머지 : 2
cs
더보기
= int(input('정수 a를 입력하시오 : '))
= int(input('정수 b를 입력하시오 : '))
print('a / b 의 몫 : ', a // b)
print('a / b 의 나머지 : ', a % b)
cs

 

 

3.7: 사용자로부터 세 자리 정수를 입력으로 받으시오. 이때 입력받은 정수 n에 대한 백의 자리, 십의 자리, 일의 자리 십진수 값을 다음과 같이 출력하시오. (힌트: // 연산자와 % 연산자를 사용하시오. 예를 들어 백의 자리는 n // 100을 통해서 구할 수 있다.)

세 자리 정수를 입력하시오 : 349
백의 자리 : 3
십의 자리 : 4
일의 자리 : 9
cs
더보기
number = int(input('세 자리 정수를 입력하시오 : '))
first = number // 100
second = number % 100 // 10
third = number % 10
print('백의 자리 : ', first)
print('십의 자리 : ', second)
print('일의 자리 : ', third)
cs

 

 

3.9: 이동 거리 구하기; 평균 시속과 이동 시간을 입력으로 받아 다음과 같이 이동 시간은 시간, 분, 초 단위로 출력하고, 이동한 거리를 계산하여 출력하시오.

평균 시속(km/h)을 입력하세요 : 46.5
이동 시간(h)을 입력하세요 : 12.342
평균 시속 : 46.5 km/h
이동 시간 : 12 시간 20 분 31 초
이동 거리 : 573.903 km
cs
더보기
= float(input('평균 시속(km/h)을 입력하세요 : '))
hour = float(input('이동 시간(h)을 입력하세요 : '))
minute = (hour - int(hour)) * 60     #float형에 int()를 쓰면 정수값만 남는다.
second = (minute - int(minute)) * 60
 
print('평균 시속 : ', v, 'km/h')
print('이동 시간 : ', hour, '시간', minute, '분', second, '초')
print('이동 거리 : ', v * hour, 'km')
cs

 

 

3.10: 다음과 같이 사용자로부터 두 점의 좌표 (x1, y1), (x2, y2)를 입력받아 두 점 사이의 거리를 출력하시오.

x1 좌표를 입력하시오 : 0
y1 좌표를 입력하시오 : 0
x2 좌표를 입력하시오 : 3
y2 좌표를 입력하시오 : 4
두 점의 거리 : 5.0
cs
더보기
x1 = int(input('x1 좌표를 입력하시오 : '))
y1 = int(input('y1 좌표를 입력하시오 : '))
x2 = int(input('x2 좌표를 입력하시오 : '))
y2 = int(input('y2 좌표를 입력하시오 : '))
distance = ((x2 - x1) ** 2 + (y2 - y1) ** 2** (1/2)
print('두 점의 거리 : ', distance)
cs
COMMENT