@@ -38,10 +38,14 @@ where
3838
3939fn compute_min_max < ' a , T > ( iter : impl Iterator < Item = & ' a T > , dtype : & DType ) -> Option < MinMaxResult >
4040where
41- T : Into < ScalarValue > + NativePType + Copy ,
41+ T : Into < ScalarValue > + NativePType ,
4242{
43- // this `compare` function provides a total ordering (even for NaN values)
44- match iter. minmax_by ( |a, b| a. total_compare ( * * b) ) {
43+ // `total_compare` function provides a total ordering (even for NaN values).
44+ // However, we exclude NaNs from min max as they're not useful for any purpose where min/max would be used
45+ match iter
46+ . filter ( |v| !v. is_nan ( ) )
47+ . minmax_by ( |a, b| a. total_compare ( * * b) )
48+ {
4549 itertools:: MinMaxResult :: NoElements => None ,
4650 itertools:: MinMaxResult :: OneElement ( & x) => {
4751 let scalar = Scalar :: new ( dtype. clone ( ) , x. into ( ) ) ;
5660 } ) ,
5761 }
5862}
63+
64+ #[ cfg( test) ]
65+ mod tests {
66+ use vortex_buffer:: buffer;
67+
68+ use crate :: arrays:: PrimitiveArray ;
69+ use crate :: compute:: min_max;
70+ use crate :: validity:: Validity ;
71+
72+ #[ test]
73+ fn min_max_nan ( ) {
74+ let array = PrimitiveArray :: new (
75+ buffer ! [ f32 :: NAN , -f32 :: NAN , -1.0 , 1.0 ] ,
76+ Validity :: NonNullable ,
77+ ) ;
78+ let min_max = min_max ( & array) . unwrap ( ) . unwrap ( ) ;
79+ assert_eq ! ( f32 :: try_from( min_max. min) . unwrap( ) , -1.0 ) ;
80+ assert_eq ! ( f32 :: try_from( min_max. max) . unwrap( ) , 1.0 ) ;
81+ }
82+
83+ #[ test]
84+ fn min_max_inf ( ) {
85+ let array = PrimitiveArray :: new (
86+ buffer ! [ f32 :: INFINITY , f32 :: NEG_INFINITY , -1.0 , 1.0 ] ,
87+ Validity :: NonNullable ,
88+ ) ;
89+ let min_max = min_max ( & array) . unwrap ( ) . unwrap ( ) ;
90+ assert_eq ! ( f32 :: try_from( min_max. min) . unwrap( ) , f32 :: NEG_INFINITY ) ;
91+ assert_eq ! ( f32 :: try_from( min_max. max) . unwrap( ) , f32 :: INFINITY ) ;
92+ }
93+ }
0 commit comments