단정밀도 부동소수점수

**단정밀도 부동소수점수**, **단정밀도 부동소수점 형식**(Single-precision floating-point format, **FP32** 또는 **float32**)은 일반적으로 주기억장치에서 32비트를 차지하는 컴퓨터 숫자 형식이다. 이는 부동소수점을 사용하여 넓은 동적 범위의 숫자 값을 나타낸다. 부동소수점 변수는 정밀도를 희생하는 대신 동일한 비트 너비의 고정소수점 변수보다 더 넓은 범위의 숫자를 표현할 수 있다. 부호 있는 32비트 정수형 변수의 최댓값은 231 − 1 = 2,147,483,647인 반면, IEEE 754 32비트 2진 부동소수점 변수의 최댓값은 (2 − 2−23) × 2127 ≈ 3.4028235 × 1038이다. 7자리 이하의 모든 십진 정수와 −149 ≤ n ≤ 127인 모든 정수 n에 대한 2n은 IEEE 754 단정밀도 부동소수점 값으로 정확하게 변환될 수 있다. IEEE 754 표준에서 32비트 2진 형식은 공식적으로 **binary32**라고 불리며, IEEE 754-1985에서는 **single**이라고 불렸다. IEEE 754는 64비트 2진 배정밀도와 최근의 10진 표현과 같은 추가적인 부동소수점 유형을 지정한다. 단정밀도 및 배정밀도 부동소수점 자료형을 제공한 최초의 프로그래밍 언어 중 하나는 포트란이었다. IEEE 754-1985가 널리 채택되기 전에는 부동소수점 자료형의 표현과 속성이 컴퓨터 제조업체와 컴퓨터 모델, 그리고 프로그래밍 언어 설계자가 내린 결정에 따라 달라졌다. 예를 들어, GW 베이직의 단정밀도 자료형은 32비트 MBF 부동소수점 형식이었다. 단정밀도는 포트란에서는 REAL,url-status=dead 커먼 리스프에서는 SINGLE-FLOAT,website=www.lispworks.com C, C++, C# 및 자바에서는 float,website=Java Documentation 하스켈website=haskell.org 및 스위프트에서는 Float,website=Apple Developer Documentation 그리고 오브젝트 파스칼 (델파이), 비주얼 베이직 및 매트랩에서는 Single이라고 부른다. 그러나 파이썬, 루비, PHP, OCaml의 float 및 옥타브 3.2 이전 버전의 single은 배정밀도 숫자를 나타낸다. 대부분의 포스트스크립트 구현과 일부 임베디드 시스템에서는 단정밀도만 지원된다.
# IEEE 754 표준: binary32
IEEE 754 표준은 binary32가 다음을 갖도록 지정한다. * 부호 비트: 1비트 * 지수 너비: 8비트 * 가수 정밀도: 24비트 (23비트 명시적으로 저장) 이는 6에서 9 유효 십진수 정밀도를 제공한다. 최대 6개의 유효 숫자를 가진 십진수 문자열이 IEEE 754 단정밀도 형식으로 변환되어 정규화된 수를 생성한 다음, 동일한 자릿수의 십진수 문자열로 다시 변환되면 최종 결과는 원래 문자열과 일치해야 한다. IEEE 754 단정밀도 숫자가 최소 9개의 유효 숫자를 가진 십진수 문자열로 변환된 다음, 단정밀도 표현으로 다시 변환되면 최종 결과는 원래 숫자와 일치해야 한다.archive-date=8 February 2012 부호 비트는 숫자의 부호를 결정하며, 이는 가수의 부호이기도 하다. "1"은 음수를 나타낸다. 지수 필드는 0부터 255까지의 8비트 부호 없는 정수이며, 편향 형식이다. 즉, 127의 값은 실제 지수 0을 나타낸다. 지수 필드의 값 0(모두 0)과 255(모두 1)는 특수 숫자(비정규 값수, 부호 있는 0, 무한, NaN 등)를 위해 예약되어 있으므로, 지수 범위는 -126에서 +127까지이다(지수 필드에서는 1에서 254까지). 정규화된 숫자의 실제 가수는 이진점 오른쪽에 23개의 분수 비트와 값 1을 가진 숨겨진 선행 비트 (이진점의 왼쪽에)를 포함한다. 비정규화된 숫자와 0 (가장 작은 양의 정규화된 숫자보다 절댓값이 작은 부동소수점 숫자)은 편향된 지수 값 0으로 표현되며, 숨겨진 선행 비트의 값은 0이 된다. 따라서 가수의 23개의 분수 비트만 메모리 형식에 나타나지만, 총 정밀도는 정규화된 값의 경우 24비트(log10(224) ≈ 7.225 십진수 자릿수와 동일)이며, 비정규화된 값은 가장 작은 비영(non-zero) 값의 경우 1비트까지 점진적으로 정밀도가 저하된다. 비트 배치는 다음과 같다: 파일:Float 주어진 부호, 편향된 지수 E (8비트 부호 없는 정수), 23비트 분수를 가진 32비트 binary32 데이터가 나타내는 실제 값은 다음과 같다. : (-1)^{b_{31 \times 2^{(b_{30}b_{29} \dots b_{23})_2 - 127} \times (1.b_{22}b_{21} \dots b_0)_2, 이는 다음을 산출한다: : \text{value} = (-1)^\text{sign} \times 2^{(E-127)} \times \left(1 + \sum_{i=1}^{23} b_{23-i} 2^{-i} \right). 이 예시에서: * \text{sign} = b_{31} = 0, * (-1)^\text{sign} = (-1)^{0} = +1 \in \\{-1, +1\\}, * E = (b_{30}b_{29} \dots b_{23})_2 = \sum_{i=0}^{7} b_{23+i} 2^{+i} = 124 \in \\{1, \ldots, (2^8 - 1) - 1\\} = \\{1, \ldots, 254 \\}, * 2^{(E-127)} = 2^{124-127} = 2^{-3} \in \\{2^{-126}, \ldots, 2^{127}\\} , * 1.b_{22}b_{21}...b_{0} = 1 + \sum_{i=1}^{23} b_{23-i} 2^{-i} = 1 + 1\cdot 2^{-2} = 1.25 \in \\{1, 1+2^{-23}, \ldots, 2-2^{-23}\\} \subset [1; 2 - 2^{-23}] \subset [1; 2). 따라서: * \text{value} = (+1) \times 2^{-3} \times 1.25 = +0.15625. 참고: * 1+2^{-23} \approx 1.000\,000\,119, * 2-2^{-23} \approx 1.999\,999\,881, * 2^{-126} \approx 1.175\,494\,35 \times 10^{-38}, * 2^{+127} \approx 1.701\,411\,83 \times 10^{+38}.
## 지수 인코딩
단정밀도 이진 부동소수점 지수는 오프셋 이진 표현을 사용하여 인코딩되며, 0 오프셋은 127이다. 이는 IEEE 754 표준에서 지수 바이어스라고도 알려져 있다. * Emin = 01H−7FH = −126 * Emax = FEH−7FH = 127 * 지수 편향 = 7FH = 127 따라서 오프셋 이진 표현에 따라 정의된 실제 지수를 얻으려면 저장된 지수에서 127의 오프셋을 빼야 한다. 저장된 지수 00H와 FFH는 특별하게 해석된다. {|class="wikitable" |- | 00H = 000000002|| ±0||비정규화된 숫자 || (-1)^\text{sign}\times2^{-126}\times0.\text{fraction} |- | 01H, ..., FEH = 000000012, ..., 111111102||colspan=2| 정규 값 || (-1)^\text{sign}\times2^{\text{exponent}-127}\times1.\text{fraction} |- | FFH = 111111112|| ±무한 || NaN (quiet, signaling) || |} 최소 양의 정규 값은 2^{-126} \approx 1.18 \times 10^{-38}이고, 최소 양의 (비정규) 값은 2^{-149} \approx 1.4 \times 10^{-45}이다.
## 십진수를 binary32로 변환
일반적으로 실수에서 동등한 binary32 형식으로의 엄격한 변환 (반올림 동작 포함)에 대해서는 IEEE 754 표준 자체를 참조할 것. 여기에서는 다음 개요를 사용하여 10진수 실수를 IEEE 754 binary32 형식으로 변환하는 방법을 보여줄 수 있다. * 12.375와 같은 정수 부분과 분수 부분을 가진 실수를 고려한다. * 정수 부분을 이진수로 변환하고 정규화한다. * 다음 기술을 사용하여 분수 부분을 변환한다. * 두 결과를 더하고 적절히 조정하여 올바른 최종 변환을 생성한다. **분수 부분의 변환:** 12.375의 분수 부분인 0.375를 고려한다. 이를 이진 분수로 변환하려면, 분수에 2를 곱하고, 정수 부분을 취한 다음, 분수가 0이 되거나 IEEE 754 binary32 형식의 정밀도 한계인 23개 분수 자릿수에 도달할 때까지 새 분수에 2를 곱하는 과정을 반복한다. : 0.375 \times 2 = 0.750 = 0 + 0.750 \Rightarrow b_{-1} = 0, 정수 부분은 이진 분수 자릿수를 나타낸다. 계속하기 위해 0.750에 2를 다시 곱한다. : 0.750 \times 2 = 1.500 = 1 + 0.500 \Rightarrow b_{-2} = 1 : 0.500 \times 2 = 1.000 = 1 + 0.000 \Rightarrow b_{-3} = 1, 분수 = 0.011, 종료 (0.375)_{10}는 이진수로 (0.011)_2로 정확하게 표현될 수 있음을 알 수 있다. 모든 십진수 분수가 유한 자릿수 이진 분수로 표현될 수 있는 것은 아니다. 예를 들어, 십진수 0.1은 이진수로 정확하게 표현될 수 없으며, 근사치로만 표현될 수 있다. 따라서: : (12.375)_{10} = (12)_{10} + (0.375)_{10} = (1100)_2 + (0.011)_2 = (1100.011)_2 IEEE 754 binary32 형식은 실제 값을 (1.x_1x_2...x_{23})_2 \times 2^{e} 형식으로 표현해야 하므로 (정규화된 수, 비정규 값 참조), 1100.011은 (1.100011)_2 \times 2^{3}이 되도록 3자리 오른쪽으로 이동한다. 결론적으로 다음을 알 수 있다: (12.375)_{10} = (1.100011)_2 \times 2^{3} 이를 통해 다음을 추론할 수 있다: * 지수는 3이다 (편향 형식에서는 (127+3)_{10} = (130)_{10} = (1000\ 0010)_{2}). * 분수는 100011이다 (이진점 오른쪽을 보면). 이것들로부터 12.375의 결과적인 32비트 IEEE 754 binary32 형식 표현을 구성할 수 있다: : (12.375)_{10} = (0\ 10000010\ 10001100000000000000000)_{2} = (41460000)_{16} 참고: 68.123을 IEEE 754 binary32 형식으로 변환하는 것을 고려한다: 위의 절차를 사용하면 마지막 4비트가 1001인 (\text{42883EF9})_{16}을 얻을 것으로 예상된다. 그러나 IEEE 754 형식의 기본 반올림 동작으로 인해 얻는 값은 마지막 4비트가 1010인 (\text{42883EFA})_{16}이다. **예시 1:** 십진수 1을 고려한다. 다음을 알 수 있다: (1)_{10} =(1.0)_2 \times 2^{0} 이를 통해 다음을 추론할 수 있다: * 지수는 0이다 (편향 형식에서는 (127+0)_{10}=(127)_{10} = (0111\ 1111)_{2}이다). * 분수는 0이다 (1.0에서 이진점 오른쪽은 모두 0 = 000...0이다). 이것들로부터 실수 1의 결과적인 32비트 IEEE 754 binary32 형식 표현을 구성할 수 있다: : (1)_{10} = (0\ 01111111\ 00000000000000000000000)_{2} = (\text{3F800000})_{16} **예시 2:** 값 0.25를 고려한다. 다음을 알 수 있다: (0.25)_{10} =(1.0)_2 \times 2^{-2} 이를 통해 다음을 추론할 수 있다: * 지수는 -2이다 (편향 형식에서는 (127+(-2))_{10} = (125)_{10} = (0111\ 1101)_{2}이다). * 분수는 0이다 (1.0에서 이진점 오른쪽은 모두 0이다). 이것들로부터 실수 0.25의 결과적인 32비트 IEEE 754 binary32 형식 표현을 구성할 수 있다: : (0.25)_{10} = (0\ 01111101\ 00000000000000000000000)_{2} = (\text{3E800000})_{16} **예시 3:** 0.375의 값을 고려한다. 0.375 = {(0.011)_2} = {(1.1)_2}\times 2^{-2}임을 보았다. 따라서 0.375를 {(1.1)_2}\times 2^{-2}로 표현한 후, 위와 같이 진행할 수 있다: * 지수는 -2이다 (편향 형식에서는 (127+(-2))_{10} = (125)_{10} = (0111\ 1101)_{2}이다). * 분수는 1이다 (1.1에서 이진점 오른쪽을 보면 단일 1 = x_1이다). 이것들로부터 실수 0.375의 결과적인 32비트 IEEE 754 binary32 형식 표현을 구성할 수 있다: : (0.375)_{10} = (0\ 01111101\ 10000000000000000000000)_{2} = (\text{3EC00000})_{16}
## binary32를 십진수로 변환
이 예시에서, binary32 값인 41C80000이 16진수일 경우, 먼저 2진수로 변환한다: : \text{41C8 0000}_{16} = 0100\ 0001\ 1100\ 1000\ 0000\ 0000\ 0000\ 0000_{2} 그 다음, 이를 세 부분으로 나눈다: 부호 비트, 지수, 가수. * 부호 비트: 0_2 * 지수: 1000\ 0011_2 = 83_{16} = 131_{10} * 가수: 100\ 1000\ 0000\ 0000\ 0000\ 0000_2 = 480000_{16} 그런 다음 가수에 숨겨진 24번째 비트를 추가한다: * 가수: \mathbf{1}100\ 1000\ 0000\ 0000\ 0000\ 0000_2 = \text{C80000}_{16} 그리고 127을 빼서 지수 값을 디코딩한다: * 원본 지수: 83_{16} = 131_{10} * 디코딩된 지수: 131 - 127 = 4 가수의 24비트(숨겨진 24번째 비트 포함), 비트 23부터 비트 0까지는 각각 1부터 시작하여 각 비트마다 절반이 되는 값을 나타내며, 다음과 같다: 비트 23 = 1 비트 22 = 0.5 비트 21 = 0.25 비트 20 = 0.125 비트 19 = 0.0625 비트 18 = 0.03125 비트 17 = 0.015625 . . 비트 6 = 0.00000762939453125 비트 5 = 0.000003814697265625 비트 4 = 0.0000019073486328125 비트 3 = 0.00000095367431640625 비트 2 = 0.000000476837158203125 비트 1 = 0.0000002384185791015625 비트 0 = 0.00000011920928955078125 이 예시의 가수는 세 비트가 설정되어 있다: 비트 23, 비트 22, 비트 19. 이제 이 비트들이 나타내는 값을 더하여 가수를 디코딩할 수 있다. * 디코딩된 가수: 1 + 0.5 + 0.0625 = 1.5625 = \text{C80000}/2^{23} 그런 다음, 최종 결과를 얻기 위해 지수의 거듭제곱인 2를 밑으로 곱해야 한다: : 1.5625 \times 2^4 = 25 따라서 : \text{41C8 0000} = 25 이는 다음과 같다: : n = (-1)^s \times (1+m*2^{-23})\times 2^{x - 127} 여기서 s는 부호 비트, x는 지수, 그리고 m은 가수이다.
## 십진수 값에 대한 정밀도 제한 (1과 16777216 사이)
* 1과 2 사이의 십진수: 고정 간격 2−23 (1+2−23은 1 다음으로 가장 큰 부동소수점) * 2와 4 사이의 십진수: 고정 간격 2−22 * 4와 8 사이의 십진수: 고정 간격 2−21 * ... * 2n과 2n+1 사이의 십진수: 고정 간격 2n−23 * ... * 222=4194304와 223=8388608 사이의 십진수: 고정 간격 2−1=0.5 * 223=8388608과 224=16777216 사이의 십진수: 고정 간격 20=1
## 정수 값에 대한 정밀도 제한
* 0에서 16777216 사이의 정수는 정확하게 표현될 수 있다 (–16777216에서 0 사이의 음의 정수에도 적용된다). * 224=16777216과 225=33554432 사이의 정수는 2의 배수(짝수)로 반올림된다. * 225와 226 사이의 정수는 4의 배수로 반올림된다. * ... * 2n과 2n+1 사이의 정수는 2n−23의 배수로 반올림된다. * ... * 2127과 2128 사이의 정수는 2104의 배수로 반올림된다. * 2128 이상의 정수는 "무한대"로 반올림된다.
## 주목할 만한 단정밀도 사례
이 예시들은 부동소수점 값의 16진수와 2진수 비트 표현으로 주어진다. 여기에는 부호, (편향된) 지수 및 가수가 포함된다. 0 00000000 000000000000000000000012 = 0000 000116 = 2−126 × 2−23 = 2−149 ≈ 1.4012984643 × 10−45 (가장 작은 양의 비정규화된 숫자) 0 00000000 111111111111111111111112 = 007f ffff16 = 2−126 × (1 − 2−23) ≈ 1.1754942107 ×10−38 (가장 큰 비정규화된 숫자) 0 00000001 000000000000000000000002 = 0080 000016 = 2−126 ≈ 1.1754943508 × 10−38 (가장 작은 양의 정규화된 숫자) 0 11111110 111111111111111111111112 = 7f7f ffff16 = 2127 × (2 − 2−23) ≈ 3.4028234664 × 1038 (가장 큰 정규화된 숫자) 0 01111110 111111111111111111111112 = 3f7f ffff16 = 1 − 2−24 ≈ 0.999999940395355225 (1보다 작은 가장 큰 숫자) 0 01111111 000000000000000000000002 = 3f80 000016 = 1 (하나) 0 01111111 000000000000000000000012 = 3f80 000116 = 1 + 2−23 ≈ 1.00000011920928955 (1보다 큰 가장 작은 숫자) 1 10000000 000000000000000000000002 = c000 000016 = −2 0 00000000 000000000000000000000002 = 0000 000016 = 0 1 00000000 000000000000000000000002 = 8000 000016 = −0 0 11111111 000000000000000000000002 = 7f80 000016 = 무한대 1 11111111 000000000000000000000002 = ff80 000016 = −무한대 0 10000000 100100100001111110110112 = 4049 0fdb16 ≈ 3.14159274101257324 ≈ π (파이) 0 01111101 010101010101010101010112 = 3eaa aaab16 ≈ 0.333333343267440796 ≈ 1/3 x 11111111 100000000000000000000012 = ffc0 000116 = qNaN (x86 및 ARM 프로세서에서) x 11111111 000000000000000000000012 = ff80 000116 = sNaN (x86 및 ARM 프로세서에서) 기본적으로 1/3은 가수의 비트 수가 짝수이기 때문에 배정밀도처럼 내림 대신 올림한다. 반올림 지점 너머의 1/3 비트는 `1010...`으로 ULP의 1/2보다 크다. qNaN 및 sNaN의 인코딩은 IEEE 754에 지정되어 있지 않으며, 프로세서마다 다르게 구현된다. X86 계열 및 ARM 계열 프로세서는 가수의 최상위 비트를 사용하여 콰이어트 NaN을 나타낸다. PA-RISC 프로세서는 이 비트를 사용하여 시그널링 NaN을 나타낸다.
## 최적화
부동소수점 형식의 설계는 원시 비트 패턴의 정수적인 관점에서 이진 로그 근사치를 쉽게 생성할 수 있게 하여 다양한 최적화를 가능하게 한다. 정수 산술 및 비트 시프팅은 컴퓨터 그래픽스에서 흔히 요구되는 고속 역 제곱근의 근사치를 제공할 수 있다.