본문으로 이동

배정밀도 부동소수점수

위키백과, 우리 모두의 백과사전.

배정밀도 부동소수점수, 배정밀도 부동소수점 형식(Double-precision floating-point format, FP64 또는 float64)은 일반적으로 컴퓨터 메모리에서 64 비트를 차지하는 부동소수점 숫자 형식이다. 이는 부동 기수점을 사용하여 광범위한 숫자 값을 나타낸다.

배정밀도는 단정밀도의 범위나 정밀도가 불충분할 때 선택할 수 있다.

IEEE 754 표준에서 64비트 2진 형식은 공식적으로 binary64로 불리며, IEEE 754-1985에서는 double이라고 불렸다. IEEE 754는 32비트 2진 단정밀도와 최근에는 10진수 표현(10진수 부동소수점)을 포함한 추가적인 부동소수점 형식을 명시한다.

부동소수점 자료형을 제공한 최초의 프로그래밍 언어 중 하나는 포트란이었다. IEEE 754-1985가 널리 채택되기 전에는 부동소수점 자료형의 표현과 속성이 컴퓨터 제조업체와 컴퓨터 모델, 그리고 프로그래밍 언어 구현자의 결정에 따라 달라졌다. 예를 들어, GW 베이직의 배정밀도 자료형은 64비트 MBF 부동소수점 형식이었다.

IEEE 754 배정밀도 이진 부동소수점 형식: binary64

[편집]

배정밀도 이진 부동소수점은 성능 및 대역폭 비용에도 불구하고 단정밀도 부동소수점보다 넓은 범위를 제공하므로 PC에서 일반적으로 사용되는 형식이다. 이는 흔히 단순히 double이라고 알려져 있다. IEEE 754 표준은 binary64를 다음과 같이 지정한다.

부호 비트는 숫자의 부호를 결정한다 (이 숫자가 0일 때도 부호 있는 0을 포함한다).

지수 필드는 0부터 2047까지의 11비트 부호 없는 정수로, 바이어스 형식이다. 즉, 지수 값 1023이 실제 0을 나타낸다. 지수 범위는 −1022에서 +1023까지인데, 이는 −1023 (모든 비트가 0) 및 +1024 (모든 비트가 1)의 지수가 특수 숫자를 위해 예약되어 있기 때문이다.

53비트 유효숫자 정밀도는 15에서 17 유효 십진 자릿수 정밀도를 제공한다 (2−53 ≈ 1.11 × 10−16). 최대 15자리 유효 숫자를 가진 십진 문자열이 IEEE 754 배정밀도 형식으로 변환되어 정규 숫자가 되고, 다시 같은 자릿수의 십진 문자열로 변환되면 최종 결과는 원래 문자열과 일치해야 한다. IEEE 754 배정밀도 숫자가 최소 17자리 유효 숫자를 가진 십진 문자열로 변환되고, 다시 배정밀도 표현으로 변환되면 최종 결과는 원래 숫자와 일치해야 한다.[1]

이 형식은 유효숫자가 값 1의 암묵적인 정수 비트를 가지도록 작성된다 (특수 데이터 제외, 아래 지수 인코딩 참조). 메모리 형식에 나타나는 52비트의 분수 (F) 유효숫자를 통해 총 정밀도는 53비트이다 (약 16 십진수 자릿수, 53 log10(2) ≈ 15.955). 비트는 다음과 같이 배치된다.

주어진 64비트 배정밀도 데이터가 주어진 바이어스 지수 와 52비트 분수를 가질 때의 실제 값은 다음과 같다.

또는

252=4,503,599,627,370,496와 253=9,007,199,254,740,992 사이의 표현 가능한 숫자는 정확히 정수이다. 다음 범위인 253부터 254까지는 모든 것이 2를 곱하므로 표현 가능한 숫자는 짝수 등이 된다. 반대로 이전 범위인 251부터 252까지는 간격이 0.5 등이다.

2n부터 2n+1까지의 범위에서 숫자의 간격은 2n−52이다. 따라서 숫자를 가장 가까운 표현 가능한 숫자로 반올림할 때의 최대 상대 반올림 오차 (계산기 엡실론)는 2−53이다.

지수의 11비트 폭은 10−308에서 10308 사이의 숫자를 15–17자리 전체 십진수 정밀도로 표현할 수 있게 한다. 정밀도를 타협하면 비정규 표현은 약 5 × 10−324까지 더 작은 값을 허용한다.

