@@ -271,7 +271,8 @@ pub fn identity_matrix<
271271/// # Returns
272272///
273273/// - Determinant of `data`.
274- /// - `0.0` when elimination detects a near-zero pivot (singular matrix).
274+ /// - `0.0` when elimination detects an exact zero pivot after pivoting
275+ /// (singular matrix).
275276fn determinant_gaussian_stack < const N : usize > ( mut data : [ [ f32 ; N ] ; N ] ) -> f32 {
276277 let mut sign = 1.0_f32 ;
277278 for pivot in 0 ..N {
@@ -285,7 +286,7 @@ fn determinant_gaussian_stack<const N: usize>(mut data: [[f32; N]; N]) -> f32 {
285286 }
286287 }
287288
288- if pivot_abs <= f32 :: EPSILON {
289+ if pivot_abs == 0.0 {
289290 return 0.0 ;
290291 }
291292
@@ -459,7 +460,7 @@ where
459460 }
460461 }
461462
462- if pivot_abs <= f32 :: EPSILON {
463+ if pivot_abs == 0.0 {
463464 return Ok ( 0.0 ) ;
464465 }
465466
@@ -571,6 +572,32 @@ mod tests {
571572 assert_eq ! ( m2. determinant( ) , Ok ( -306.0 ) ) ;
572573 }
573574
575+ #[ test]
576+ fn determinant_preserves_small_non_zero_pivot_in_stack_path ( ) {
577+ let m = [ [ 1.0e-8 , 0.0 , 0.0 ] , [ 0.0 , 2.0 , 0.0 ] , [ 0.0 , 0.0 , 3.0 ] ] ;
578+ crate :: assert_approximately_equal!(
579+ m. determinant( ) . expect( "determinant should succeed" ) ,
580+ 6.0e-8 ,
581+ 1.0e-12
582+ ) ;
583+ }
584+
585+ #[ test]
586+ fn determinant_preserves_small_non_zero_pivot_in_dynamic_path ( ) {
587+ let m = [
588+ [ 1.0e-8 , 0.0 , 0.0 , 0.0 , 0.0 ] ,
589+ [ 0.0 , 2.0 , 0.0 , 0.0 , 0.0 ] ,
590+ [ 0.0 , 0.0 , 3.0 , 0.0 , 0.0 ] ,
591+ [ 0.0 , 0.0 , 0.0 , 4.0 , 0.0 ] ,
592+ [ 0.0 , 0.0 , 0.0 , 0.0 , 5.0 ] ,
593+ ] ;
594+ crate :: assert_approximately_equal!(
595+ m. determinant( ) . expect( "determinant should succeed" ) ,
596+ 1.2e-6 ,
597+ 1.0e-10
598+ ) ;
599+ }
600+
574601 #[ test]
575602 fn non_square_matrix_determinant ( ) {
576603 let m = [ [ 3.0 , 8.0 ] , [ 4.0 , 6.0 ] , [ 0.0 , 1.0 ] ] ;
0 commit comments