본문으로 건너뛰기
최종 수정: 에

부동소수점 타입(FLOAT 및 DOUBLE)

설명​

Doris는 FLOAT와 DOUBLE이라는 두 가지 부동소수점 데이터 타입을 제공합니다. 이들은 IEEE 754 부동소수점 연산 표준을 따르는 가변 정밀도 숫자 타입입니다.

타입별칭저장 크기설명
FLOATFLOAT4, REAL4바이트단정밀도 부동소수점
DOUBLEFLOAT8, DOUBLE PRECISION8바이트배정밀도 부동소수점

값 범위​

FLOAT​

Doris는 IEEE-754 단정밀도 부동소수점 수를 사용하며, 값 범위는 다음과 같습니다.

  • -∞ (-Infinity)
  • [-3.402E+38, -1.175E-37]
  • 0
  • [1.175E-37, 3.402E+38]
  • +∞ (+Infinity)
  • NaN (숫자가 아님)

자세한 내용은 C++ float 타입과 Wikipedia의 단정밀도 부동소수점 형식을 참조하세요.

DOUBLE​

Doris는 IEEE-754 배정밀도 부동소수점 수를 사용하며, 값 범위는 다음과 같습니다.

  • -∞ (-Infinity)
  • [-1.79769E+308, -2.225E-307]
  • 0
  • [+2.225E-307, +1.79769E+308]
  • +∞ (+Infinity)
  • NaN (숫자가 아님)

자세한 내용은 C++ double 타입과 Wikipedia의 배정밀도 부동소수점 형식을 참조하세요.

특수 값​

부동소수점 타입에는 일반적인 숫자 값 외에도 IEEE 754 표준을 따르는 몇 가지 특수 값이 있습니다.

  • Infinity 또는 Inf: 양의 무한대
  • -Infinity 또는 -Inf: 음의 무한대
  • NaN: 숫자가 아님

이러한 특수 값은 CAST 변환으로 생성할 수 있습니다.

mysql> select cast('NaN' as double), cast('inf' as double), cast('-Infinity' as double);
+-----------------------+-----------------------+-----------------------------+
| cast('NaN' as double) | cast('inf' as double) | cast('-Infinity' as double) |
+-----------------------+-----------------------+-----------------------------+
| NaN | Infinity | -Infinity |
+-----------------------+-----------------------+-----------------------------+

부동소수점 수에는 직관적이지 않은 특성도 있습니다. 영을 나타내는 서로 다른 두 값인 +0과 -0이 존재합니다. 대부분의 상황에서는 같은 값으로 간주하지만, 부호 비트는 서로 다릅니다.

mysql> select cast('+0.0' as double), cast('-0.0' as double);
+------------------------+------------------------+
| cast('+0.0' as double) | cast('-0.0' as double) |
+------------------------+------------------------+
| 0 | -0 |
+------------------------+------------------------+

부동소수점 연산​

산술 연산​

Doris의 부동소수점 수는 덧셈, 뺄셈, 곱셈, 나눗셈과 같은 일반적인 산술 연산을 지원합니다.

Doris는 부동소수점 수를 0으로 나누는 경우 IEEE 754 표준을 완전히 따르지 않는다는 점에 유의해야 합니다.

이 경우 Doris는 PostgreSQL의 구현 방식을 따르며, 0으로 나눌 때 특수 값을 생성하는 대신 SQL NULL을 반환합니다.

표현식PostgreSQLIEEE 754Doris
1.0 / 0.0ErrorInfinityNULL
0.0 / 0.0ErrorNaNNULL
-1.0 / 0.0Error-InfinityNULL
'Infinity' / 'Infinity'NaNNaNNaN
1.0 / 'Infinity'0.00.00
'Infinity' - 'Infinity'NaNNaNNaN
'Infinity' - 1.0InfinityInfinityInfinity

비교 연산​

IEEE 표준에서 정의하는 부동소수점 비교는 일반적인 정수 비교와 몇 가지 중요한 차이가 있습니다. 예를 들어 음의 영과 양의 영은 같은 값으로 간주하며, NaN은 자기 자신을 포함한 어떤 값과도 같지 않습니다. 모든 유한한 부동소수점 수는 +∞보다 작고 -∞보다 큽니다.

