WeniVooks

검색

견고한 파이썬

실수 자료형

1. 실수란?

수학에서 실수(實數, real number)는 실제로 존재하는 수입니다. 파이썬에서 실수는 float 표현됩니다. float는 소수점이 있는 숫자를 나타냅니다. 예를 들어, 3.14, 0.001, -0.1 등이 있습니다. 앞에 0은 생략할 수 있습니다. 0.1.1은 같은 값을 나타냅니다.

1.1 실수 타입의 변수 생성
x = 10.0 y = 10 print(type(x), type(y)) # 출력 : <class 'float'> <class 'int'>

이 예제에서 x, y는 모두 10을 저장하고 있습니다. 하지만 x는 실수형, y는 정수형입니다. 10.0은 뒤에 소숫점으로 인하여 실수로 인식되기 때문입니다.

1.2 실수의 사칙연산

실수도 기본적인 산술연산을 지원합니다. 이 챕터에서는 간단한 사칙연산만 해보도록 하겠습니다.

1.2.1 덧셈

실수와 실수의 덧셈은 결과가 실수로 나옵니다.

x = 9.9 y = 20.1 result = x + y print(result) print(type(result))

실수와 정수의 덧셈도 결과는 실수로 나옵니다. 다른 언어는 정수와 실수의 덧셈이 애러가 나는 경우도 있습니다. 이러한 결과가 일반적이진 않다는 것을 기억해주세요.

x = 10.0 y = 20 result = x + y print(result) print(type(result))
1.2.2 뺄셈
x = 15.5 y = 5.5 result = x - y print(result) print(type(result))
1.2.3 곱셈
x = 10.0 y = 2 result = x * y print(result) print(type(result))
1.2.4 나눗셈

