[ComputerScience bootcamp with python 3장]
in Python on BootcampPython
본 포스팅은
컴퓨터사이언스 부트캠프 with 파이썬
이라는 책을 참고하여 개인 공부를 하면서 정리하고 있습니다.문제 될 시 삭제하겠습니다.
Chapter 3 실수
실수 표현은 표현 범위가 넓은 대신 정밀도가 낮음
3-1. 실수 연산의 함정
a = 0.01
result = 0.0
for i in range(100):
result += a
>>> result
1.0000000000000007
# 0.01을 100번 더했으니 1이 나오는 것을 예상했지만 아님
1에 매우 가까운 수라고는 해도 1은 아니다
이번에는 0.015625를 100번 더할 계획
계산결과 1.5625 라고 예상
a = 0.015625
>>> a
0.015625
result = 0.0
for i in range(100):
result += a
>>> result
1.5625
# 이번에는 예측한 결과가 정확하게 나옴
이 결과를 이해하려면 컴퓨터가 실수를 표현하는 방법인 부동소수점이라는 개념을 알아야함
3-2. 부동소수점
ANSI/IEEE 754-1985
라는 컴퓨터에서 부동 소수점 숫자를 나타내는데 사용하는 산업 표준
- 여기서 ‘부’는 둥둥 떠다닌다는 의미
실수 123.456을 여러 가지 방식으로 표현한 것을 살펴보면
- 소수점 위치를 보면 앞에 있기도 하고 뒤에 있기도 함
- 소수점의 위치가 바뀌기 때문에 실수를 표현할 때 주로 사용
고정 소수점 방식보다 넓은 범위의 수를 표현할 수 있음
3-3. 단정도와 배정도
부동소수점에는 단정도 부동소수점과 배정도 부동소수점이 존재
- 단정도
- 실수를 32비트(4바이트)로 표현
- 부호 1비트, 지수부 8비트, 가수부 23비트로 구성
- 배정도
- 실수를 64비트(8바이트)로 표현
- 부호 1비트, 지수부 11비트, 가수부 52비트로 구성
- 단정도보다 두 배 많은 만큼 정밀도가 높음
- 파이썬은 배정도를 사용
import sys >>> sys.float_info sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308, min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53, epsilon=2.220446049250313e-16, radix=2, rounds=1)
- sys 모듈
- 파이썬
인터프리터
를 제어 할 수 있음 인터프리터: 소스 코드를 바로 실행하는 프로그램 또는 환경
- 파이썬
sys 모듈을 임포트한 다음 float_info를 입력하면 최댓값, 최솟값, 정밀도 등 확인 가능
- 배정도 부동소수점으로 표현할 수 있는 가장 큰 수
>>> sys.float_info.max
1.7976931348623157e+308
여기서 e
는 지수를 뜻함 exponent 줄임말
지수만 봐도 10의 308승이니 엄청나게 큰 수인걸 알 수 있음
1.7976931348623157 × 10^308
- 배정도 부동소수점으로 표현할 수 있는 가장 작은 수
>>> sys.float_info.min
2.2250738585072014e-308
10의 -308승이 굉장히 작은지 알 수 있음
그만큼 8바이트 배정도 부동소수점을 사용하면 표현 범위가 엄청나게 넓어짐
2.2250738585072014 × 10^308
3-4. 1바이트 실수 자료형 설계
1바이트 실수 자료형을 수식으로 표현하면?
± 1.man × 2^exp - bias
1.man은 가수, 2는 밑수, exp-bias는 지수 의미
이 식을 이용해 7.75라는 10진수 실수를 1바이트 부동소수점으로 표현하면?
먼저, 2진수에 대한 식이므로 우선 7.75라는 10진수 실수를 2진수 실수바꾸는 작업을 먼저 해야 한다
3-4-1. 1바이트 실수 자료형 설계
10진수 실수를 2진수로 바꾸는 방법은 정수를 바꿨던 방법과 크게 다르지 않음
2^-1 은 음수가 아니라 분수 1/2, 2^-2 는 1/4
7.75 = 4 + 2 +1 + 0.5 + 0.25
= 22 + 21+ 20+ 2^-1+ 2^-2
= 111.11
3-4-2. 정규화
정규화란 소수점 왼쪽에 위치한 가수 부분을 밑수보다 작은 자연수가 되도록 만드는 것
예를 들어 10진수 567.89를 정규화하면?
소수점 왼쪽에 위치한 가수 부분이 밑수 10보다 작은 자연수가 5가 되어
5.6789x10^2
2진수의 밑수는 2
- 2보다 작은 자연수는 1 만 존재
- 소수점 왼쪽의 가수 부분은 항상 1이 됨
즉, 111.11을 정규화하면 111.11 = 1.1111 x 2^2
3-4-3. 메모리 구조
정규화된 부동소수점 수 1.1111 x 2^2
을 앞의 수식과 비교해 보면?
man
은 1111exp - bias
는 2
이제 1바이트의 메모리 구조를 정하고 man
과 exp
값만 저장하면 설계는 끝남
이때, 지수부와 가수부에 할당하는 비트 수에 따라 표현 범위와 정밀도가 결정됨
1바이트 부동소수점이 어떻게 구성될까?
- 첫 번째 비트는 부호를 나타냄
0
이면 양수1
이면 음수
- 가운데 4비트는 지수부로
exp
값 저장 - 맨 뒤 3비트는 가수부로
man
값 저장
이 때 bias
는 지수의 부호를 결정하는데 쓰임
부동소수점의 지수부에는 부호 비트가 없으며 0~15의 양수만 나타낼 수 있음
하지만 음수 지수도 필요함
음수를 사용하려면 bias
를 7로 두고 지수부(exp)에서 bias
를 뺀 값을 실제 지수로 사용
bias
는 2^n-1 - 1
식에 지수부의 비트 수인 4를 대입
위의 3-4-2절
에서 정규화된 수 1.1111x2^2
에서 실제 지수는 2라는 의미는 exp-bias
가 2라는 것
지수부의 비트 수 4를 식 2^n-1 -1
에 대입해 얻은 bias
값이 7
실제로 부동소수점의 지수부에 나타나는 값 exp
는 9
bias = 2^n-1 -1 = 7
exp - 7 = 2
exp = 9
필요한 값을 모두 구했으니 1바이트를 구성하면?
- 부호 => 0
- 지수부 => 1001
- 가수부 => 1111
그치만 여기서 문제가 있는데 가수부는 3비트만 할당되는데 1111이다
이런 경우에는 뒷자리 1을 생략함
즉, 가수부는 111
0 1001 111 = 0100 1111 = 0x4f
실수 7.75는 1바이트 부동소수점으로 나타내면 0x4f
부동소수점을 계산할 때는 보수의 개념을 사용하지 않음
엡실론과 정밀도
엡실론(epsilon)
엡실론이란 1.0과 그 다음으로 표현 가능한 수 사이의 차이를 말하며, 이 엡실론은 실수들의 정밀도를 표현하는데 사용된다
배정도 실수 9.25를 부동소수점 방식으로 표현하면 1.00101 * 23 이다
위 식에서 지수 부분만 떼어 내 엡실론을 곱하면 이 실수와 다음 표현 가능한 수 사이의 차이를 구할 수 있음
import sys
ep = sys.float_info.epsilon
a = 9.25
diff = (2**3)*ep
>>> diff
1.7763568394002505e-15
b = a + diff
>>> b
9.250000000000002
epsilon은 1.0과 그 다음 수의 표현 가능한 수의 차이
따라서 위 식은 지수 부분이 1.0 * 20 이 아니라 (1.0) * 23 이므로 1.0 * 23 * epsilon을 해줘야
23 만큼 소수점이 움직인
epsilon
을 구할 수 있음
위 식에서 diff
는 지수 부분인 23 에 엡실론을 곱한 값으로 9.25와 그 다음 표현 가능한 수 사이의 차이
만약에 9.25에 diff
보다 작은 값을 더하면 부동소수점 방식에서는 이 값을 다르게 표현 할 방법이 없다
예를 들어 9.25에 diff/2
더한 값과 9.25을 비교해도 두 값은 같다고 컴퓨터는 인식함
왜냐하면 표현 가능한 수의 차이 보다 작은 값을 더했기 때문에 컴퓨터가 인식하지 못하기 때문