common_decimal/
decimal128.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Display;
16use std::hash::Hash;
17use std::str::FromStr;
18
19use bigdecimal::{BigDecimal, ToPrimitive};
20use rust_decimal::Decimal as RustDecimal;
21use serde::{Deserialize, Serialize};
22use snafu::ResultExt;
23
24use crate::error::{
25    self, BigDecimalOutOfRangeSnafu, Error, InvalidPrecisionOrScaleSnafu, ParseBigDecimalStrSnafu,
26    ParseRustDecimalStrSnafu,
27};
28
29/// The maximum precision for [Decimal128] values
30pub const DECIMAL128_MAX_PRECISION: u8 = 38;
31
32/// The maximum scale for [Decimal128] values
33pub const DECIMAL128_MAX_SCALE: i8 = 38;
34
35/// The default scale for [Decimal128] values
36pub const DECIMAL128_DEFAULT_SCALE: i8 = 10;
37
38/// The maximum bytes length that an accurate RustDecimal can represent
39const BYTES_TO_OVERFLOW_RUST_DECIMAL: usize = 28;
40
41/// 128bit decimal, using the i128 to represent the decimal.
42///
43/// **precision**: the total number of digits in the number, it's range is \[1, 38\].
44///
45/// **scale**: the number of digits to the right of the decimal point, it's range is \[0, precision\].
46#[derive(Debug, Eq, Copy, Clone, Serialize, Deserialize)]
47pub struct Decimal128 {
48    value: i128,
49    precision: u8,
50    scale: i8,
51}
52
53impl Decimal128 {
54    /// Create a new Decimal128 from i128, precision and scale without any validation.
55    pub fn new(value: i128, precision: u8, scale: i8) -> Self {
56        // debug assert precision and scale is valid
57        debug_assert!(
58            precision > 0 && precision <= DECIMAL128_MAX_PRECISION,
59            "precision should be in [1, {}]",
60            DECIMAL128_MAX_PRECISION
61        );
62        debug_assert!(
63            scale >= 0 && scale <= precision as i8,
64            "scale should be in [0, precision]"
65        );
66        Self {
67            value,
68            precision,
69            scale,
70        }
71    }
72
73    /// Try new Decimal128 from i128, precision and scale with validation.
74    pub fn try_new(value: i128, precision: u8, scale: i8) -> error::Result<Self> {
75        // make sure the precision and scale is valid.
76        valid_precision_and_scale(precision, scale)?;
77        Ok(Self {
78            value,
79            precision,
80            scale,
81        })
82    }
83
84    /// Return underlying value without precision and scale
85    pub fn val(&self) -> i128 {
86        self.value
87    }
88
89    /// Returns the precision of this decimal.
90    pub fn precision(&self) -> u8 {
91        self.precision
92    }
93
94    /// Returns the scale of this decimal.
95    pub fn scale(&self) -> i8 {
96        self.scale
97    }
98
99    /// Convert to ScalarValue(value,precision,scale)
100    pub fn to_scalar_value(&self) -> (Option<i128>, u8, i8) {
101        (Some(self.value), self.precision, self.scale)
102    }
103
104    /// split the self.value(i128) to (high-64 bit, low-64 bit), and
105    /// the precision, scale information is discarded.
106    ///
107    /// Return: (high-64 bit, low-64 bit)
108    pub fn split_value(&self) -> (i64, i64) {
109        ((self.value >> 64) as i64, self.value as i64)
110    }
111
112    /// Convert from precision, scale, a i128 value which
113    /// represents by i64 + i64 value(high-64 bit, low-64 bit).
114    pub fn from_value_precision_scale(hi: i64, lo: i64, precision: u8, scale: i8) -> Self {
115        // 128                             64                              0
116        // +-------+-------+-------+-------+-------+-------+-------+-------+
117        // |               hi              |               lo              |
118        // +-------+-------+-------+-------+-------+-------+-------+-------+
119        let hi = (hi as u128 & u64::MAX as u128) << 64;
120        let lo = lo as u128 & u64::MAX as u128;
121        let value = (hi | lo) as i128;
122        Self::new(value, precision, scale)
123    }
124
125    pub fn negative(mut self) -> Self {
126        self.value = -self.value;
127        self
128    }
129}
130
131/// The default value of Decimal128 is 0, and its precision is 1 and scale is 0.
132impl Default for Decimal128 {
133    fn default() -> Self {
134        Self {
135            value: 0,
136            precision: 1,
137            scale: 0,
138        }
139    }
140}
141
142impl PartialEq for Decimal128 {
143    fn eq(&self, other: &Self) -> bool {
144        self.precision.eq(&other.precision)
145            && self.scale.eq(&other.scale)
146            && self.value.eq(&other.value)
147    }
148}
149
150// Two decimal values can be compared if they have the same precision and scale.
151impl PartialOrd for Decimal128 {
152    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
153        if self.precision == other.precision && self.scale == other.scale {
154            return self.value.partial_cmp(&other.value);
155        }
156        None
157    }
158}
159
160/// Convert from string to Decimal128
161/// If the string length is less than 28, the result of rust_decimal will underflow,
162/// In this case, use BigDecimal to get accurate result.
163impl FromStr for Decimal128 {
164    type Err = Error;
165
166    fn from_str(s: &str) -> Result<Self, Self::Err> {
167        let len = s.len();
168        if len <= BYTES_TO_OVERFLOW_RUST_DECIMAL {
169            let rd = RustDecimal::from_str_exact(s).context(ParseRustDecimalStrSnafu { raw: s })?;
170            Ok(Self::from(rd))
171        } else {
172            let bd = BigDecimal::from_str(s).context(ParseBigDecimalStrSnafu { raw: s })?;
173            Self::try_from(bd)
174        }
175    }
176}
177
178impl Display for Decimal128 {
179    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180        write!(
181            f,
182            "{}",
183            format_decimal_str(&self.value.to_string(), self.precision as usize, self.scale)
184        )
185    }
186}
187
188impl Hash for Decimal128 {
189    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
190        state.write_i128(self.value);
191        state.write_u8(self.precision);
192        state.write_i8(self.scale);
193    }
194}
195
196impl From<Decimal128> for serde_json::Value {
197    fn from(decimal: Decimal128) -> Self {
198        serde_json::Value::String(decimal.to_string())
199    }
200}
201
202impl From<Decimal128> for i128 {
203    fn from(decimal: Decimal128) -> Self {
204        decimal.val()
205    }
206}
207
208impl From<i128> for Decimal128 {
209    fn from(value: i128) -> Self {
210        Self {
211            value,
212            precision: DECIMAL128_MAX_PRECISION,
213            scale: DECIMAL128_DEFAULT_SCALE,
214        }
215    }
216}
217
218/// Convert from RustDecimal to Decimal128
219/// RustDecimal can represent the range is smaller than Decimal128,
220/// it is safe to convert RustDecimal to Decimal128
221impl From<RustDecimal> for Decimal128 {
222    fn from(rd: RustDecimal) -> Self {
223        let s = rd.to_string();
224        let precision = (s.len() - s.matches(&['.', '-'][..]).count()) as u8;
225        Self {
226            value: rd.mantissa(),
227            precision,
228            scale: rd.scale() as i8,
229        }
230    }
231}
232
233/// Try from BigDecimal to Decimal128
234/// The range that BigDecimal can represent is larger than Decimal128,
235/// so it is not safe to convert BigDecimal to Decimal128,
236/// If the BigDecimal is out of range, return error.
237impl TryFrom<BigDecimal> for Decimal128 {
238    type Error = Error;
239
240    fn try_from(value: BigDecimal) -> Result<Self, Self::Error> {
241        let precision = value.digits();
242        let (big_int, scale) = value.as_bigint_and_exponent();
243        // convert big_int to i128, if convert failed, return error
244        big_int
245            .to_i128()
246            .map(|val| Self::try_new(val, precision as u8, scale as i8))
247            .unwrap_or_else(|| BigDecimalOutOfRangeSnafu { value }.fail())
248    }
249}
250
251/// Port from arrow-rs,
252/// see https://github.com/Apache/arrow-rs/blob/master/arrow-array/src/types.rs#L1323-L1344
253fn format_decimal_str(value_str: &str, precision: usize, scale: i8) -> String {
254    let (sign, rest) = match value_str.strip_prefix('-') {
255        Some(stripped) => ("-", stripped),
256        None => ("", value_str),
257    };
258
259    let bound = precision.min(rest.len()) + sign.len();
260    let value_str = &value_str[0..bound];
261
262    if scale == 0 {
263        value_str.to_string()
264    } else if scale < 0 {
265        let padding = value_str.len() + scale.unsigned_abs() as usize;
266        format!("{value_str:0<padding$}")
267    } else if rest.len() > scale as usize {
268        // Decimal separator is in the middle of the string
269        let (whole, decimal) = value_str.split_at(value_str.len() - scale as usize);
270        format!("{whole}.{decimal}")
271    } else {
272        // String has to be padded
273        format!("{}0.{:0>width$}", sign, rest, width = scale as usize)
274    }
275}
276
277/// check whether precision and scale is valid
278fn valid_precision_and_scale(precision: u8, scale: i8) -> error::Result<()> {
279    if precision == 0 {
280        return InvalidPrecisionOrScaleSnafu {
281            reason: format!(
282                "precision cannot be 0, has to be between [1, {}]",
283                DECIMAL128_MAX_PRECISION
284            ),
285        }
286        .fail();
287    }
288    if precision > DECIMAL128_MAX_PRECISION {
289        return InvalidPrecisionOrScaleSnafu {
290            reason: format!(
291                "precision {} is greater than max {}",
292                precision, DECIMAL128_MAX_PRECISION
293            ),
294        }
295        .fail();
296    }
297    if scale > DECIMAL128_MAX_SCALE {
298        return InvalidPrecisionOrScaleSnafu {
299            reason: format!(
300                "scale {} is greater than max {}",
301                scale, DECIMAL128_MAX_SCALE
302            ),
303        }
304        .fail();
305    }
306    if scale > 0 && scale > precision as i8 {
307        return InvalidPrecisionOrScaleSnafu {
308            reason: format!("scale {} is greater than precision {}", scale, precision),
309        }
310        .fail();
311    }
312
313    Ok(())
314}
315
316#[cfg(test)]
317mod tests {
318    use super::*;
319
320    #[test]
321    fn test_common_decimal128() {
322        let decimal = Decimal128::new(123456789, 9, 3);
323        assert_eq!(decimal.to_string(), "123456.789");
324
325        let decimal = Decimal128::try_new(123456789, 9, 0);
326        assert_eq!(decimal.unwrap().to_string(), "123456789");
327
328        let decimal = Decimal128::try_new(123456789, 9, 2);
329        assert_eq!(decimal.unwrap().to_string(), "1234567.89");
330
331        let decimal = Decimal128::try_new(123, 3, -2);
332        assert_eq!(decimal.unwrap().to_string(), "12300");
333
334        // invalid precision or scale
335
336        // precision is 0
337        let decimal = Decimal128::try_new(123, 0, 0);
338        assert!(decimal.is_err());
339
340        // precision is greater than 38
341        let decimal = Decimal128::try_new(123, 39, 0);
342        assert!(decimal.is_err());
343
344        // scale is greater than 38
345        let decimal = Decimal128::try_new(123, 38, 39);
346        assert!(decimal.is_err());
347
348        // scale is greater than precision
349        let decimal = Decimal128::try_new(123, 3, 4);
350        assert!(decimal.is_err());
351    }
352
353    #[test]
354    fn test_decimal128_from_str() {
355        // 0 < precision <= 28
356        let decimal = Decimal128::from_str("1234567890.123456789").unwrap();
357        assert_eq!(decimal.to_string(), "1234567890.123456789");
358        assert_eq!(decimal.precision(), 19);
359        assert_eq!(decimal.scale(), 9);
360
361        let decimal = Decimal128::from_str("1234567890.123456789012345678").unwrap();
362        assert_eq!(decimal.to_string(), "1234567890.123456789012345678");
363        assert_eq!(decimal.precision(), 28);
364        assert_eq!(decimal.scale(), 18);
365
366        // 28 < precision <= 38
367        let decimal = Decimal128::from_str("1234567890.1234567890123456789012").unwrap();
368        assert_eq!(decimal.to_string(), "1234567890.1234567890123456789012");
369        assert_eq!(decimal.precision(), 32);
370        assert_eq!(decimal.scale(), 22);
371
372        let decimal = Decimal128::from_str("1234567890.1234567890123456789012345678").unwrap();
373        assert_eq!(
374            decimal.to_string(),
375            "1234567890.1234567890123456789012345678"
376        );
377        assert_eq!(decimal.precision(), 38);
378        assert_eq!(decimal.scale(), 28);
379
380        // precision > 38
381        let decimal = Decimal128::from_str("1234567890.12345678901234567890123456789");
382        assert!(decimal.is_err());
383    }
384
385    #[test]
386    #[ignore]
387    fn test_parse_decimal128_speed() {
388        // RustDecimal::from_str: 1.124855167s
389        for _ in 0..1500000 {
390            let _ = RustDecimal::from_str("1234567890.123456789012345678999").unwrap();
391        }
392
393        // BigDecimal::try_from: 6.799290042s
394        for _ in 0..1500000 {
395            let _ = BigDecimal::from_str("1234567890.123456789012345678999").unwrap();
396        }
397    }
398
399    #[test]
400    fn test_decimal128_precision_and_scale() {
401        // precision and scale from Deicmal(1,1) to Decimal(38,38)
402        for precision in 1..=38 {
403            for scale in 1..=precision {
404                let decimal_str = format!("0.{}", "1".repeat(scale as usize));
405                let decimal = Decimal128::from_str(&decimal_str).unwrap();
406                assert_eq!(decimal_str, decimal.to_string());
407            }
408        }
409    }
410
411    #[test]
412    fn test_decimal128_compare() {
413        // the same precision and scale
414        let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
415        let decimal2 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
416        assert!(decimal1 == decimal2);
417
418        let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
419        let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
420        assert!(decimal1 > decimal2);
421
422        let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
423        let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
424        assert!(decimal2 < decimal1);
425
426        let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
427        let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
428        assert!(decimal1 >= decimal2);
429
430        let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
431        let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
432        assert!(decimal2 <= decimal1);
433
434        let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
435        let decimal2 = Decimal128::from_str("1234567890.123456789012345678998").unwrap();
436        assert!(decimal1 != decimal2);
437
438        // different precision and scale cmp is None
439        let decimal1 = Decimal128::from_str("1234567890.123456789012345678999").unwrap();
440        let decimal2 = Decimal128::from_str("1234567890.123").unwrap();
441        assert_eq!(decimal1.partial_cmp(&decimal2), None);
442    }
443
444    #[test]
445    fn test_convert_with_i128() {
446        let test_decimal128_eq = |value| {
447            let decimal1 =
448                Decimal128::new(value, DECIMAL128_MAX_PRECISION, DECIMAL128_DEFAULT_SCALE);
449            let (hi, lo) = decimal1.split_value();
450            let decimal2 = Decimal128::from_value_precision_scale(
451                hi,
452                lo,
453                DECIMAL128_MAX_PRECISION,
454                DECIMAL128_DEFAULT_SCALE,
455            );
456            assert_eq!(decimal1, decimal2);
457        };
458
459        test_decimal128_eq(1 << 63);
460
461        test_decimal128_eq(0);
462        test_decimal128_eq(1234567890);
463        test_decimal128_eq(-1234567890);
464        test_decimal128_eq(32781372819372817382183218i128);
465        test_decimal128_eq(-32781372819372817382183218i128);
466        test_decimal128_eq(i128::MAX);
467        test_decimal128_eq(i128::MIN);
468    }
469}