Последний раз редактировалось wrest 29.06.2025, 13:00, всего редактировалось 2 раз(а).
Улучшил функцию, Фунция sqm(a,m) находит все решения n<m сравнения n^2 = a (mod m) включая составные модули в части поиска базовых решений для нечетных простых делителей модуля. DeepSeek там изначально устроил перебор решений, что для больших простых делителей модуля будет неэффективно. Сейчас перебор устранён использованием функции issquare() которая не только определяет есть ли решение, но если есть сразу и возвращает его. можно было бы воспользоваться функцией kronecker() для определения есть ли решение, но не знаю будет ли какой-то выигрыш по производительности. Думаю что функция теперь годная. Структурированный вид (отступы, комментарии) (Оффтоп)
- \\ v2 Написано wrest с помощью DeepSeek
- \\ Переделан поиск базовых решений для нечетных простых делителей.
- \\ Теперь вместо перебора используется встроенная функция
- \\ Это должно существенно ускорить работу при очень больших простых делителях модуля
- \\ Фунция sqm(a,m) находит все решения n<m сравнения n^2 = a mod m и работает для составных модулей
- \\ модуль факторизуется, затем отдельно обрабатываются степени двойки и степени нечетных простых.
- \\ Найденные корни для нечетных простых делителей поднимаются до соответстующих степеней
- \\ с использованием леммы Гензеля. Затем корни по простым делителям модуля объединяются с использованием КТО
- \\ китайской теоремы об остатках
- sqm(a, m) = {
- my(factors, solutions_list, mod_list, p, e, sols, solutions, new_solutions, crt_val, i, k, j, x0, x1, x2);
-
- \\ Специальные случаи
- if(m == 1, return([0]));
- if(a == 0, return([0]));
-
- factors = factor(m);
- if(#factors[,1] == 0, return([]));
-
- solutions_list = [];
- mod_list = [];
-
- for(i = 1, #factors[,1],
- p = factors[i,1];
- e = factors[i,2];
- sols = [];
-
- if(p == 2,
- \\ Решение для 2^1
- if(e == 1,
- if(a%2 == 0, sols = [0])
- ,
- \\ Решение для 2^2
- if(e == 2,
- if(a%4 == 0, sols = [0, 2]);
- if(a%4 == 1, sols = [1, 3])
- ,
- \\ Решение для 2^k, k>=3
- \\ Рекурсивный поиск решений
- my(x0 = [], x0_temp = []);
- if(a%4 == 0, x0 = [0, 2]);
- if(a%4 == 1, x0 = [1, 3]);
-
- for(k_temp = 3, e,
- x0_temp = [];
- for(idx = 1, #x0,
- x = x0[idx];
- if((x^2 - a) % (2^k_temp) == 0,
- x0_temp = concat(x0_temp, [x]);
- x0_temp = concat(x0_temp, [x + 2^(k_temp-1)]);
- )
- );
- x0 = x0_temp;
- if(#x0 == 0, break);
- );
- sols = x0;
- ))
- ,
- \\ Оптимизированная обработка нечетных простых
- if(issquare(Mod(a,p),&x1),x1=lift(x1),return([]));
- x2 = p - x1;
- x0 = [x1, x2];
-
- \\ Подъем Гензеля для p^k
- for(k_step = 2, e,
- my(temp = []);
- for(j = 1, #x0,
- my(x = x0[j], f = x^2 - a, df = 2*x);
- if(Mod(df, p) != 0,
- my(inv_df = lift(Mod(df, p^k_step)^(-1)));
- x = (x - f * inv_df) % (p^k_step);
- temp = concat(temp, [x]);
- ,
- if(Mod(f, p^k_step) == 0,
- for(t = 0, p-1,
- my(new_x = (x + t*p^(k_step-1)) % (p^k_step));
- temp = concat(temp, [new_x]);
- )
- )
- )
- );
- x0 = temp;
- if(#x0 == 0, break);
- );
- sols = x0;
- );
-
- if(#sols == 0, return([]));
- solutions_list = concat(solutions_list, [sols]);
- mod_list = concat(mod_list, [p^e]);
- );
-
- \\ Объединение решений
- if(#solutions_list == 0, return([]));
- if(#solutions_list == 1, return(solutions_list[1]));
-
- solutions = solutions_list[1];
- for(k = 2, #solutions_list,
- new_solutions = [];
- for(i = 1, #solutions,
- for(j = 1, #solutions_list[k],
- crt_val = chinese(Mod(solutions[i], mod_list[1]), Mod(solutions_list[k][j], mod_list[k]));
- if(crt_val != -1,
- new_solutions = concat(new_solutions, [lift(crt_val)]);
- )
- )
- );
- solutions = new_solutions;
- if(#solutions == 0, return([]));
- );
-
- vecsort(solutions,,8);
- }
Вид в одну строку, без пробелов и комментариев (может быть удобней для копипаста в pari) (Оффтоп)
- sqm(a,m)=my(factors,solutions_list,mod_list,p,e,sols,solutions,new_solutions,crt_val,i,k,j,x0,x1,x2);if(m==1,return([0]));if(a==0,return([0]));factors=factor(m);if(#factors[,1]==0,return([]));solutions_list=[];mod_list=[];for(i=1,#factors[,1],p=factors[i,1];e=factors[i,2];sols=[];if(p==2,if(e==1,if(a%2==0,sols=[0]),if(e==2,if(a%4==0,sols=[0,2]);if(a%4==1,sols=[1,3]),my(x0=[],x0_temp=[]);if(a%4==0,x0=[0,2]);if(a%4==1,x0=[1,3]);for(k_temp=3,e,x0_temp=[];for(idx=1,#x0,x=x0[idx];if((x^2-a)%(2^k_temp)==0,x0_temp=concat(x0_temp,[x]);x0_temp=concat(x0_temp,[x+2^(k_temp-1)]);));x0=x0_temp;if(#x0==0,break););sols=x0;)),if(issquare(Mod(a,p),&x1),x1=lift(x1),return([]));x2=p-x1;x0=[x1,x2];for(k_step=2,e,my(temp=[]);for(j=1,#x0,my(x=x0[j],f=x^2-a,df=2*x);if(Mod(df,p)!=0,my(inv_df=lift(Mod(df,p^k_step)^(-1)));x=(x-f*inv_df)%(p^k_step);temp=concat(temp,[x]);,if(Mod(f,p^k_step)==0,for(t=0,p-1,my(new_x=(x+t*p^(k_step-1))%(p^k_step));temp=concat(temp,[new_x]);))));x0=temp;if(#x0==0,break););sols=x0;);if(#sols==0,return([]));solutions_list=concat(solutions_list,[sols]);mod_list=concat(mod_list,[p^e]););if(#solutions_list==0,return([]));if(#solutions_list==1,return(solutions_list[1]));solutions=solutions_list[1];for(k=2,#solutions_list,new_solutions=[];for(i=1,#solutions,for(j=1,#solutions_list[k],crt_val=chinese(Mod(solutions[i],mod_list[1]),Mod(solutions_list[k][j],mod_list[k]));if(crt_val!=-1,new_solutions=concat(new_solutions,[lift(crt_val)]);)));solutions=new_solutions;if(#solutions==0,return([])););vecsort(solutions,,8)
|