polars_core/chunked_array/arithmetic/
decimal.rs1use polars_compute::decimal::{
2 DEC128_MAX_PREC, dec128_add, dec128_div, dec128_mul, dec128_rescale, dec128_sub,
3};
4
5use super::*;
6use crate::prelude::arity::broadcast_try_binary_elementwise;
7
8impl Add for &DecimalChunked {
9 type Output = PolarsResult<DecimalChunked>;
10
11 fn add(self, rhs: Self) -> Self::Output {
12 let left_s = self.scale();
13 let right_s = rhs.scale();
14 let scale = left_s.max(right_s);
15 let prec = DEC128_MAX_PREC;
16 let phys = broadcast_try_binary_elementwise(
17 self.physical(),
18 rhs.physical(),
19 |opt_l, opt_r| {
20 let (Some(l), Some(r)) = (opt_l, opt_r) else {
21 return PolarsResult::Ok(None);
22 };
23 let ls = dec128_rescale(l, left_s, prec, scale).ok_or_else(|| {
24 polars_err!(ComputeError: "overflow in Decimal cast for {l} from scale {left_s} to {scale}")
25 })?;
26 let rs = dec128_rescale(r, right_s, prec, scale).ok_or_else(|| {
27 polars_err!(ComputeError: "overflow in Decimal cast for {r} from scale {right_s} to {scale}")
28 })?;
29 let ret = dec128_add(ls, rs, prec).ok_or_else(
30 || polars_err!(ComputeError: "overflow in decimal addition for {ls} + {rs}"),
31 )?;
32 Ok(Some(ret))
33 },
34 );
35 Ok(phys?.into_decimal_unchecked(prec, scale))
36 }
37}
38
39impl Sub for &DecimalChunked {
40 type Output = PolarsResult<DecimalChunked>;
41
42 fn sub(self, rhs: Self) -> Self::Output {
43 let left_s = self.scale();
44 let right_s = rhs.scale();
45 let scale = left_s.max(right_s);
46 let prec = DEC128_MAX_PREC;
47 let phys = broadcast_try_binary_elementwise(
48 self.physical(),
49 rhs.physical(),
50 |opt_l, opt_r| {
51 let (Some(l), Some(r)) = (opt_l, opt_r) else {
52 return PolarsResult::Ok(None);
53 };
54 let ls = dec128_rescale(l, left_s, prec, scale).ok_or_else(|| {
55 polars_err!(ComputeError: "overflow in Decimal cast for {l} from scale {left_s} to {scale}")
56 })?;
57 let rs = dec128_rescale(r, right_s, prec, scale).ok_or_else(|| {
58 polars_err!(ComputeError: "overflow in Decimal cast for {r} from scale {right_s} to {scale}")
59 })?;
60 let ret = dec128_sub(ls, rs, prec).ok_or_else(
61 || polars_err!(ComputeError: "overflow in decimal subtraction for {ls} - {rs}"),
62 )?;
63 Ok(Some(ret))
64 },
65 );
66 Ok(phys?.into_decimal_unchecked(prec, scale))
67 }
68}
69
70impl Mul for &DecimalChunked {
71 type Output = PolarsResult<DecimalChunked>;
72
73 fn mul(self, rhs: Self) -> Self::Output {
74 let left_s = self.scale();
75 let right_s = rhs.scale();
76 let scale = left_s.max(right_s);
77 let prec = DEC128_MAX_PREC;
78 let phys = broadcast_try_binary_elementwise(
79 self.physical(),
80 rhs.physical(),
81 |opt_l, opt_r| {
82 let (Some(l), Some(r)) = (opt_l, opt_r) else {
83 return PolarsResult::Ok(None);
84 };
85 let ls = dec128_rescale(l, left_s, prec, scale).ok_or_else(|| {
86 polars_err!(ComputeError: "overflow in Decimal cast for {l} from scale {left_s} to {scale}")
87 })?;
88 let rs = dec128_rescale(r, right_s, prec, scale).ok_or_else(|| {
89 polars_err!(ComputeError: "overflow in Decimal cast for {r} from scale {right_s} to {scale}")
90 })?;
91 let ret = dec128_mul(ls, rs, prec, scale).ok_or_else(|| {
92 polars_err!(ComputeError: "overflow in decimal multiplication for {ls} * {rs}")
93 })?;
94 Ok(Some(ret))
95 },
96 );
97 Ok(phys?.into_decimal_unchecked(prec, scale))
98 }
99}
100
101impl Div for &DecimalChunked {
102 type Output = PolarsResult<DecimalChunked>;
103
104 fn div(self, rhs: Self) -> Self::Output {
105 let left_s = self.scale();
106 let right_s = rhs.scale();
107 let scale = left_s.max(right_s);
108 let prec = DEC128_MAX_PREC;
109 let phys = broadcast_try_binary_elementwise(
110 self.physical(),
111 rhs.physical(),
112 |opt_l, opt_r| {
113 let (Some(l), Some(r)) = (opt_l, opt_r) else {
114 return PolarsResult::Ok(None);
115 };
116 if r == 0 {
117 polars_bail!(ComputeError: "division by zero Decimal");
118 }
119 let ls = dec128_rescale(l, left_s, prec, scale).ok_or_else(|| {
120 polars_err!(ComputeError: "overflow in Decimal cast for {l} from scale {left_s} to {scale}")
121 })?;
122 let rs = dec128_rescale(r, right_s, prec, scale).ok_or_else(|| {
123 polars_err!(ComputeError: "overflow in Decimal cast for {r} from scale {right_s} to {scale}")
124 })?;
125 let ret = dec128_div(ls, rs, prec, scale).ok_or_else(
126 || polars_err!(ComputeError: "overflow in decimal division for {ls} / {rs}"),
127 )?;
128 Ok(Some(ret))
129 },
130 );
131 Ok(phys?.into_decimal_unchecked(prec, scale))
132 }
133}