Улучшил предыдущий код:
Код:
/* solve x^2=a mod p, p is prime */
modulop(a,p):=block([h, N1, N2, legandr, N,a1,a2, k,p1,i, b, c, d, j],
if primep(p) then
block(
legandr: power_mod(a,(p-1)/2,p),
if legandr = p-1 then
"No solutions"
else
block(
h:p-1, k:0,
while mod(h,2)=0 do block(h:h/2,k:k+1),
N:2,
while power_mod(N,(p-1)/2,p)=1 do N:N+1,
a1:power_mod(a, (h+1)/2,p), N1:power_mod(N,h,p),
N2:1, j:0, a2:inv_mod(a,p),
for i:0 thru k-2 do
block(
b:mod(a1*N2,p), c:mod(a2*b^2,p),
d:power_mod(c,2^(k-2-i),p),
if d = 1 then j:0,
if d=p-1 then j:1,
N2:mod(N2*power_mod(N1,(2^i*j),p),p)),
j:mod(a1*N2,p),
[j, p-j]))
else
"Not prime")$
Реализовал нахождение решения сравнения
![$v^2\equiv R\mod m$ $v^2\equiv R\mod m$](https://dxdy-04.korotkov.co.uk/f/b/f/1/bf17227f49fc5d6d9c7964670755f09282.png)
для
![$m=p_1\cdot p_2$ $m=p_1\cdot p_2$](https://dxdy-03.korotkov.co.uk/f/2/f/b/2fb75b3a3e302165f69a45aa7de45d3582.png)
:
Код:
/* solve x^2=a mod m, m = p1 * p2 */
modulop1p2(a,m):= block([fact:ifactors(m), ans1, ans2,res:[]],
if length(fact) # 2 then
"m is not equal p1*p2"
else
block(
if (fact[1][2] = 1) and (fact[2][2] = 1) then
block(
ans1:modulop(a,fact[1][1]),
ans2:modulop(a,fact[2][1]),
res:cons(chinese([ans1[1],ans2[1]],[fact[1][1], fact[2][1]]), res),
res:cons(chinese([ans1[1],ans2[2]],[fact[1][1], fact[2][1]]), res),
res:cons(chinese([ans1[2],ans2[1]],[fact[1][1], fact[2][1]]), res),
res:cons(chinese([ans1[2],ans2[2]],[fact[1][1], fact[2][1]]), res),
res)
else
"m is equal p1^a*p2^b, a or b > 1" ))$
Для общего вида
![$m$ $m$](https://dxdy-01.korotkov.co.uk/f/0/e/5/0e51a2dede42189d77627c4d742822c382.png)
больно муторно перебирать все
![$2^n$ $2^n$](https://dxdy-04.korotkov.co.uk/f/f/8/f/f8f25e4580c418a51dc556db0d8d2b9382.png)
комбинаций, где
![$n$ $n$](https://dxdy-02.korotkov.co.uk/f/5/5/a/55a049b8f161ae7cfeb0197d75aff96782.png)
- число простых делителей
![$m$ $m$](https://dxdy-01.korotkov.co.uk/f/0/e/5/0e51a2dede42189d77627c4d742822c382.png)
.
Для эффективного перебора нужно еще разработать правила останова для
![$R$ $R$](https://dxdy-02.korotkov.co.uk/f/1/e/4/1e438235ef9ec72fc51ac5025516017c82.png)
.
Пусть известно решение
![$v_1^2\equiv R_1\mod m$ $v_1^2\equiv R_1\mod m$](https://dxdy-04.korotkov.co.uk/f/f/3/5/f35fb774ab5f46f26386681d6fbb8a6482.png)
, найдем ограничение для
![$R_2, v_2$ $R_2, v_2$](https://dxdy-04.korotkov.co.uk/f/f/5/6/f563c30d01c2d66911e7201f9a5d999982.png)
, для которых возможно лучшее приближение.
Имеем:
![$$2m-\sqrt{(m-v_1)^2-R_1}-\sqrt{(m+v_1)^2-R_1}>2m-\sqrt{(m-v_2)^2-R_2}-\sqrt{(m+v_2)^2-R_2}$$ $$2m-\sqrt{(m-v_1)^2-R_1}-\sqrt{(m+v_1)^2-R_1}>2m-\sqrt{(m-v_2)^2-R_2}-\sqrt{(m+v_2)^2-R_2}$$](https://dxdy-04.korotkov.co.uk/f/3/e/9/3e91a1f288fb4fa3ed1a7a68682f1f7582.png)
т.е. должно выполняться:
![$$\sqrt{(m-v_1)^2-R_1}+\sqrt{(m+v_1)^2-R_1}<\sqrt{(m-v_2)^2-R_2}+\sqrt{(m+v_2)^2-R_2}$$ $$\sqrt{(m-v_1)^2-R_1}+\sqrt{(m+v_1)^2-R_1}<\sqrt{(m-v_2)^2-R_2}+\sqrt{(m+v_2)^2-R_2}$$](https://dxdy-02.korotkov.co.uk/f/1/6/0/160493fa7996c7d1c2d3e844904289ed82.png)
Обозначим
![$a=\sqrt{(m-v_1)^2-R_1}+\sqrt{(m+v_1)^2-R_1}, b=(m-v_2)^2, c=(m+v_2)^2$ $a=\sqrt{(m-v_1)^2-R_1}+\sqrt{(m+v_1)^2-R_1}, b=(m-v_2)^2, c=(m+v_2)^2$](https://dxdy-02.korotkov.co.uk/f/5/7/4/574b1c351f1f504544e187b54e8c94c382.png)
Возводим в квадрат:
![$$a^2<b-R_2+c-R_2+2\sqrt{(b-R_2)(c-R_2)}$$ $$a^2<b-R_2+c-R_2+2\sqrt{(b-R_2)(c-R_2)}$$](https://dxdy-02.korotkov.co.uk/f/9/7/a/97a4bc78e8bed375e937577e1beb06d382.png)
![$$a^2-b-c+2R_2<2\sqrt{(b-R_2)(c-R_2)}$$ $$a^2-b-c+2R_2<2\sqrt{(b-R_2)(c-R_2)}$$](https://dxdy-04.korotkov.co.uk/f/3/6/9/3694c6b71008903ff34fde0308498d1e82.png)
Возводим еще раз в квадрат:
![$$(a^2-b-c+2R_2)^2<4(b-R_2)(c-R_2)$$ $$(a^2-b-c+2R_2)^2<4(b-R_2)(c-R_2)$$](https://dxdy-02.korotkov.co.uk/f/1/9/b/19b9f0b48be83b80f12fd3b061a593b482.png)
![$$(a^2-b-c)^2+4R_2(a^2-b-c)+4R_2^2<4bc-4bR_2-4cR_2+4R_2^2$$ $$(a^2-b-c)^2+4R_2(a^2-b-c)+4R_2^2<4bc-4bR_2-4cR_2+4R_2^2$$](https://dxdy-02.korotkov.co.uk/f/5/6/f/56f47a310bb3ad1e68e8c6f1eb5abd8c82.png)
![$$(a^2-b-c)^2+4R_2a^2<4bc$$ $$(a^2-b-c)^2+4R_2a^2<4bc$$](https://dxdy-04.korotkov.co.uk/f/f/b/8/fb8b38a13248fef3aed9e6193eca76ae82.png)
![$$R_2<\frac{4bc-(a^2-b-c)^2}{4a^2}$$ $$R_2<\frac{4bc-(a^2-b-c)^2}{4a^2}$$](https://dxdy-02.korotkov.co.uk/f/5/a/9/5a957450b7829b87d8953fd681eaa28882.png)
После всех подстановок и сокращений окончательно получаем (если не ошибся):
![$$R_2<m^2-\frac{a^2}{4}+v_2^2-\frac{4m^2v_2^2}{a^2}$$ $$R_2<m^2-\frac{a^2}{4}+v_2^2-\frac{4m^2v_2^2}{a^2}$$](https://dxdy-03.korotkov.co.uk/f/a/7/1/a711dea6c3d6c732ee6fbae66c1f3cc882.png)
Поскольку
![$4m^2>a^2$ $4m^2>a^2$](https://dxdy-02.korotkov.co.uk/f/1/0/2/10265105da5c9905f577aa7e39ca867e82.png)
, то функция
![$f(v_2)=v_2^2(1-\frac{4m^2}{a^2})$ $f(v_2)=v_2^2(1-\frac{4m^2}{a^2})$](https://dxdy-04.korotkov.co.uk/f/7/3/7/7374ef1b64de5b1d48237e9d4f73c49e82.png)
достигает максимума в точке
![$v_2=0$ $v_2=0$](https://dxdy-02.korotkov.co.uk/f/5/8/7/587da0ba78454365c222f12088cea26082.png)
.
Поэтому имеем следующее ограничение:
![$$R_2<m^2-\frac{a^2}{4}$$ $$R_2<m^2-\frac{a^2}{4}$$](https://dxdy-01.korotkov.co.uk/f/4/4/f/44f782d6dc26d5cccda4972d3cfe085582.png)
Но это не особенно полезно.
![$$v_2<\sqrt{\frac{m^2-\frac{a^2}{4}-R_2}{\frac{4m^2}{a^2}-1}}$$ $$v_2<\sqrt{\frac{m^2-\frac{a^2}{4}-R_2}{\frac{4m^2}{a^2}-1}}$$](https://dxdy-03.korotkov.co.uk/f/2/4/2/242e2caed98e4343cd723ec055312fb082.png)
А вот на это можно опираться. Для этого добавим еще порцию кода:
Код:
delta(m,R,L):=block([dd,v,vv,i:1,j],
while not(integerp(xy(m,L[i],R)[1])) and (i<length(L)) do i:i+1,
dd:bfloat(2*m-sqrt((m-L[i])^2-R)-sqrt((m+L[i])^2-R)),vv:L[i],
for j:i+1 thru length(L) do
block(
if (dd>bfloat(2*m-sqrt((m-L[j])^2-R)-sqrt((m+L[j])^2-R))) and (integerp(xy(m,L[j],R)[1])) then
block(dd:bfloat(2*m-sqrt((m-L[j])^2-R)-sqrt((m+L[j])^2-R)),vv:L[j])),
if integerp(xy(m,vv,R)[1]) then
[vv,dd]
else
false)$
xy(m,v,R):=([((m-v)^2-R)/(4*m),((m+v)^2-R)/(4*m)])$
fpprec:30$
v2(m,v1,R1,R2):=block([a], a:bfloat(sqrt((m-v1)^2-R1)+sqrt((m+v1)^2-R1)),bfloat(sqrt((m^2-a^2/4-R2)/(4*m^2/a^2-1))))$
Функция delta(m,R,L) выбирает из списка L решений сравнения
![$v^2\equiv R\mod m$ $v^2\equiv R\mod m$](https://dxdy-04.korotkov.co.uk/f/b/f/1/bf17227f49fc5d6d9c7964670755f09282.png)
целочисленное решение с минимальной ошибкой
![$2m-a$ $2m-a$](https://dxdy-03.korotkov.co.uk/f/e/a/b/eab6164e212b948c843691ccf2d0d8e782.png)
, если целочисленных решений нет, то возвращается false.
Функция xy(m,v,R) просто получает список решений
![$x,y$ $x,y$](https://dxdy-01.korotkov.co.uk/f/0/a/c/0acac2a2d5d05a8394e21a70a71041b482.png)
для заданных
![$m,v,R$ $m,v,R$](https://dxdy-02.korotkov.co.uk/f/1/5/c/15cda416ec573439e43c3afdeae59d8782.png)
.
Функция v2(m,v1,R1,R2) считает собственно верхнее ограничение для
![$v_2$ $v_2$](https://dxdy-02.korotkov.co.uk/f/5/3/2/53292819177dbb29ba6d92fe3aa2880c82.png)
по полученной формуле для известных
![$v_1,R_1$ $v_1,R_1$](https://dxdy-04.korotkov.co.uk/f/3/f/2/3f24efc53ddd8c1f598f701c62a8ccb082.png)
и нового
![$R_2$ $R_2$](https://dxdy-01.korotkov.co.uk/f/0/5/f/05f4ca837f07995f711e9df7b84e1c0782.png)
.
Продемонстрируем на примере треугольного числа (максимального в указанной ранее таблице)
![$m=714195944281=597577\cdot 1195153$ $m=714195944281=597577\cdot 1195153$](https://dxdy-01.korotkov.co.uk/f/8/f/4/8f409d04753cdac8d08febedd75b159682.png)
Код:
(%i7) delta(714195944281,1, modulop1p2(1, 714195944281));
(%o7) [714193553974, 2.09178501637662800360928372356b-7]
(%i8) v2(714195944281, 714193553974, 1, 2);
(%o8) 7.14191163658994066022843741247b11
(%i9) delta(714195944281,2, modulop1p2(2, 714195944281));
(%o9) false
(%i10) v2(714195944281, 714193553974, 1, 3);
(%o10) 7.14188773335993878063157787733b11
(%i11) delta(714195944281,3, modulop1p2(3, 714195944281));
(%o11) false
(%i12) v2(714195944281, 714193553974, 1, 4);
(%o12) 7.14186383004993475900066029253b11
(%i13) delta(714195944281,4, modulop1p2(4, 714195944281));
(%o13) [714191163667, 4.18357703366352418061779872005b-7]
(%i14) v2(714195944281, 714191163667, 4, 5);
(%o14) 7.14189968508510919964289242979b11
(%i15) delta(714195944281,5, modulop1p2(5, 714195944281));
(%o15) false
(%i16) v2(714195944281, 714191163667, 4, 6);
(%o16) 7.14188773348010840036651324299b11
(%i17) delta(714195944281,6, modulop1p2(6, 714195944281));
(%o17) false
(%i18) v2(714195944281, 714191163667, 4, 7);
(%o18) 7.14187578185510713252166124388b11
(%i19) delta(714195944281,7, modulop1p2(7, 714195944281));
(%o19) false
(%i20) v2(714195944281, 714191163667, 4, 8);
(%o20) 7.14186383021010529569837096844b11
(%i21) delta(714195944281,8, modulop1p2(8, 714195944281));
(%o21) [214899754753, 1.23165381973183718500308714283b-11]
(%i22) v2(714195944281, 214899754753, 8, 9);
(%o22) 1.08650074855601945444046486567b11 %i
Итак, на
![$R=8$ $R=8$](https://dxdy-04.korotkov.co.uk/f/3/9/8/39851f26937257bec43381c1b9a2b63382.png)
уперлись. Имеем в порядке убывания точности:
![$$\sqrt{714195944281}\approx\sqrt{87264806974}+\sqrt{302164561727}, R=8$$ $$\sqrt{714195944281}\approx\sqrt{87264806974}+\sqrt{302164561727}, R=8$$](https://dxdy-04.korotkov.co.uk/f/3/c/a/3ca8d88cb3c9382b5e2411b20351332982.png)
![$$\sqrt{714195944281}\approx\sqrt{2}+\sqrt{714193553976}, R=1$$ $$\sqrt{714195944281}\approx\sqrt{2}+\sqrt{714193553976}, R=1$$](https://dxdy-01.korotkov.co.uk/f/0/6/d/06d62e6e6f63870e4e5ad61c114c7e2982.png)
![$$\sqrt{714195944281}\approx\sqrt{8}+\sqrt{714191163675}, R=4$$ $$\sqrt{714195944281}\approx\sqrt{8}+\sqrt{714191163675}, R=4$$](https://dxdy-01.korotkov.co.uk/f/c/c/e/cce4102f90e0b519ab96770b40bfe6d482.png)
Код:
(%i33) bfloat(sqrt(714195944281));
(%o33) 8.45101144408762471059270771886b5
(%i34) bfloat(sqrt(87264806974)+sqrt(302164561727));
(%o34) 8.45101144408762471059263484866b5
(%i35) bfloat(sqrt(2)+sqrt(714193553976));
(%o35) 8.45101144408762470935511324262b5
(%i36) bfloat(sqrt(8)+sqrt(714191163675));
(%o36) 8.45101144408762470811751462432b5
-- Вс янв 15, 2023 17:12:19 --много ли радости в таком решении
Для составных общего вида радости немного, поскольку там наблюдается экспоненциальный рост от количества простых делителей, плюс факторизация нужна.
На алгоритм, который я реализовал в виде функции modulop, оказывается указывал еще
waxtep:
Тогда, для простого
![$m$ $m$](https://dxdy-01.korotkov.co.uk/f/0/e/5/0e51a2dede42189d77627c4d742822c382.png)
, можно попробовать перебирать значения
![$R$ $R$](https://dxdy-02.korotkov.co.uk/f/1/e/4/1e438235ef9ec72fc51ac5025516017c82.png)
по возрастанию (причем, не все
![$R$ $R$](https://dxdy-02.korotkov.co.uk/f/1/e/4/1e438235ef9ec72fc51ac5025516017c82.png)
будут разрешены по соображениям взаимности) и в лоб извлекать из них корни по модулю
![$m$ $m$](https://dxdy-01.korotkov.co.uk/f/0/e/5/0e51a2dede42189d77627c4d742822c382.png)
, - здесь же есть быстрые алгоритмы (не имел реального опыта реализации, но вот пишут: Алгоритм Тонелли—Шенкса
; есть некоторые оговорки, но, на первый взгляд, алгоритм не выглядит устрашающим/безнадежным).
https://ru.wikipedia.org/wiki/%D0%90%D0 ... 1%81%D0%B0