지수 인코딩

[편집]

배정밀도 이진 부동소수점 지수는 오프셋 이진 표현을 사용하여 인코딩되며, 0 오프셋은 1023이다. 이는 IEEE 754 표준에서 지수 바이어스로도 알려져 있다. 이러한 표현의 예는 다음과 같다.

e =000000000012=00116=1: (정규 숫자의 최소 지수)
e =011111111112=3ff16=1023: (0 오프셋)
e =100000001012=40516=1029:
e =111111111102=7fe16=2046: (최고 지수)

지수 000167ff16는 특별한 의미를 가진다.

  • 000000000002=00016부호 있는 0 (F = 0인 경우)과 비정규 숫자 (F ≠ 0인 경우)를 나타내는 데 사용된다.
  • 111111111112=7ff16 (F = 0인 경우)와 NaN (F ≠ 0인 경우)을 나타내는 데 사용된다.

여기서 F는 유효숫자의 소수 부분이다. 모든 비트 패턴은 유효한 인코딩이다.

위 예외를 제외하고 전체 배정밀도 숫자는 다음으로 설명된다.

비정규 숫자의 경우 (e = 0) 배정밀도 숫자는 다음으로 설명된다.

엔디언

[편집]

배정밀도 예시

[편집]
  0 01111111111 00000000000000000000000000000000000000000000000000002
≙ 3FF0 0000 0000 000016
≙ +20 × 1
= 1
  0 01111111111 00000000000000000000000000000000000000000000000000012
≙ 3FF0 0000 0000 000116
≙ +20 × (1 + 2−52)
≈ 1.0000000000000002220 (1보다 큰 가장 작은 숫자)
  0 01111111111 00000000000000000000000000000000000000000000000000102
≙ 3FF0 0000 0000 000216
≙ +20 × (1 + 2−51)
≈ 1.0000000000000004441 (1보다 큰 두 번째로 작은 숫자)
  0 10000000000 00000000000000000000000000000000000000000000000000002
≙ 4000 0000 0000 000016
≙ +21 × 1
= 2
  1 10000000000 00000000000000000000000000000000000000000000000000002
≙ C000 0000 0000 000016
≙ −21 × 1
= −2
  0 10000000000 10000000000000000000000000000000000000000000000000002
≙ 4008 0000 0000 000016
≙ +21 × 1.12
= 112
= 3
  0 10000000001 00000000000000000000000000000000000000000000000000002
≙ 4010 0000 0000 000016
≙ +22 × 1
= 1002
= 4
  0 10000000001 01000000000000000000000000000000000000000000000000002
≙ 4014 0000 0000 000016
≙ +22 × 1.012
= 1012
= 5
  0 10000000001 10000000000000000000000000000000000000000000000000002
≙ 4018 0000 0000 000016
≙ +22 × 1.12
= 1102
= 6
  0 10000000011 01110000000000000000000000000000000000000000000000002
≙ 4037 0000 0000 000016
≙ +24 × 1.01112
= 101112
= 23
  0 01111111000 10000000000000000000000000000000000000000000000000002
≙ 3F88 0000 0000 000016
≙ +2−7 × 1.12
= 0.000000112
= 0.01171875 (3/256)
  0 00000000000 00000000000000000000000000000000000000000000000000012
≙ 0000 0000 0000 000116
≙ +2−1022 × 2−52
= 2−1074
≈ 4.9406564584124654 × 10−324 (가장 작은 양수 비정규 숫자)
  0 00000000000 11111111111111111111111111111111111111111111111111112
≙ 000F FFFF FFFF FFFF16
≙ +2−1022 × (1 − 2−52)
≈ 2.2250738585072009 × 10−308 (가장 큰 비정규 숫자)
  0 00000000001 00000000000000000000000000000000000000000000000000002
≙ 0010 0000 0000 000016
≙ +2−1022 × 1
≈ 2.2250738585072014 × 10−308 (가장 작은 양수 정규 숫자)
  0 11111111110 11111111111111111111111111111111111111111111111111112
≙ 7FEF FFFF FFFF FFFF16
≙ +21023 × (2 − 2−52)
≈ 1.7976931348623157 × 10308 (가장 큰 정규 숫자)
  0 00000000000 00000000000000000000000000000000000000000000000000002
