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]

Reply via email to