나눗셈은 두 종류가 있습니다. 하나는 나눗셈의 결과를 소숫점까지 표시(/)하는 것이고, 다른 하나는 나눗셈을 하고 나머지를 버리는(//) 것입니다.

x = 10 y = 5 result = x / y print(result) print(type(result)) x = 10.0 y = 5.0 result = x // y print(result) print(type(result))

위 코드의 실행 결과는 정수가 나올 것 같지만 실수가 나옵니다.

x = 10.0 y = 5 result = x / y print(result) print(type(result))

실수와 정수의 나눗셈도 결과는 실수로 나옵니다.

2. float의 특수값

파이썬의 float 클래스에는 몇몇 특별한 값을 가진 상수들이 있습니다. 여기서는 자주 사용되는 양의 무한대와 음의 무한대를 알아보도록 하겠습니다.

  • inf: 양의 무한대를 나타내는 상수입니다.
x = float("inf")
x = float("inf")
  • -inf: 음의 무한대를 나타내는 상수입니다.
x = float("-inf")
x = float("-inf")

이러한 무한대는 아래와 같이 비교 구문에서 활용될 수 있습니다.

float("inf") > 10

3. 실수의 부동소수점 문제

실수의 연산은 정수와 다르게 정확하지 않을 수 있습니다. 이를 고려하여 코드를 작성해야 합니다.

예를 들어 아래와 같은 연산은 컴퓨터가 정확히 연산할 수 없습니다. 대부분의 프로그래밍 언어에서 이를 정확히 처리하지 못합니다. 결과를 예상하고 실행해보세요.

10.1 + 10.2

위의 출력값은 10.3이 아닙니다. 20.299999999999997입니다. 이는 아래와 같은 연산도 마찬가지입니다.

0.1 + 0.2

파이썬의 float는 IEEE 754 표준을 따르는 64비트 배정밀도(double precision)로 구현되어 있습니다. 이 표준은 10진수 숫자를 표현하는데 완벽하지 않습니다. 대부분의 프로그래밍 언어는 이 표준을 따릅니다. 컴퓨터 연산은 2진수로 이뤄지기 때문에 10진수를 2진수로 변환하는 과정에서 오차가 발생하는 것이죠.

이를 이해하기 위해서는 우선 10진수를 2진수로 바꾸는 방법을 알아야 합니다. 프로그래밍 언어는 기본적으로 사람이 사용하기 편리하도록 10진수를 기반으로 수를 표현하지만 컴파일 과정에서 2진수로 전환되기 때문입니다.

앞의 정수부(0)는 그대로 두고 소수부에 1이 나올 때까지 2를 곱합니다.

.5 * 2 === 1
.5 * 2 === 1

1이 나오면 이제 정수부와 합쳐봅니다. 이것이 소수를 이진수로 바꾸는 방법입니다.

0.5의 이진수 표현은 0.1
0.5의 이진수 표현은 0.1

이번에는 0.1을 이진수로 바꿔보겠습니다.

.1 * 2 === 0.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4, # 여기서부터 같은 결과가 반복되기 시작합니다.
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.
.
.
정부수와 합치면 결과는 0.000110011001100110011... 이 됩니다.
.1 * 2 === 0.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4, # 여기서부터 같은 결과가 반복되기 시작합니다.
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.
.
.
정부수와 합치면 결과는 0.000110011001100110011... 이 됩니다.

0.5와 다르게 0.1은 무한소수가 됩니다. 컴퓨터는 메모리의 한계로 무한한 값을 저장할 수 없기 때문에 적당한 소수점 위치에서 반올림하여 계산을 종료합니다.

이번에는 0.2를 이진수로 바꿔보겠습니다.

.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.
.
.
정부수와 합치면 결과는 0.00110011001100110011... 이 됩니다.
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.6 * 2 === 1.2,
.2 * 2 === 0.4,
.4 * 2 === 0.8,
.8 * 2 === 1.6,
.
.
.
정부수와 합치면 결과는 0.00110011001100110011... 이 됩니다.

마찬가지로 0.2 역시 무한소수가 됩니다. 때문에 프로그래밍 언어는 값을 확실히 계산할 수 없는 두 수의 합을 십진수로 계산해야하기 때문에 오차가 발생합니다.

실제로 파이썬이 표현 가능한 0.3과 가장 가까운 수는 0.299999999999999988897769753748434595763683319091796875 입니다. 하지만 여기서 적당히 소수점 버림을 하면 0.1 + 0.2 의 답은 0.2 가 되어버리기 때문에 표현할 수 있는 살짝 더 큰 수인 0.30000000000000004 를 반환하는 것입니다.

해결하기

이를 해결하는 방법은 여러가지 방법이 있습니다. python에서는 decimal을 사용하여 좀 더 정확한 연산을 할 수 있습니다. 아래 서비스는 여러가지 언어들에서 발생하는 문제를 해결하는 방법을 담고 있습니다. 다른 언어를 하실 때에도 아래 서비스를 이용하시면 쉽게 해결책을 검색해볼 수 있습니다.

Floating Point Math
import decimal float(decimal.Decimal('.1') + decimal.Decimal('.2')) # 출력: 0.3

4. 지수의 표현

10에 승수는 eE로 표현할 수 있습니다. 이는 모두 float형으로 표현됩니다.

print(2e3) # 지수표현, float형 print(2E3) print(2 * (10 ** 3)) # int 형

아래처럼 float형이 표현할 수 있는 수, 부동 소수점이 표현할 수 있는 수를 넘겨버리면 무한수로 취급됩니다. 항상 모든 수에서 float('inf')가 더 큰 값은 아니라는 점을 기억해주세요.

# IEEE 754 배정밀도 부동 소수점 표현에서 가장 큰 (정규화된) 유한 값은 대략 1.8 * (10 ** 308)입니다. 10e308는 이 근사치보다 큰 값입니다. int는 메모리 제한 내에서 한계 없이 표현합니다.
 
print(float('inf') > 10e307)
print(float('inf') > 10e308)
 
float('inf') == 10e307, float('inf') == 10e308, float('inf') == 10e309
# IEEE 754 배정밀도 부동 소수점 표현에서 가장 큰 (정규화된) 유한 값은 대략 1.8 * (10 ** 308)입니다. 10e308는 이 근사치보다 큰 값입니다. int는 메모리 제한 내에서 한계 없이 표현합니다.
 
print(float('inf') > 10e307)
print(float('inf') > 10e308)
 
float('inf') == 10e307, float('inf') == 10e308, float('inf') == 10e309
{"packages":["numpy","pandas","matplotlib","lxml"]}
4.2 정수 자료형4.4 복소수 자료형