≙ 0000 0000 0000 000016
≙ +0 (양수 0)
  1 00000000000 00000000000000000000000000000000000000000000000000002
≙ 8000 0000 0000 000016
≙ −0 (음수 0)
  0 11111111111 00000000000000000000000000000000000000000000000000002
≙ 7FF0 0000 0000 000016
≙ +∞ (양수 무한)
  1 11111111111 00000000000000000000000000000000000000000000000000002
≙ FFF0 0000 0000 000016
≙ −∞ (음수 무한)
  0 11111111111 00000000000000000000000000000000000000000000000000012
≙ 7FF0 0000 0000 000116
≙ NaN (대부분의 프로세서, 예: x86 및 ARM에서 sNaN)
  0 11111111111 10000000000000000000000000000000000000000000000000012
≙ 7FF8 0000 0000 000116
≙ NaN (대부분의 프로세서, 예: x86 및 ARM에서 qNaN)
  0 11111111111 11111111111111111111111111111111111111111111111111112
≙ 7FFF FFFF FFFF FFFF16
≙ NaN (NaN의 대체 인코딩)
  0 01111111101 01010101010101010101010101010101010101010101010101012
≙ 3FD5 5555 5555 555516
≙ +2−2 × (1 + 2−2 + 2−4 + ... + 2−52)
≈ 0.33333333333333331483 (1/3에 가장 가까운 근사치)
  0 10000000000 10010010000111111011010101000100010000101101000110002
≙ 4009 21FB 5444 2D1816
≈ 3.141592653589793116 (π에 가장 가까운 근사치)

qNaN 및 sNaN의 인코딩IEEE 754에 완전히 명시되어 있지 않으며 프로세서에 따라 달라진다. X86 계열 및 ARM 계열 프로세서와 같은 대부분의 프로세서는 유효숫자 필드의 최상위 비트를 사용하여 quiet NaN을 나타낸다. 이는 IEEE 754에서 권장하는 방식이다. PA-RISC 프로세서는 이 비트를 사용하여 signaling NaN을 나타낸다.

기본적으로 1/3은 유효숫자의 홀수 비트 때문에 단정밀도처럼 올림이 아닌 내림으로 반올림된다.

더 자세히:

16진수 표현 3FD5 5555 5555 555516가 주어지면,
  부호 = 0
  지수 = 3FD16 = 1021
  지수 바이어스 = 1023 (상수 값; 위 참조)
  분수 = 5 5555 5555 555516
  값 = 2(지수 − 지수 바이어스) × 1.분수 – 여기서 분수는 십진수로 변환해서는 안 된다
        = 2−2 × (15 5555 5555 555516 × 2−52)
        = 2−54 × 15 5555 5555 555516
        = 0.333333333333333314829616256247390992939472198486328125
        ≈ 1/3

배정밀도 연산의 실행 속도

[편집]

배정밀도 부동소수점 변수를 사용하는 것은 일반적으로 단정밀도 변수를 사용하는 것보다 느리다. 이 문제가 특히 중요한 컴퓨팅 영역 중 하나는 GPU에서 실행되는 병렬 코드이다. 예를 들어, 엔비디아CUDA 플랫폼을 사용할 때 배정밀도 계산은 하드웨어에 따라 단정밀도를 사용한 계산에 비해 완료하는 데 2배에서 32배까지 더 오래 걸릴 수 있다.[2]

또한, 많은 수학 함수 (예: sin, cos, atan2, log, exp 및 sqrt)는 정확한 배정밀도 결과를 제공하기 위해 더 많은 계산이 필요하므로 느리다.

정수 값에 대한 정밀도 제한

[편집]
  • −253에서 253 (−9,007,199,254,740,992에서 9,007,199,254,740,992)까지의 정수는 정확히 표현될 수 있다.
  • 253에서 254 = 18,014,398,509,481,984 사이의 정수는 2의 배수로 반올림된다 (짝수).
  • 254에서 255 = 36,028,797,018,963,968 사이의 정수는 4의 배수로 반올림된다.
  • 2n에서 2n+1 사이의 정수는 2n−52의 배수로 반올림된다.

구현

[편집]

Double은 다음과 같이 다양한 방식으로 많은 프로그래밍 언어에서 구현된다. SSE2 없이 (또는 호환성을 위해 SSE2를 사용하지 않을 때) X86과 같이 동적 정밀도만 있는 프로세서에서 확장 정밀도가 기본적으로 사용될 때, 소프트웨어는 일부 요구 사항을 충족하는 데 어려움을 겪을 수 있다.

