본문으로 바로가기
본문으로 바로가기

Decimal, Decimal(P), Decimal(P, S), Decimal32(S), Decimal64(S), Decimal128(S), Decimal256(S)

덧셈, 뺄셈, 곱셈 연산에서 정밀도가 유지되는 부호 있는 고정 소수점 수입니다. 나눗셈 연산에서는 가장 낮은 자릿수가 버려지며(반올림되지 않습니다).

Parameters

  • P - 정밀도(precision). 유효 범위: [ 1 : 76 ]. 소수 부분을 포함하여 숫자가 가질 수 있는 10진 자릿수의 개수를 결정합니다. 기본 정밀도는 10입니다.
  • S - 스케일(scale). 유효 범위: [ 0 : P ]. 소수 부분이 가질 수 있는 10진 자릿수의 개수를 결정합니다.

Decimal(P)은 Decimal(P, 0)과 동일합니다. 마찬가지로 Decimal 구문은 Decimal(10, 0)과 동일합니다.

P 매개변수 값에 따라 Decimal(P, S)는 다음과 같이 해석됩니다.

  • P가 [ 1 : 9 ] 범위일 때 - Decimal32(S)
  • P가 [ 10 : 18 ] 범위일 때 - Decimal64(S)
  • P가 [ 19 : 38 ] 범위일 때 - Decimal128(S)
  • P가 [ 39 : 76 ] 범위일 때 - Decimal256(S)

Decimal 값 범위

  • Decimal(P, S) - ( -1 * 10^(P - S), 1 * 10^(P - S) )
  • Decimal32(S) - ( -1 * 10^(9 - S), 1 * 10^(9 - S) )
  • Decimal64(S) - ( -1 * 10^(18 - S), 1 * 10^(18 - S) )
  • Decimal128(S) - ( -1 * 10^(38 - S), 1 * 10^(38 - S) )
  • Decimal256(S) - ( -1 * 10^(76 - S), 1 * 10^(76 - S) )

예를 들어 Decimal32(4)는 -99999.9999부터 99999.9999까지 0.0001 단위로 숫자를 저장할 수 있습니다.

내부 표현

내부적으로 데이터는 해당 비트 폭을 갖는 일반 부호 있는 정수로 표현됩니다. 메모리에 저장될 수 있는 실제 값 범위는 위에서 지정한 것보다 약간 더 크며, 문자열에서 변환할 때에만 검사됩니다.

최신 CPU는 128비트 및 256비트 정수를 직접 지원하지 않으므로, Decimal128 및 Decimal256에 대한 연산은 에뮬레이션됩니다. 따라서 Decimal128 및 Decimal256은 Decimal32/Decimal64보다 상당히 느리게 동작합니다.

연산과 결과 타입

Decimal에 대한 이항 연산은 (인자의 순서와 관계없이) 더 넓은 결과 타입을 생성합니다.

  • Decimal64(S1) <op> Decimal32(S2) -> Decimal64(S)
  • Decimal128(S1) <op> Decimal32(S2) -> Decimal128(S)
  • Decimal128(S1) <op> Decimal64(S2) -> Decimal128(S)
  • Decimal256(S1) <op> Decimal<32|64|128>(S2) -> Decimal256(S)

스케일(scale)에 대한 규칙:

  • 덧셈, 뺄셈: S = max(S1, S2).
  • 곱셈: S = S1 + S2.
  • 나눗셈: S = S1.

Decimal과 정수 사이의 유사한 연산에 대해서는, 결과가 인자와 동일한 크기의 Decimal이 됩니다.

Decimal과 Float32/Float64 사이의 연산은 정의되어 있지 않습니다. 해당 연산이 필요하면, 인자 중 하나를 toDecimal32, toDecimal64, toDecimal128 또는 toFloat32, toFloat64 내장 함수로 명시적으로 캐스팅해야 합니다. 이때 결과의 정밀도가 손실되며, 타입 변환은 계산 비용이 큰 연산이라는 점을 유의해야 합니다.

일부 Decimal용 함수는 결과를 Float64로 반환합니다(예: var 또는 stddev). 중간 계산은 여전히 Decimal에서 수행될 수 있으며, 동일한 값을 가진 Float64 입력과 Decimal 입력 사이에서 서로 다른 결과가 나올 수 있습니다.

오버플로우 검사

Decimal 형식으로 계산을 수행하는 동안 정수 오버플로우가 발생할 수 있습니다. 소수 부분에서 자릿수가 초과되면 초과된 자릿수는 버려지며(반올림되지 않음), 정수 부분에서 자릿수가 초과되면 예외가 발생합니다.

참고

Decimal128 및 Decimal256에 대해서는 오버플로우 검사가 구현되어 있지 않습니다. 오버플로우가 발생하는 경우 예외가 발생하지 않으며, 잘못된 결과가 반환됩니다.

SELECT toDecimal32(2, 4) AS x, x / 3
┌──────x─┬─divide(toDecimal32(2, 4), 3)─┐
│ 2.0000 │                       0.6666 │
└────────┴──────────────────────────────┘
SELECT toDecimal32(4.2, 8) AS x, x * x
DB::Exception: Scale is out of bounds.
SELECT toDecimal32(4.2, 8) AS x, 6 * x
DB::Exception: Decimal math overflow.

오버플로 검사는 연산 속도를 저하시킵니다. 오버플로가 발생하지 않는 것이 확실한 경우 decimal_check_overflow 설정을 사용하여 검사를 비활성화하는 것이 합리적입니다. 검사가 비활성화된 상태에서 오버플로가 발생하면 결과가 잘못됩니다:

SET decimal_check_overflow = 0;
SELECT toDecimal32(4.2, 8) AS x, 6 * x
┌──────────x─┬─multiply(6, toDecimal32(4.2, 8))─┐
│ 4.20000000 │                     -17.74967296 │
└────────────┴──────────────────────────────────┘

오버플로 검사는 산술 연산에서만 수행되는 것이 아니라 값 비교 시에도 수행됩니다:

SELECT toDecimal32(1, 8) < 100
DB::Exception: Can't compare.

함께 보기