11// SPDX-License-Identifier: Apache-2.0
22// SPDX-FileCopyrightText: Copyright the Vortex contributors
33
4- use arrow_array:: ArrowNativeTypeOp ;
5- use num_traits:: { CheckedAdd , CheckedMul , ToPrimitive } ;
4+ use num_traits:: { CheckedAdd , CheckedMul } ;
65use vortex_dtype:: { DType , DecimalDType , NativePType , Nullability , i256, match_each_native_ptype} ;
76use vortex_error:: { VortexExpect , VortexResult , vortex_bail, vortex_err} ;
87use vortex_scalar:: { DecimalScalar , DecimalValue , PrimitiveScalar , Scalar , ScalarValue } ;
@@ -138,21 +137,20 @@ fn sum_float(
138137 array_len : usize ,
139138 accumulator : & Scalar ,
140139) -> VortexResult < Option < f64 > > {
141- let v = primitive_scalar
142- . as_ :: < f64 > ( )
143- . vortex_expect ( "cannot be null" ) ;
144- let array_len = array_len
145- . to_f64 ( )
146- . ok_or_else ( || vortex_err ! ( "array_len must fit the sum type" ) ) ?;
147-
148- let Ok ( array_sum) = v. mul_checked ( array_len) else {
149- return Ok ( None ) ;
150- } ;
151140 let initial = accumulator
152141 . as_primitive ( )
153142 . as_ :: < f64 > ( )
154143 . vortex_expect ( "cannot be null" ) ;
155- Ok ( Some ( initial + array_sum) )
144+ let v = primitive_scalar
145+ . as_ :: < f64 > ( )
146+ . vortex_expect ( "cannot be null" ) ;
147+
148+ // Preserve numerical behaviour of summation of floats by using a loop instead of simplifying to multiplication.
149+ let mut sum = initial;
150+ for _ in 0 ..array_len {
151+ sum += v;
152+ }
153+ Ok ( Some ( sum) )
156154}
157155
158156register_kernel ! ( SumKernelAdapter ( ConstantVTable ) . lift( ) ) ;
@@ -161,10 +159,11 @@ register_kernel!(SumKernelAdapter(ConstantVTable).lift());
161159mod tests {
162160 use vortex_dtype:: Nullability :: Nullable ;
163161 use vortex_dtype:: { DType , DecimalDType , Nullability , PType , i256} ;
162+ use vortex_error:: VortexUnwrap ;
164163 use vortex_scalar:: { DecimalValue , Scalar } ;
165164
166165 use crate :: arrays:: ConstantArray ;
167- use crate :: compute:: sum;
166+ use crate :: compute:: { sum, sum_with_accumulator } ;
168167 use crate :: stats:: Stat ;
169168 use crate :: { Array , IntoArray } ;
170169
@@ -269,4 +268,16 @@ mod tests {
269268 Some ( DecimalValue :: I256 ( i256:: from_i128( 99_999_999_900 ) ) )
270269 ) ;
271270 }
271+
272+ #[ test]
273+ fn test_sum_float_non_multiply ( ) {
274+ let acc = -2048669276050936500000000000f64 ;
275+ let array = ConstantArray :: new ( 6.1811675e16f64 , 25 ) ;
276+ let sum =
277+ sum_with_accumulator ( array. as_ref ( ) , & Scalar :: primitive ( acc, Nullable ) ) . vortex_unwrap ( ) ;
278+ assert_eq ! (
279+ sum,
280+ Scalar :: primitive( -2048669274505641600000000000f64 , Nullable )
281+ ) ;
282+ }
272283}
0 commit comments