본문 바로가기
Python/Basic

[파이썬, Python] 부동 소수점(floating point number) - 실수의 연산, 부동 소수점 오차, 실수의 비교

by coding-choonsik 2023. 3. 7.
728x90
반응형
SMALL

✔ 실수의 연산

파이썬에서 실수를 연산할 때 가끔 사람의 직관에 반대되는 결과가 도출될 때가 있다. 

예를들어 정수 10과 3을 나누는 연산을 해보자.

 

일반적으로 사람은 연산의 결과가  3.333(반올림/내림 법칙에 따른 소수점 버림)정도  혹은 3.33333333.....으로 생각할 것이다.

print(10 / 3)
>>>3.3333333333333335

하지만 파이썬에서 결과는 3.3333333333333335이다. 이는 계산의 오류일까?

 

또, 0.1과 0.2 두 실수의 덧셈 연산을 해보자.

사람은 0.3이라고 도출된 결과에 참이라고 대답할 것이다. 

0.1 + 1.1 == 1.2
>>> False

하지만 컴퓨터는 False 결과를 도출한다. 이는 컴퓨터의 오류일까?

 

✔ 정수와 실수 자료형

  • 파이썬에서는 정수뿐 아니라 소숫점을 포함하는 실수도 다룰 수 있다.
  • 정수 데이터에는 소숫점이 없고 실수 데이터에는 소수점이 붙어 있다.
print(10)    # 정수
>>> 10

print(10.0)  # 실수
>>> 10.0

print(.1)    # 정수부가 0인 실수는 0을 생략 가능
>>> 0.1
  • 숫자 계산을 하는 경우 계산에 쓰인 숫자 중 하나라도 실수라면 계산결과는 실수가 된다.
  • 나눗셈 연산의 결과는 입력에 상관없이 항상 실수로 처리
print(10 * 5)    # 정수
>>> 50

print(10.0 * 5)  # 실수
>>> 50.0

print(10 / 5)    # 결과는 항상 실수
>>> 2.0

✔ 부동소수점 실수

  • 로그래밍 언어는 IEEE 754라는 국제표준에 따라 실수를 부동소수점 방식으로 표현
  • 부동소수점 방식에서는 숫자를 정수로 된 유효숫자와 정수로 된 지수의 곱으로 표현
  • 예) 십진수 부동소수점 방식에서 123.456이란 숫자는 123456 * 10^−3 이므로 123456이라는 정수 유효숫자와 −3이라는 정수 지수로 나타낼 수 있다. (정수 유효숫자: 123456, 정수 지수: -3)
파이썬에서는 유효숫자e지수 라는 방법으로 부동소수점 형태를 직접 표현한다.

123e2      # 123e2 = 123.0 x 10**2 = 12300.0
>>> 12300.0

123e-2     # 123e-2 = 123.0 x 0.01 = 1.23
>>> 1.23

123.456e-3  # # 123.456e-3 = 123.456 x 0.001 = 0.123456
>>> 0.123456

 

✔ 십진법과 이진법

  • 컴퓨터는 십진법이 아닌 이진법을 사용
  • 십진법에서는 0, 1, 2, 3, 4, 5, 6, 7, 8, 9의 10개 숫자만 사용하고 10 이상의 수는 자리를 나타내는 숫자를 나열하여 표현
  • 모든 십진법 숫자는 10의 제곱의 합으로 풀어서 나타낼 수 있다.
  • 소수점이 있는 경우에는 10의 제곱승을 음수로 표현

  • 이진법에서는 0, 1의 2개 숫자만 사용하고 2 이상의 수는 자리를 나타내는 숫자를 나열하여 표현
  • 소수점이 있는 경우에는 2의 제곱승을 음수로 표현

파이썬에서 십진수로 이진수로 표현해보자.

  • 파이썬의 bin 명령어를 사용.
  • 0b는 접두사
bin(15)
>>>'0b1111'   # str로 출력됨

bin(567)
>>> '0b1000110111'

✔ 부동소수점 오차

  • 1보다 작은 수의 경우에 십진법으로 간단히 표현되는 수도 이진법에서는 무한개의 유효숫자를 가질 수 있음
  • 예를 들어 0.1이라는 숫자는 십진수로는 간단히 표현되지만 이진수로 나타내면 다음과 같이 0011(₂)이 무한히 반복되는 실수가 됨.

  • 컴퓨터에서는 하나의 숫자를 나타내기 위한 메모리 크기가 제한되어 있기 때문에 특정 소수점 이하는 생략하고 가장 비슷한 숫자로 표현함.
  • 0.1은 실제로는 가장 비슷한 다음과 같은 숫자로 저장됨.

  • 파이썬 콘솔이나 주피터 노트북은 REPL 인터페이스에서 값이 출력될 때 편의상 일정 소수점 이하를 생략하고 출력되기 때문에  0.1을 입력하면 0.1로 출력된다.

 

REPL이란?
  • REPL은 Read-Eval-Print-Loop의 약자
  • 애플리케이션 실행 상태에서 사용자가 입력한 명령어(소스코드)를 읽고(Read) 명령어를 평가(Eval)하고 결과를 출력(Print)한 다음 다시 입력을 기다리는 상태로 돌아가는 과정을 반복(Loop)함.
  • REPL은 코드 실행 결과를 빠르게 확인하고 싶은 경우 유용함.
0.1
>>> 0.1

# 소숫점을 보고싶은 만큼 출력하기
%precision 55
>>> '%.55f'

0.1
>>> 0.1000000000000000055511151231257827021181583404541015625

# 다시 원래대로 돌아가기
%precision %r
>>> '%r'

0.1
>>> 0.1

실수의 연산 문제를 다시 생각해보자.

print(10 / 3)
>>>3.3333333333333335
0.1 + 1.1 == 1.2
>>> False

두 가지 예시에서 소숫점 55자리까지 표현하여 연산한 결과,

%precision 55   # 소숫점 55자리까지 표현

10 / 3 
>>> 3.3333333333333334813630699500208720564842224121093750000

0.1 + 1.1
>>> 1.2000000000000001776356839400250464677810668945312500000
  • 첫번째 문제는 소수점 17번째 자리에서 반올림한 값을 출력한 것임을 알 수 있다.
  • 두번째 문제는 0.1 + 1.1 의 결과가 정확한 1.2의 값이 아닌 일정 소수점 이하를 생략하고 출력된 결과임을 알 수 있다.

✔ 실수의 비교

  • round명령을 사용하여 유효숫자를 지정한 반올림을 한 후에 비교해야 함.
  • round명령은 두 번째 인수로 반올림할 소수점 이하의 유효숫자의 개수를 입력. 
round(0.1 + 1.1, 3) == round(1.2, 3)
>>> True

 

 

728x90
반응형
LIST