실수(Real Number) = 실제 자연상에 존재하는 수량을 표시하는 수
정수(Integer) = 가지런한 수. 1보다 큰 수
소수(Fraction) = 작은 수. 1보다 작은 수.
소수점 (decimal point) = 정수부와 소수부를 구분하는 점
# 실수 = 정수.소수
(1) 고정소수점 - 정수.소수 (고정)
(2) 부동소수점
! 이것만 알고 가렴 !
- 4바이트 유효자릿수 7
- 8바이트 유효자릿수 15
- IEEE-754 규격의 결함으로, 유효자릿수 내에서도 실수가 완벽하게 표현되지 않을 수 있음(CPU, OS, 컴파일러, JVM의 문제가 아님)
부동소수
: 소수점이 좌우로 이동하도록 만든 2진수 표현법. 한정된 메모리 공간에 큰 수와 작은 수를 모두 표현하려면 소수점이 자유롭게 이동해야 한다.
1.000 * 10³ = 1000
( 4자리 수 가수부 )( 3 : 지수부 )
가수부 : 수의 정밀도 결정
지수부 : 수의 크기 결정
부동소수점을 2진수로 변환하는 규칙(IEEE-754)
- 부동소수점을 메모리에 저장하려면 2진수로 표현해야 함 -> 정규화(nomalized) 필요 : IEEE-754
- 부동소수점을 2진수로 바꿀 때, 가수부와 지수부로 분리하여 변환
- 가수부(fraction/mantissa) : sign-magnitude 방식
- 지수부(exponent) : Excess-K 방식
- 32비트 float 타입 표현 : 단정도(single-precision)
- [부호비트(1)][지수부(8)][가수부(23)]

- 64비트 double 타입 표현 : 배정도(double-precision)
- [부호비트(1)][지수부(11)][가수부(52)]
- 부호비트(sign bit) : 음수(1) 양수(0)
- 127 bias를 사용한다. 즉 2의 지수 값에 127을 더한 결과 값을 사용한다.
- 1.xxxx 값에서 소수점 왼쪽에 있는 1을 제외한 나머지 수를 사용한다.
- 가수부에 남는 비트가 있다면 0으로 채운다.
<3.14159>
System.out.println(0.0314159e2);
System.out.println(31.4159e-1);
System.out.println(314.159e-2);
System.out.println(3141.59e-3);
System.out.println(3.1415926535f); //3.1415927
System.out.println(3.141592653f); //3.1415927
System.out.println(3.14159265f); //3.1415927
System.out.println(3.1415926f); //3.1415925
System.out.println(3.141592f); //3.141592(OK)
System.out.println(314.1592f); //314.1592
System.out.println(3141.592f); //3141.592
System.out.println(31415.92f); //31415.92
System.out.println(314159.2f); //314159.2
System.out.println(3141592.6f); //3141592.5 (Error)
위 예제를 통해 일정 규칙을 찾을 수 있음
=> 4바이트 메모리에 저장할 수 있는 부동소수점은 소수점의 위치와 상관 없이 숫자의 개수가 7개이면 거의 정상적으 로 저장하고 꺼낼 수 있다.
이렇게 정상적으로 넣고 꺼낼 수 있는 부동소수점의 숫자 개수를 "유효자릿수"라고 부른다.
주의!
부동소수점은 메모리에서 꺼낸 값을 내부의 규칙에 따라 보정하여 리턴하지만, 7자리라 하더라도 값이 구겨질 수 있음(즉, 정상적으로 저장되지 않을 수 있음.)
=> 부동소수점을 2진수로 바꿀 때 IEEE754 규칙에 따라 변경하는데, 이 규칙에서 일부 부동소수점은 2진수로 정확히 변경되지 못하는 문제가 있기 때문.
실수 값을 정규화하는 방법
= 실수 값을 32비트 2진수로 만드는 방법
예: 12.375(10진수)
1) 소수점 앞의 정수 값을 2진수로 변환한다.
12(10진수)
= 1100(2진수)
2) 소수점 뒤의 값을 2진수로 변환한다.
- 변환 규칙
- 소수점을 2로 곱하여 나온 결과에서 정수 부분만을 차례대로 표기한다.
- 소수 부분이 0이거나 반복되면 계산을 멈춘다.
- 예: 0.375(10진수)
0.375 * 2 = 0.75 --> 0
0.75 * 2 = 1.5 --> 1
0.5 * 2 = 1.0 --> 1
=> 0.011(2진수)
3) 2진수 바꾼 최종 결과
12.375(10진수)
= 12(10진수) + 0.375(10진수)
= 1100(2진수) + 0.011(2진수)
= 1100.011(2진수)
= 1*2^3 + 1*2^2 + 0*2^1 + 0*2^0 + 0*2^-1 + 1*2^-2 + 1*2^-3
= 1*8 + 1*4 + 0*2 + 0*1 + 0*0.5 + 1*0.25 + 1*0.125
4) 정규화
- 소수점의 위치를 조정하여 가수부와 지수부를 분리한다.
- IEEE 754 명세는 다음과 같은 형식으로 가수부와 지수부를 나눈다.
1.x1x2x3x4...x23(2진수) * 2^e
=> 소수점 왼쪽에 1만 남도록 소수점을 이동한다.
=> 소수점 왼쪽은 무조건 1이기 때문에 저장하지 않고 버린다.
=> 따라서 소수점 오른쪽 수만 가수부에 놓는다.
즉 x1, x2 등은 가수부 1번 비트부터 23번 비트까지를 의미한다.
=> 23번 비트까지 채우지 못하면 나머지 비트는 0으로 채운다.
- 예)
1100.011(2진수)
= 1.100011(2진수) * 2^3
가수부 => 100011(2진수)
지수부 => 3 + 127(bias) = 130(10진수) = 10000010(2진수)
5) 32비트로 표현하기
[0][10000010][10001100000000000000000]
=> 0100_0001_0100_0110_0000_0000_0000_0000
=> 0x41460000
주의!
- 유효 자릿수의 부동소수점이라도 정규화할 때 2진수로 딱 떨어지지 않은 경우가 있다.
- 예) 2.127
2 => 0010
0.127 =>
0.127 * 2 = 0.254 --> 0
0.254 * 2 = 0.508 --> 0
0.508 * 2 = 1.016 --> 1
0.016 * 2 = 0.032 --> 0
0.032 * 2 = 0.064 --> 0
0.064 * 2 = 0.128 --> 0
0.128 * 2 = 0.256 --> 0
0.256 * 2 = 0.512 --> 0
0.512 * 2 = 1.024 --> 1
0.024 * 2 = 0.048 --> 0
....
이처럼 2진수로 완벽히 표현할 수 없는 수가 있다.
0.00000....1 의 오차가 있다.
그래서 부동소수점은 정수와 다르게 정확하게 메모리에 저장되지 않는다.
'프로그래밍 > CS' 카테고리의 다른 글
| 인터페이스 (0) | 2019.12.11 |
|---|---|
| 문자의 표현 - Character Set (0) | 2019.12.09 |
| 숫자의 표현방법 - sign-magnitude/1's complement/2's complement/Excess-K (0) | 2019.12.09 |
| 데이터의 코드화, 리터럴, 이스케이프 문자 (0) | 2019.12.07 |
| 해석기 - 컴파일러 인터프리터 어셈블러 (0) | 2019.12.07 |