Doris는 결과의 일관성과 예측 가능성을 보장하기 위해 NaN을 IEEE 표준과 다르게 처리합니다. Doris에서는 NaN을 Infinity를 포함한 다른 모든 값보다 큰 값으로 간주하며, NaN은 NaN과 같습니다.

mysql> select * from sort_float order by d;
+------+-----------+
| id | d |
+------+-----------+
| 5 | -Infinity |
| 2 | -123 |
| 1 | 123 |
| 4 | Infinity |
| 8 | NaN |
| 9 | NaN |
+------+-----------+

mysql> select
cast('Nan' as double) = cast('Nan' as double) ,
cast('Nan' as double) > cast('Inf' as double) ,
cast('Nan' as double) > cast('123456.789' as double);
+-----------------------------------------------+-----------------------------------------------+------------------------------------------------------+
| cast('Nan' as double) = cast('Nan' as double) | cast('Nan' as double) > cast('Inf' as double) | cast('Nan' as double) > cast('123456.789' as double) |
+-----------------------------------------------+-----------------------------------------------+------------------------------------------------------+
| 1 | 1 | 1 |
+-----------------------------------------------+-----------------------------------------------+------------------------------------------------------+

부동소수점 정밀도 문제​

근삿값과 정밀도 손실​

부동소수점 수는 본질적으로 값을 근사하여 표현합니다. 따라서 일부 십진수 값은 부동소수점 수의 이진 표현으로 정확하게 저장할 수 없으며, 대신 근삿값으로 저장됩니다. 이로 인해 저장하고 읽어 오는 과정에서 미세한 차이가 발생할 수 있습니다.

예를 들면 다음과 같습니다.

mysql> SELECT CAST(1.3 AS FLOAT) - CAST(0.7 AS FLOAT) = CAST(0.6 AS FLOAT);
+--------------------------------------------------------------+
| CAST(1.3 AS FLOAT) - CAST(0.7 AS FLOAT) = CAST(0.6 AS FLOAT) |
+--------------------------------------------------------------+
| 0 |
+--------------------------------------------------------------+

부동소수점 표현 오차로 인해 이 표현식의 평가 결과는 예상과 달리 TRUE가 아닐 수 있습니다.

결합법칙을 따르지 않는 연산​

부동소수점 연산은 정밀도에 한계가 있으므로 이론적인 수학 연산과 다른 계산 특성을 보입니다. 부동소수점 덧셈과 곱셈은 결합법칙과 분배법칙을 엄밀하게 따르지 않습니다.

따라서 계산 순서가 다르면 결과도 조금씩 달라질 수 있습니다. Doris는 MPP 아키텍처를 사용하므로 정확한 데이터 처리 순서를 보장할 수 없습니다. 이 때문에 입력 데이터가 같더라도 부동소수점 수를 사용하는 계산은 실행할 때마다 결과가 조금씩 달라질 수 있습니다.

집계 함수​

부동소수점 값에 집계 함수를 적용하면 오차가 누적될 수 있으며, 특히 대규모 데이터셋을 처리할 때 이러한 문제가 발생하기 쉽습니다. 데이터에 매우 크거나 작은 값이 포함되어 있으면 오차가 더욱 커질 수 있습니다. 계산 순서가 정해져 있지 않으므로, 데이터에 극단적인 값이 포함된 경우 같은 집계 함수를 여러 번 실행해도 결과가 달라질 수 있습니다.

JOIN 연산​

집계 함수와 마찬가지로 부동소수점 컬럼을 기준으로 테이블 JOIN을 수행하는 것은 권장하지 않습니다. 부동소수점 수의 정밀도 문제로 인해 이론적으로 같은 두 값도 내부 표현이 조금씩 다를 수 있으며, 이 때문에 일치하는 값으로 처리되지 않을 수 있습니다.

부동소수점 출력​