C 및 C++

[편집]

C 및 C++는 다양한 산술 자료형을 제공한다. 배정밀도는 표준에서 요구되지 않지만 (IEEE 754 산술을 다루는 C99의 선택적 부록 F 제외), 대부분의 시스템에서 double 형식은 배정밀도에 해당한다. 그러나 기본적으로 확장 정밀도를 사용하는 32비트 x86에서는 일부 컴파일러가 C 표준을 따르지 않거나 산술이 이중 반올림으로 인해 문제가 발생할 수 있다.[3]

포트란

[편집]

포트란은 여러 정수 및 실수 형식을 제공하며, 포트란의 내장 모듈 iso_fortran_env를 통해 접근 가능한 64비트 형식 real64는 배정밀도에 해당한다.

커먼 리스프

[편집]

커먼 리스프는 SHORT-FLOAT, SINGLE-FLOAT, DOUBLE-FLOAT 및 LONG-FLOAT 유형을 제공한다. 대부분의 구현은 SINGLE-FLOAT 및 DOUBLE-FLOAT를 제공하며 다른 유형은 적절한 동의어로 사용된다. 커먼 리스프는 IEEE 754에 따라 부동소수점 언더플로우 및 오버플로우와 부정확한 부동소수점 예외를 포착하기 위한 예외를 제공한다. ANSI 표준에는 무한대와 NaN이 명시되어 있지 않지만, 여러 구현에서 이를 확장으로 제공한다.

자바

[편집]

버전 1.2 이전의 자바에서는 모든 구현이 IEEE 754를 준수해야 했다. 버전 1.2에서는 x87과 같은 플랫폼을 위해 중간 계산에서 추가 정밀도를 허용했다. 따라서 엄격한 IEEE 754 계산을 강제하기 위해 strictfp 수정자가 도입되었다. 엄격한 부동소수점은 Java 17에서 복원되었다.[4]

자바스크립트

[편집]

ECMA스크립트 표준에 명시된 바와 같이, 자바스크립트의 모든 산술은 배정밀도 부동소수점 산술을 사용하여 수행되어야 한다.[5]

JSON

[편집]

JSON 데이터 인코딩 형식은 숫자 값을 지원하며, 숫자 표현이 준수해야 하는 문법에는 인코딩된 숫자의 정밀도나 범위에 제한이 없다. 그러나 RFC 8259는 IEEE 754 binary64 숫자가 널리 구현되어 있으므로, JSON을 처리하는 구현이 binary64가 제공하는 것 이상의 정밀도나 범위를 기대하지 않는다면 좋은 상호 운용성을 달성할 수 있다고 조언한다.[6]

러스트 및 Zig

[편집]

러스트Zigf64 자료형을 가지고 있다.[7][8]

각주

[편집]
  1. William Kahan (1997년 10월 1일). “Lecture Notes on the Status of IEEE Standard 754 for Binary Floating-Point Arithmetic” (PDF). 4쪽. 2012년 2월 8일에 원본 문서 (PDF)에서 보존된 문서. 
  2. “Nvidia's New Titan V Pushes 110 Teraflops From A Single Chip”. 《Tom's Hardware》 (영어). 2017년 12월 8일. 2018년 11월 5일에 확인함. 
  3. “Bug 323 – optimized code gives strange floating point results”. 《gcc.gnu.org》. 2018년 4월 30일에 원본 문서에서 보존된 문서. 2018년 4월 30일에 확인함. 
  4. Darcy, Joseph D. “JEP 306: Restore Always-Strict Floating-Point Semantics”. 2021년 9월 12일에 확인함. 
  5. 《ECMA-262 ECMAScript Language Specification》 (PDF) 5판. Ecma International. p. 29, §8.5 The Number Type. 2012년 3월 13일에 원본 문서 (PDF)에서 보존된 문서. 
  6. Bray, Tim (December 2017). “The JavaScript Object Notation (JSON) Data Interchange Format”. Internet Engineering Task Force. 2022년 2월 1일에 확인함. 
  7. “Data Types - The Rust Programming Language”. 《doc.rust-lang.org》. 2024년 8월 10일에 확인함. 
  8. “Documentation - The Zig Programming Language”. 《ziglang.org》. 2024년 8월 10일에 확인함.