mbutrovich opened a new issue, #11605:
URL: https://github.com/apache/arrow-rs/issues/11605
### Describe the bug
`multiply_fixed_point`, `multiply_fixed_point_checked` and
`multiply_fixed_point_dyn` round the product with the divisor
`10^(product_scale - required_scale)`. When that exponent is 77 or more, the
divisor does not fit in `i256` and wraps, and the results are wrong: a zero
product gives 1. When the exponent is above 127, computing it overflows `i8`,
which panics in debug builds. I did not check what a release build returns.
### To Reproduce
```rust
use arrow_arith::arithmetic::{multiply_fixed_point,
multiply_fixed_point_checked};
use arrow_array::Decimal128Array;
fn dec(v: Vec<i128>, p: u8, s: i8) -> Decimal128Array {
Decimal128Array::from(v).with_precision_and_scale(p, s).unwrap()
}
fn main() {
// Product scale 0, required scale -77
let a = dec(vec![0, 5, 5], 1, 0);
let b = dec(vec![0, 5, -5], 1, 0);
let r = multiply_fixed_point(&a, &b, -77).unwrap();
println!("{:?}", r.values()); // [1, 1, -1]
let r = multiply_fixed_point_checked(&a, &b, -77).unwrap();
println!("{:?}", r.values()); // [1, 1, -1]
// Product scale 38, required scale -90
let z = dec(vec![0], 1, 0);
let c = dec(vec![0], 38, 38);
let _ = multiply_fixed_point(&z, &c, -90);
// debug build: panics with "attempt to subtract with overflow"
}
```
### Expected behavior
`[0, 0, 0]` for both calls in the first case, because no product of two
`i128` values reaches `10^77 / 2`, so every product rounds to 0 at that scale.
Alternatively an error, as the
[docs](https://github.com/apache/arrow-rs/blob/dd240116c75a15a2a048a041c808d67f3f32a375/arrow-arith/src/arithmetic.rs#L130-L144)
specify for a required scale above the product scale. They do not restrict how
far below it the required scale can be, and `Decimal128(p, -77)` passes
`validate_decimal_precision_and_scale`.
### Additional context
[`get_fixed_point_info`](https://github.com/apache/arrow-rs/blob/dd240116c75a15a2a048a041c808d67f3f32a375/arrow-arith/src/arithmetic.rs#L35-L52)
computes `product_scale - required_scale` in `i8` and the divisor with
`i256::pow_wrapping`. `10^77` wraps to a negative `i256`, so `half` in
[`divide_and_round`](https://github.com/apache/arrow-rs/blob/dd240116c75a15a2a048a041c808d67f3f32a375/arrow-arith/src/arithmetic.rs#L174-L188)
is negative and every non-negative remainder rounds up. Should exponents above
76 return zeros, or an error?
Found with property-based tests that build arrays in every physical layout
the Arrow format allows, on `main` at `72887ed9`. The code is unchanged on
`main` at `dd240116`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]