(
value: V,
input_scale: i8,
output_scale: i8,
decimal_places: i32,
)
| 643 | } |
| 644 | |
| 645 | fn round_decimal<V: ArrowNativeTypeOp>( |
| 646 | value: V, |
| 647 | input_scale: i8, |
| 648 | output_scale: i8, |
| 649 | decimal_places: i32, |
| 650 | ) -> Result<V, ArrowError> { |
| 651 | let diff = i64::from(input_scale) - i64::from(decimal_places); |
| 652 | if diff <= 0 { |
| 653 | return Ok(value); |
| 654 | } |
| 655 | |
| 656 | debug_assert!(diff <= i64::from(u32::MAX)); |
| 657 | let diff = diff as u32; |
| 658 | |
| 659 | let one = V::ONE; |
| 660 | let two = V::from_usize(2).ok_or_else(|| { |
| 661 | ArrowError::ComputeError("Internal error: could not create constant 2".into()) |
| 662 | })?; |
| 663 | let ten = V::from_usize(10).ok_or_else(|| { |
| 664 | ArrowError::ComputeError("Internal error: could not create constant 10".into()) |
| 665 | })?; |
| 666 | |
| 667 | let factor = ten.pow_checked(diff).map_err(|_| { |
| 668 | ArrowError::ComputeError(format!( |
| 669 | "Overflow while rounding decimal with scale {input_scale} and decimal places {decimal_places}" |
| 670 | )) |
| 671 | })?; |
| 672 | |
| 673 | let mut quotient = value.div_wrapping(factor); |
| 674 | let remainder = value.mod_wrapping(factor); |
| 675 | |
| 676 | // `factor` is an even number (10^n, n > 0), so `factor / 2` is the tie threshold |
| 677 | let threshold = factor.div_wrapping(two); |
| 678 | if remainder >= threshold { |
| 679 | quotient = quotient.add_checked(one).map_err(|_| { |
| 680 | ArrowError::ComputeError("Overflow while rounding decimal".into()) |
| 681 | })?; |
| 682 | } else if remainder <= threshold.neg_wrapping() { |
| 683 | quotient = quotient.sub_checked(one).map_err(|_| { |
| 684 | ArrowError::ComputeError("Overflow while rounding decimal".into()) |
| 685 | })?; |
| 686 | } |
| 687 | |
| 688 | // `quotient` is the rounded value at scale `decimal_places`. Rescale to the desired |
| 689 | // `output_scale` (which is always >= `decimal_places` in cases where diff > 0). |
| 690 | let scale_shift = i64::from(output_scale) - i64::from(decimal_places); |
| 691 | if scale_shift == 0 { |
| 692 | return Ok(quotient); |
| 693 | } |
| 694 | |
| 695 | debug_assert!(scale_shift > 0); |
| 696 | debug_assert!(scale_shift <= i64::from(u32::MAX)); |
| 697 | let scale_shift = scale_shift as u32; |
| 698 | let shift_factor = ten.pow_checked(scale_shift).map_err(|_| { |
| 699 | ArrowError::ComputeError(format!( |
| 700 | "Overflow while rounding decimal with scale {input_scale} and decimal places {decimal_places}" |
| 701 | )) |
| 702 | })?; |
no test coverage detected
searching dependent graphs…