前面我們已經學習過了高斯引理,那么二次互反律就呼之欲出了
我們先介紹一下什么是二次互反律
假設p,q是兩個奇素數,二次互反律就是要研究p對q的勒讓德符號和q對p的勒讓德符號之間的關系
二次互反律給出了結論:
legendre(p,q)*legendre(q,p)=(-1)^((p-1)*(q-1)/4)
我們通過證明下式來證明二次互反律,它蘊含着二次互反律
T(p,q)+T(q,p)=(p-1)*(q-1)/4
怎么證明T函數具有這樣一個奇妙性質呢?
不想寫太多證明的東西,看幾張圖片直觀感受一下你就明白了,其實這個公式不太難
這是最常見的利用填矩形的方式證明,直線上方點數就是T(p,q),下方點數就是T(q,p)
圖一:T(5,3)+T(3,5)=2*3
圖二 T(11,7)+T(7,11)=3*5
圖片是用java繪制的,代碼分享給大家:
import java.awt.Color; import java.awt.Graphics; import javax.swing.JFrame; public class test{ static int width=800,height=800,r=4,d=80; public static void paint_point(int x,int y,Graphics g) { x=d+d*x; y=height-d-d*y; g.setColor(Color.black); g.fillOval(x-r, y-r, r<<1, r<<1); } public static void paint_line(int fx,int fy,int sx,int sy,Graphics g) { fx=d+d*fx; fy=height-d-d*fy; sx=d+d*sx; sy=height-d-d*sy; g.setColor(Color.BLACK); g.drawLine(sx, sy, fx, fy); } public static void label_x(int p,int q,int i,Graphics g) { String str="["+p+"*"+i+"/"+q+"]"; int x=d*i+60,y=height-d; g.drawString(str, x, y); } public static void label_y(int p,int q,int i,Graphics g) { String str="["+p+"*"+i+"/"+q+"]"; int x=d,y=height-i*d-d; g.drawString(str, x, y); } public static void main(String[] args) { JFrame jf=new JFrame() { public void paint(Graphics g) { g.setColor(Color.white); g.fillRect(0, 0, width, height); int p=13,q=11;//在這里修改你想要的值 for(int i=1;i<=p/2;i++) { for(int j=1;j<=q/2;j++) { paint_point(i,j,g); } } for(int x=1;x<=p/2;x++) { label_x(q, p, x, g); } for(int y=1;y<=q/2;y++) { label_y(p, q, y, g); } paint_line(0, 0, p, q,g); } }; jf.setSize(width, height); jf.setVisible(true); jf.setDefaultCloseOperation(3); } }
話題收回來,我們知道了T(p,q)+T(q,p)=(p-1)*(q-1)/4
將兩邊作為-1的指數,就得到了二次互反律。
有了二次互反律,我們就可以高效解決判斷二次剩余的問題了
下面我們給出算法:
求a對p的勒讓德符號:
利用勒讓德符號的周期性,先將a取模p
將a分解素因數,保留次數為奇數的素因素{a1,a2....an}
對2,利用高斯引理的推論直接計算,對其他奇素數,利用二次互反律計算
利用勒讓德符號的可乘性,返回結果的積
此算法的瓶頸還是在於分解素因數,下面給出C++代碼實現
#include<iostream> using namespace std; //用於分解素因子 struct breaker{ int num,cur=2; breaker(int num){ this->num=num; } void next(int&res,int&pow){ pow=0;res=0; while(num%cur==0){ res=cur; pow++;num/=cur; } cur++; } //獲取下一個奇數次素因子 int get(){ int res,pow; next(res,pow); while(pow%2==0&&num>1){ next(res,pow); } return res; } }; //計算a對p的勒讓德符號,要求p是素數,a不是p的倍數 int legendre(int a,int p){ a%=p; breaker bk(a); int temp=bk.get(); int res=1; if(temp==2){ //使用高斯引理推論計算 res*=((p*p-1)&8)?-1:1; temp=bk.get(); } while(temp){ //使用二次互反律計算 res*=legendre(p,temp)*(((p-1)&(temp-1)&2)?-1:1); temp=bk.get(); } return res; } int main(){ cout<<legendre(137,227); }
希望對大家有幫助!