4.1.4부터 Doris는 부동소수점 수를 문자열로 변환할 때 값을 손실 없이 왕복 변환할 수 있는 가장 짧은 문자열을 출력합니다. 이 문자열을 다시 FLOAT / DOUBLE로 파싱하면 원래 값과 정확히 같은 이진 값이 생성되며, 불필요한 자릿수는 출력하지 않습니다.

출력 형식 규칙은 다음과 같습니다.

  • 십진 지수가 [-4, 16) 범위에 있으면 고정소수점 표기법을 사용합니다.
  • 그 외에는 과학적 표기법을 사용합니다. 소문자 e와 명시적인 부호를 사용하고 지수를 최소 두 자리로 표시합니다. 예: 1.23456e-05.
  • 양의 영과 음의 영은 구분해서 출력합니다(0 및 -0).
  • NaN, Infinity, -Infinity는 기존 표기를 유지합니다.
mysql> select cast('0.000123456' as double), cast('0.0000123456' as double);
+-------------------------------+--------------------------------+
| cast('0.000123456' as double) | cast('0.0000123456' as double) |
+-------------------------------+--------------------------------+
| 0.000123456 | 1.23456e-05 |
+-------------------------------+--------------------------------+
동작 변경 (4.1.4)

4.1.4 이전 버전에서는 고정된 수의 유효 자릿수(FLOAT는 약 7자리, DOUBLE은 약 16자리)를 출력했으므로, 출력된 문자열을 다시 파싱해도 항상 원래 값으로 복원되지는 않았습니다. 가장 짧은 왕복 변환 표현으로 전환한 이후에도 저장된 값은 바뀌지 않으며, 텍스트 표현만 달라질 수 있습니다. 예를 들면 다음과 같습니다.

4.1.4 이전4.1.4 이상
246.9120025634766246.91200256347656
15241.3842524765615241.384252476564
11.1110756131770711.111075613177073
일부 텍스트 출력에서 DOUBLE 값 2.0을 2.0으로 출력2로 출력
0.00001234561.23456e-05

이 변경은 다양한 출력 경로에 영향을 줍니다. 여기에는 MySQL 프로토콜 쿼리 결과, CAST(... AS STRING), ARRAY / MAP / STRUCT 요소 표시, JSON / VARIANT 표시, CSV / Parquet / ORC 형식의 SELECT INTO OUTFILE 텍스트 출력, EXPORT, Stream Load 반환값, 외부 테이블(Hive / Iceberg / Paimon / JDBC / ES / TVF)의 부동소수점 컬럼이 포함됩니다.

다운스트림 시스템에서 부동소수점 수의 문자열 표현이 정확히 일치하는지 비교하는 경우(예: 내보낸 파일을 비교할 때), 업그레이드 후 이 변경에 맞게 조정하세요.

권장 사항​

  1. 적절한 데이터 타입 선택: 재무 계산이나 정확한 숫자 값이 필요한 경우에는 부동소수점 타입 대신 DECIMAL 타입을 사용하세요.

  2. 동등 비교 시 주의: 두 부동소수점 값이 같은지 직접 비교하는 것은 피하세요. 특히 JOIN 연산에서 주의해야 합니다.

  3. 문자열 변환 시 주의: 부동소수점 수를 문자열로 변환한 뒤 다시 원래 타입으로 변환하면 정밀도가 추가로 손실될 수 있습니다.

  4. 플랫폼 간 차이 이해: 데이터베이스 시스템마다 부동소수점 연산을 처리하는 방식에 미묘한 차이가 있을 수 있습니다. 특히 NaN과 Infinity 같은 특수한 경우를 처리할 때 차이가 나타날 수 있습니다(대부분의 데이터베이스 시스템은 대체로 IEEE 표준을 따릅니다).

  5. 표시에 맞게 결과 반올림: 부동소수점 계산 결과를 표시할 때는 사용자가 겪는 정밀도 문제를 줄일 수 있도록 적절한 반올림을 고려하세요.

키워드​

FLOAT, FLOAT4, REAL, DOUBLE, DOUBLE PRECISION, FLOAT8, 부동소수점