1use crate::arity::*;
26use arrow_array::types::*;
27use arrow_array::*;
28use arrow_buffer::i256;
29use arrow_schema::*;
30use std::cmp::min;
31use std::sync::Arc;
32
33fn get_fixed_point_info(
36 left: (u8, i8),
37 right: (u8, i8),
38 required_scale: i8,
39) -> Result<(u8, i8, i256), ArrowError> {
40 let product_scale = left.1 + right.1;
41 let precision = min(left.0 + right.0 + 1, DECIMAL128_MAX_PRECISION);
42
43 if required_scale > product_scale {
44 return Err(ArrowError::ComputeError(format!(
45 "Required scale {required_scale} is greater than product scale {product_scale}",
46 )));
47 }
48
49 let divisor = i256::from_i128(10).pow_wrapping((product_scale - required_scale) as u32);
50
51 Ok((precision, product_scale, divisor))
52}
53
54pub fn multiply_fixed_point_dyn(
69 left: &dyn Array,
70 right: &dyn Array,
71 required_scale: i8,
72) -> Result<ArrayRef, ArrowError> {
73 match (left.data_type(), right.data_type()) {
74 (DataType::Decimal128(_, _), DataType::Decimal128(_, _)) => {
75 let left = left.as_any().downcast_ref::<Decimal128Array>().unwrap();
76 let right = right.as_any().downcast_ref::<Decimal128Array>().unwrap();
77
78 multiply_fixed_point(left, right, required_scale).map(|a| Arc::new(a) as ArrayRef)
79 }
80 (_, _) => Err(ArrowError::CastError(format!(
81 "Unsupported data type {}, {}",
82 left.data_type(),
83 right.data_type()
84 ))),
85 }
86}
87
88pub fn multiply_fixed_point_checked(
101 left: &PrimitiveArray<Decimal128Type>,
102 right: &PrimitiveArray<Decimal128Type>,
103 required_scale: i8,
104) -> Result<PrimitiveArray<Decimal128Type>, ArrowError> {
105 let (precision, product_scale, divisor) = get_fixed_point_info(
106 (left.precision(), left.scale()),
107 (right.precision(), right.scale()),
108 required_scale,
109 )?;
110
111 if required_scale == product_scale {
112 return try_binary::<_, _, _, Decimal128Type>(left, right, |a, b| a.mul_checked(b))?
113 .with_precision_and_scale(precision, required_scale);
114 }
115
116 let round = divide_and_round(divisor);
117 let product = try_binary::<_, _, _, Decimal128Type>(left, right, |a, b| {
118 let a = i256::from_i128(a);
119 let b = i256::from_i128(b);
120
121 let mut mul = a.wrapping_mul(b);
122 mul = round(mul);
123 mul.to_i128().ok_or_else(|| {
124 ArrowError::ArithmeticOverflow(format!("Overflow happened on: {a:?} * {b:?}"))
125 })
126 })?;
127 product.with_precision_and_scale(precision, required_scale)
128}
129
130pub fn multiply_fixed_point(
146 left: &PrimitiveArray<Decimal128Type>,
147 right: &PrimitiveArray<Decimal128Type>,
148 required_scale: i8,
149) -> Result<PrimitiveArray<Decimal128Type>, ArrowError> {
150 let (precision, product_scale, divisor) = get_fixed_point_info(
151 (left.precision(), left.scale()),
152 (right.precision(), right.scale()),
153 required_scale,
154 )?;
155
156 if required_scale == product_scale {
157 return binary(left, right, |a, b| a.mul_wrapping(b))?
158 .with_precision_and_scale(precision, required_scale);
159 }
160
161 let round = divide_and_round(divisor);
162 let product = binary::<_, _, _, Decimal128Type>(left, right, |a, b| {
163 let a = i256::from_i128(a);
164 let b = i256::from_i128(b);
165
166 let mut mul = a.wrapping_mul(b);
167 mul = round(mul);
168 mul.as_i128()
169 })?;
170 product.with_precision_and_scale(precision, required_scale)
171}
172
173fn divide_and_round(div: i256) -> impl Fn(i256) -> i256 {
175 let half = div.div_wrapping(i256::from_i128(2));
176 let half_neg = half.neg_wrapping();
177
178 move |input| {
179 let (d, r) = input.wrapping_div_rem(div);
180
181 match input >= i256::ZERO {
183 true if r >= half => d.add_wrapping(i256::ONE),
184 false if r <= half_neg => d.sub_wrapping(i256::ONE),
185 _ => d,
186 }
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193 use crate::numeric::mul;
194
195 #[test]
196 fn test_decimal_multiply_allow_precision_loss() {
197 let a = Decimal128Array::from(vec![123456789000000000000000000])
200 .with_precision_and_scale(38, 18)
201 .unwrap();
202
203 let b = Decimal128Array::from(vec![10000000000000000000])
205 .with_precision_and_scale(38, 18)
206 .unwrap();
207
208 let err = mul(&a, &b).unwrap_err();
209 assert!(
210 err.to_string().contains(
211 "Overflow happened on: 123456789000000000000000000 * 10000000000000000000"
212 )
213 );
214
215 let result = multiply_fixed_point_checked(&a, &b, 28).unwrap();
217 let expected = Decimal128Array::from(vec![12345678900000000000000000000000000000])
219 .with_precision_and_scale(38, 28)
220 .unwrap();
221
222 assert_eq!(&expected, &result);
223 assert_eq!(
224 result.value_as_string(0),
225 "1234567890.0000000000000000000000000000"
226 );
227
228 let a = Decimal128Array::from(vec![1, 123456789555555555555555555, 1555555555555555555])
231 .with_precision_and_scale(38, 18)
232 .unwrap();
233
234 let b = Decimal128Array::from(vec![1555555555555555555, 11222222222222222222, 1])
236 .with_precision_and_scale(38, 18)
237 .unwrap();
238
239 let result = multiply_fixed_point_checked(&a, &b, 28).unwrap();
240 let expected = Decimal128Array::from(vec![
246 15555555556,
247 13854595272345679012071330528765432099,
248 15555555556,
249 ])
250 .with_precision_and_scale(38, 28)
251 .unwrap();
252
253 assert_eq!(&expected, &result);
254
255 assert_eq!(
257 result.value_as_string(1),
258 "1385459527.2345679012071330528765432099"
259 );
260 assert_eq!(result.value_as_string(0), "0.0000000000000000015555555556");
261 assert_eq!(result.value_as_string(2), "0.0000000000000000015555555556");
262
263 let a = Decimal128Array::from(vec![1230])
264 .with_precision_and_scale(4, 2)
265 .unwrap();
266
267 let b = Decimal128Array::from(vec![1000])
268 .with_precision_and_scale(4, 2)
269 .unwrap();
270
271 let result = multiply_fixed_point_checked(&a, &b, 4).unwrap();
273 assert_eq!(result.precision(), 9);
274 assert_eq!(result.scale(), 4);
275
276 let expected = mul(&a, &b).unwrap();
277 assert_eq!(expected.as_ref(), &result);
278
279 let result = multiply_fixed_point_checked(&a, &b, 5).unwrap_err();
281 assert!(
282 result
283 .to_string()
284 .contains("Required scale 5 is greater than product scale 4")
285 );
286 }
287
288 #[test]
289 fn test_decimal_multiply_allow_precision_loss_overflow() {
290 let a = Decimal128Array::from(vec![99999999999123456789000000000000000000])
292 .with_precision_and_scale(38, 18)
293 .unwrap();
294
295 let b = Decimal128Array::from(vec![9999999999910000000000000000000])
297 .with_precision_and_scale(38, 18)
298 .unwrap();
299
300 let err = multiply_fixed_point_checked(&a, &b, 28).unwrap_err();
301 assert!(err.to_string().contains(
302 "Overflow happened on: 99999999999123456789000000000000000000 * 9999999999910000000000000000000"
303 ));
304
305 let result = multiply_fixed_point(&a, &b, 28).unwrap();
306 let expected = Decimal128Array::from(vec![62946009661555981610246871926660136960])
307 .with_precision_and_scale(38, 28)
308 .unwrap();
309
310 assert_eq!(&expected, &result);
311 }
312
313 #[test]
314 fn test_decimal_multiply_fixed_point() {
315 let a = Decimal128Array::from(vec![123456789000000000000000000])
317 .with_precision_and_scale(38, 18)
318 .unwrap();
319
320 let b = Decimal128Array::from(vec![10000000000000000000])
322 .with_precision_and_scale(38, 18)
323 .unwrap();
324
325 let err = mul(&a, &b).unwrap_err();
327 assert_eq!(
328 err.to_string(),
329 "Arithmetic overflow: Overflow happened on: 123456789000000000000000000 * 10000000000000000000"
330 );
331
332 let result = multiply_fixed_point(&a, &b, 28).unwrap();
334 let expected = Decimal128Array::from(vec![12345678900000000000000000000000000000])
336 .with_precision_and_scale(38, 28)
337 .unwrap();
338
339 assert_eq!(&expected, &result);
340 assert_eq!(
341 result.value_as_string(0),
342 "1234567890.0000000000000000000000000000"
343 );
344 }
345
346 #[test]
347 fn test_decimal_multiply_fixed_point_rounding() {
348 let a = Decimal128Array::from(vec![
350 Some(14),
351 Some(15),
352 Some(16),
353 Some(-14),
354 Some(-15),
355 Some(-16),
356 Some(25),
357 Some(-25),
358 None,
359 ])
360 .with_precision_and_scale(38, 1)
361 .unwrap();
362 let b = Decimal128Array::from(vec![1, 1, 1, 1, 1, 1, -1, -1, 1])
363 .with_precision_and_scale(38, 0)
364 .unwrap();
365 let expected = Decimal128Array::from(vec![
366 Some(1),
367 Some(2),
368 Some(2),
369 Some(-1),
370 Some(-2),
371 Some(-2),
372 Some(-3),
373 Some(3),
374 None,
375 ])
376 .with_precision_and_scale(38, 0)
377 .unwrap();
378
379 for (a, b, expected) in [
381 (a.clone(), b.clone(), expected.clone()),
382 (a.slice(0, 8), b.slice(0, 8), expected.slice(0, 8)),
383 ] {
384 assert_eq!(multiply_fixed_point(&a, &b, 0).unwrap(), expected);
385 assert_eq!(multiply_fixed_point_checked(&a, &b, 0).unwrap(), expected);
386 }
387 }
388}