mbutrovich opened a new issue, #12004: URL: https://github.com/apache/arrow-rs/issues/12004
**Describe the bug** `interval_mul_f64` adapts DuckDB's `INTERVAL * DOUBLE` (#10409). It computes the seconds remainder from `days_product.fract() + month_remainder.fract()` ([numeric.rs](https://github.com/apache/arrow-rs/blob/9ffd63d528e924d9c0faceef0027e3766b615c98/arrow-arith/src/numeric.rs#L793-L794)). DuckDB computes it from `left.days * right - result.days + month_remainder - day_remainder` ([multiply.cpp](https://github.com/duckdb/duckdb/blob/21aca0424f1faf78b593b1e6fbfdd4846624c987/src/function/scalar/operator/multiply.cpp#L85)), the same order as PostgreSQL's `interval_mul`. Floating-point addition is not associative, so the two can round differently, and the nanoseconds can differ in the last place. The order changed during review. The revision of #10409 under https://github.com/apache/arrow-rs/pull/10409#discussion_r3705124717 used DuckDB's order, and that suggestion replaced it with `fract()`. `fract()` is exact for the month remainder, because `months_product - trunc(months_product)` has no rounding error, but for the seconds remainder it reassociates the sum. **To Reproduce** On `main` at 9ffd63d528: ```rust use arrow::array::{AsArray, Float64Array, IntervalMonthDayNanoArray}; use arrow::compute::kernels::numeric::mul; use arrow::datatypes::{IntervalMonthDayNano, IntervalMonthDayNanoType}; let iv = IntervalMonthDayNanoArray::from(vec![IntervalMonthDayNano::new(1, 1, 0)]); let out = mul(&iv, &Float64Array::from(vec![32.0 / 7.0])).unwrap(); let v = out.as_primitive::<IntervalMonthDayNanoType>().value(0); // 4 months, 21 days, 61714285726629 ns assert_eq!((v.months, v.days, v.nanoseconds), (4, 21, 61_714_285_726_629)); ``` DuckDB's order of operations, at nanosecond precision, gives 61714285726628 ns. Both are about 12 us from the exact 61714285714285.7 ns, because the month remainder is rounded to 1e-9 of a day, so neither order is more accurate. Of the 212,160 products of 0 to 12 months and 0 to 31 days by a non-integral p/q (1 <= p <= 40, 2 <= q <= 16), 1,364 differ, each by 1 ns. Months and days are the same in all of them. With large nanosecond values, the difference is one unit in the last place of the final sum, which can be several ns. **Expected behavior** Should the seconds remainder use DuckDB's order again, so that results match DuckDB's at nanosecond precision? Or are differences from DuckDB in the last place acceptable, and should the comment on `interval_mul_f64` say so? cc @Jefffrey **Additional context** Found by a property test of interval multiplication and division. -- 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]
