덧셈, 뺄셈, 곱셈 연산에서 정밀도를 유지하는 부호 있는 고정소수점 수입니다. 나눗셈에서는 최하위 자릿수를 버리며(반올림하지 않음).
- P - 정밀도. 유효 범위: [ 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(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.
관련 항목