@@ -990,7 +990,7 @@ trait RootSelector: Sized {
990990 . collect ( ) ;
991991 let mut factors_temp = Vec :: with_capacity ( factors. len ( ) ) ;
992992 loop {
993- let interval = self . get_interval ( ) ;
993+ let mut interval = self . get_interval ( ) ;
994994 let ( lower_bound, upper_bound) = interval. to_ratio_range ( ) ;
995995 mem:: swap ( & mut factors, & mut factors_temp) ;
996996 factors. clear ( ) ;
@@ -1019,10 +1019,94 @@ trait RootSelector: Sized {
10191019 }
10201020 }
10211021 if roots_left <= 1 {
1022- break RealAlgebraicNumber :: new_unchecked (
1023- factors. remove ( 0 ) . into_factor ( ) ,
1024- interval,
1025- ) ;
1022+ let factor = factors. remove ( 0 ) ;
1023+ if factor. factor ( ) . degree ( ) . is_some_and ( |deg| deg > 1 ) {
1024+ // Reduce the precision of the interval as much as possible to prevent the precision from exploding due to repeated computation
1025+ // Skip this step if the number is rational
1026+
1027+ let mut precomputed_lower_bound_sign_changes = None ;
1028+ let mut precomputed_upper_bound_sign_changes = None ;
1029+
1030+ while interval. log2_denom ( ) > 0 {
1031+ let trial_interval = interval
1032+ . clone ( )
1033+ . into_converted_log2_denom ( interval. log2_denom ( ) - 1 ) ;
1034+
1035+ let lower_bound_sign_changes = sign_changes_at (
1036+ & factor. primitive_sturm_sequence ,
1037+ ValueOrInfinity :: Value ( & trial_interval. lower_bound ( ) ) ,
1038+ ) ;
1039+ let upper_bound_sign_changes = sign_changes_at (
1040+ & factor. primitive_sturm_sequence ,
1041+ ValueOrInfinity :: Value ( & trial_interval. upper_bound ( ) ) ,
1042+ ) ;
1043+ // We don't need to check if the lower bound is a root because we know that the root is irrational
1044+ let num_roots = distance (
1045+ lower_bound_sign_changes. sign_change_count ,
1046+ upper_bound_sign_changes. sign_change_count ,
1047+ ) ;
1048+
1049+ assert ! ( num_roots > 0 ) ;
1050+
1051+ if num_roots == 1 {
1052+ interval = trial_interval;
1053+ precomputed_lower_bound_sign_changes = Some ( lower_bound_sign_changes) ;
1054+ precomputed_upper_bound_sign_changes = Some ( upper_bound_sign_changes) ;
1055+ } else {
1056+ break ;
1057+ }
1058+ }
1059+
1060+ // Tighten the range as much as possible to prevent that from exploding too
1061+
1062+ let lower_bound_sign_changes = precomputed_lower_bound_sign_changes
1063+ . unwrap_or_else ( || {
1064+ sign_changes_at (
1065+ & factor. primitive_sturm_sequence ,
1066+ ValueOrInfinity :: Value ( & interval. lower_bound ( ) ) ,
1067+ )
1068+ } ) ;
1069+ let upper_bound_sign_changes = precomputed_upper_bound_sign_changes
1070+ . unwrap_or_else ( || {
1071+ sign_changes_at (
1072+ & factor. primitive_sturm_sequence ,
1073+ ValueOrInfinity :: Value ( & interval. upper_bound ( ) ) ,
1074+ )
1075+ } ) ;
1076+
1077+ while interval. upper_bound_numer ( ) - interval. lower_bound_numer ( )
1078+ > BigInt :: from ( 1 )
1079+ {
1080+ let middle = ( interval. lower_bound_numer ( ) + interval. upper_bound_numer ( ) )
1081+ / BigInt :: from ( 2 ) ;
1082+
1083+ let middle_sign_changes = sign_changes_at (
1084+ & factor. primitive_sturm_sequence ,
1085+ ValueOrInfinity :: Value ( & Ratio :: new (
1086+ middle. clone ( ) ,
1087+ BigInt :: one ( ) << interval. log2_denom ( ) ,
1088+ ) ) ,
1089+ ) ;
1090+
1091+ if middle_sign_changes. sign_change_count
1092+ == lower_bound_sign_changes. sign_change_count
1093+ {
1094+ interval. set_lower_bound_numer ( middle) ;
1095+ } else {
1096+ assert_eq ! (
1097+ middle_sign_changes. sign_change_count,
1098+ upper_bound_sign_changes. sign_change_count
1099+ ) ;
1100+ interval. set_upper_bound_numer ( middle) ;
1101+ }
1102+ }
1103+ }
1104+
1105+ let v = RealAlgebraicNumber :: new_unchecked ( factor. into_factor ( ) , interval) ;
1106+ break match v. to_rational ( ) {
1107+ Some ( rational) => RealAlgebraicNumber :: from ( rational) ,
1108+ None => v,
1109+ } ;
10261110 }
10271111 self . shrink_interval ( ) ;
10281112 }
0 commit comments