目录
欧拉定理求逆
欧拉定理
欧拉函数的通式
欧拉筛
欧拉筛代码
演示结果
EULER_F.m
输出的质数表
防溢出
欧拉定理求逆元的代码
辗转相减法求逆
更相减损术
迭代式:
辗转相减求逆代码
检验结果
小结
上一篇文章讲了求逆的扩欧法和公式法,这一次讲欧拉定理法和辗转相减法。
欧拉定理求逆
欧拉定理
对于 a和模 n,a和n互质, a^φ(n) = 1(mod n)。
φ(n)为欧拉函数,是2 - n-1中,所有和n互质的数加1。其中,φ(1)=φ(2)=1。
这个式子太熟悉了。把其中一个a提出来,就变成了a*a^(φ(n) -1) = 1(mod n),a的逆元就是a^(φ(n) -1)。
欧拉函数的通式
如果n可以被分解成若干个质因数的乘积pm,则
φ(n)=n*(1-1/p1)*(1-1/p2)*(1-1/p3)*(1-1/p4)*……*(1-1/pm)
若n为质数,则φ(n) = n - 1;
(如果n可以被分解成两个质数p,q的乘积,那么欧拉函数就是两个质数的欧拉函数的乘积(p-1)*(q-1)
质因数是指,可以被n整除的质数,或者说是n的因数中不可再分的因数。
所以用欧拉定理求逆的关键在于,判断n有没有质因数。即找到比n小的质数,判断是否可以整除。
寻找比n小的质数,这里使用欧拉筛来筛选素数。
欧拉筛
欧拉筛相比起其他筛素数的方法的特点是,不会重复筛选。所以效率是有保障的。
步骤是这样的:
建立一个合数集和质数。初始都是空集。
从2开始遍历,一直到n。(这里用来筛选所有小于n的质数,如果只是要筛选质因数,到n/2就可以了)
判断是否是质数的条件,就是判断它是否出现在合数集中。没有出现在合数集,就储存在质数集中。
判断是合数的条件,就是用遍历中的每个数,乘以质数集里面的每个数,得到的这些乘积就是合数。
一开始合数集和质数集是空的,先判断质数,然后再乘以质数集的元素储存合数。
如果乘积大于n,用不上,就不储存啦。
为了避免重复储存合数,这里用比较小的质数来储存合数。比如24 = 2*12 = 3*8 = 4*6,这里24可以在遍历到6,8,12的时候都可以储存,为了避免重复储存,应该避免在在6的时候乘到4,和8的时候乘到3。即遍历的数不能乘以比它质因数还大的质数。
代码如下:
欧拉筛代码
isnot_prime = zeros(1 , n);%判断是否是合数prime = [];%质数集for i = 2:nif (isnot_prime(i) == 0)prime(end + 1) = i;endfor j = 1 : length(prime)if((i*(prime(j))>n))break;endisnot_prime(i*(prime(j))) = 1;if(mod(i , prime(j)) == 0)break;endendend
演示结果
n = 2 ---not prime: 4 n = 3 ---not prime: 6 9 n = 4 ---not prime: 8 n = 5 ---not prime: 10 15 25 n = 6 ---not prime: 12 n = 7 ---not prime: 14 21 35 49 n = 8 ---not prime: 16 n = 9 ---not prime: 18 27 n = 10 ---not prime: 20 n = 11 ---not prime: 22 33 55 77 121 n = 12 ---not prime: 24 n = 13 ---not prime: 26 39 65 91 143 169 n = 14 ---not prime: 28 n = 15 ---not prime: 30 45 n = 16 ---not prime: 32 n = 17 ---not prime: 34 51 85 119 187 221 289 n = 18 ---not prime: 36 n = 19 ---not prime: 38 57 95 133 209 247 323 361 n = 20 ---not prime: 40
然后再加上判断质因数的个数,来求欧拉函数就好了。我这里遍历到了n,如果最后的质因数等于它本身,那么它就是质数,欧拉函数就是n-1,如果不是质数,就按照通式计算。
求欧拉函数的代码:
EULER_F.m
%计算欧拉函数claculate the Euler functionfunction e = EULER_F(n)isnot_prime = zeros(1 , n);%判断是否是质数prime = [];%质数集primen = [];%质因数集if(n == 1)e = 1;return;endfor i = 2:nif (isnot_prime(i) == 0)prime(end + 1) = i;endfor j = 1 : length(prime)if((i*(prime(j))>n))break;endisnot_prime(i*(prime(j))) = 1;if(mod(i , prime(j)) == 0)break;endendendfor k = 1:length(prime)if(mod(n , prime(k)) == 0)primen(end + 1) = prime(k);endendif(primen(length(primen)) == n)e = n-1;elsee = n;for i = 1 : length(primen)e = e*(1 - 1/primen(i));endende = floor(e);
同样,只要把prime集输出,就可以得到质数表。
输出的质数表
打印小于10000的质数表>> 2357 11 13 17 19 23 29 >> 31 37 41 43 47 53 59 61 67 71 >> 73 79 83 89 97 101 103 107 109 113 >> 127 131 137 139 149 151 157 163 167 173 >> 179 181 191 193 197 199 211 223 227 229 >> 233 239 241 251 257 263 269 271 277 281 >> 283 293 307 311 313 317 331 337 347 349 >> 353 359 367 373 379 383 389 397 401 409 >> 419 421 431 433 439 443 449 457 461 463 >> 467 479 487 491 499 503 509 521 523 541 >> 547 557 563 569 571 577 587 593 599 601 >> 607 613 617 619 631 641 643 647 653 659 >> 661 673 677 683 691 701 709 719 727 733 >> 739 743 751 757 761 769 773 787 797 809 >> 811 821 823 827 829 839 853 857 859 863 >> 877 881 883 887 907 911 919 929 937 941 >> 947 953 967 971 977 983 991 997 1009 1013 >> 1019 1021 1031 1033 1039 1049 1051 1061 1063 1069 >> 1087 1091 1093 1097 1103 1109 1117 1123 1129 1151 >> 1153 1163 1171 1181 1187 1193 1201 1213 1217 1223 >> 1229 1231 1237 1249 1259 1277 1279 1283 1289 1291 >> 1297 1301 1303 1307 1319 1321 1327 1361 1367 1373 >> 1381 1399 1409 1423 1427 1429 1433 1439 1447 1451 >> 1453 1459 1471 1481 1483 1487 1489 1493 1499 1511 >> 1523 1531 1543 1549 1553 1559 1567 1571 1579 1583 >> 1597 1601 1607 1609 1613 1619 1621 1627 1637 1657 >> 1663 1667 1669 1693 1697 1699 1709 1721 1723 1733 >> 1741 1747 1753 1759 1777 1783 1787 1789 1801 1811 >> 1823 1831 1847 1861 1867 1871 1873 1877 1879 1889 >> 1901 1907 1913 1931 1933 1949 1951 1973 1979 1987 >> 1993 1997 1999 2027 2029 2039 2053 >> 2063 2069 2081 2083 2087 2089 2099 2111 2113 2129 >> 2131 2137 2141 2143 2153 2161 2179 2203 2207 2213 >> 2221 2237 2239 2243 2251 2267 2269 2273 2281 2287 >> 2293 2297 2309 2311 2333 2339 2341 2347 2351 2357 >> 2371 2377 2381 2383 2389 2393 2399 2411 2417 2423 >> 2437 2441 2447 2459 2467 2473 2477 2503 2521 2531 >> 2539 2543 2549 2551 2557 2579 2591 2593 2609 2617 >> 2621 2633 2647 2657 2659 2663 2671 2677 2683 2687 >> 2689 2693 2699 2707 2711 2713 2719 2729 2731 2741 >> 2749 2753 2767 2777 2789 2791 2797 2801 2803 2819 >> 2833 2837 2843 2851 2857 2861 2879 2887 2897 2903 >> 2909 2917 2927 2939 2953 2957 2963 2969 2971 2999 >> 3001 3011 3019 3023 3037 3041 3049 3061 3067 3079 >> 3083 3089 3109 3119 3121 3137 3163 3167 3169 3181 >> 3187 3191 3203 3209 3217 3221 3229 3251 3253 3257 >> 3259 3271 3299 3301 3307 3313 3319 3323 3329 3331 >> 3343 3347 3359 3361 3371 3373 3389 3391 3407 3413 >> 3433 3449 3457 3461 3463 3467 3469 3491 3499 3511 >> 3517 3527 3529 3533 3539 3541 3547 3557 3559 3571 >> 3581 3583 3593 3607 3613 3617 3623 3631 3637 3643 >> 3659 3671 3673 3677 3691 3697 3701 3709 3719 3727 >> 3733 3739 3761 3767 3769 3779 3793 3797 3803 3821 >> 3823 3833 3847 3851 3853 3863 3877 3881 3889 3907 >> 3911 3917 3919 3923 3929 3931 3943 3947 3967 3989 >> 4001 4003 4007 4013 4019 4021 4027 4049 4051 4057 >> 4073 4079 4091 4093 4099 4111 4127 4129 4133 4139 >> 4153 4157 4159 4177 4201 4211 4217 4219 4229 4231 >> 4241 4243 4253 4259 4261 4271 4273 4283 4289 4297 >> 4327 4337 4339 4349 4357 4363 4373 4391 4397 4409 >> 4421 4423 4441 4447 4451 4457 4463 4481 4483 4493 >> 4507 4513 4517 4519 4523 4547 4549 4561 4567 4583 >> 4591 4597 4603 4621 4637 4639 4643 4649 4651 4657 >> 4663 4673 4679 4691 4703 4721 4723 4729 4733 4751 >> 4759 4783 4787 4789 4793 4799 4801 4813 4817 4831 >> 4861 4871 4877 4889 4903 4909 4919 4931 4933 4937 >> 4943 4951 4957 4967 4969 4973 4987 4993 4999 5003 >> 5009 5011 5021 5023 5039 5051 5059 5077 5081 5087 >> 5099 5101 5107 5113 5119 5147 5153 5167 5171 5179 >> 5189 5197 5209 5227 5231 5233 5237 5261 5273 5279 >> 5281 5297 5303 5309 5323 5333 5347 5351 5381 5387 >> 5393 5399 5407 5413 5417 5419 5431 5437 5441 5443 >> 5449 5471 5477 5479 5483 5501 5503 5507 5519 5521 >> 5527 5531 5557 5563 5569 5573 5581 5591 5623 5639 >> 5641 5647 5651 5653 5657 5659 5669 5683 5689 5693 >> 5701 5711 5717 5737 5741 5743 5749 5779 5783 5791 >> 5801 5807 5813 5821 5827 5839 5843 5849 5851 5857 >> 5861 5867 5869 5879 5881 5897 5903 5923 5927 5939 >> 5953 5981 5987 6007 6011 6029 6037 6043 6047 6053 >> 6067 6073 6079 6089 6091 6101 6113 6121 6131 6133 >> 6143 6151 6163 6173 6197 6199 6203 6211 6217 6221 >> 6229 6247 6257 6263 6269 6271 6277 6287 6299 6301 >> 6311 6317 6323 6329 6337 6343 6353 6359 6361 6367 >> 6373 6379 6389 6397 6421 6427 6449 6451 6469 6473 >> 6481 6491 6521 6529 6547 6551 6553 6563 6569 6571 >> 6577 6581 6599 6607 6619 6637 6653 6659 6661 6673 >> 6679 6689 6691 6701 6703 6709 6719 6733 6737 6761 >> 6763 6779 6781 6791 6793 6803 6823 6827 6829 6833 >> 6841 6857 6863 6869 6871 6883 6899 6907 6911 6917 >> 6947 6949 6959 6961 6967 6971 6977 6983 6991 6997 >> 7001 7013 7019 7027 7039 7043 7057 7069 7079 7103 >> 7109 7121 7127 7129 7151 7159 7177 7187 7193 7207 >> 7211 7213 7219 7229 7237 7243 7247 7253 7283 7297 >> 7307 7309 7321 7331 7333 7349 7351 7369 7393 7411 >> 7417 7433 7451 7457 7459 7477 7481 7487 7489 7499 >> 7507 7517 7523 7529 7537 7541 7547 7549 7559 7561 >> 7573 7577 7583 7589 7591 7603 7607 7621 7639 7643 >> 7649 7669 7673 7681 7687 7691 7699 7703 7717 7723 >> 7727 7741 7753 7757 7759 7789 7793 7817 7823 7829 >> 7841 7853 7867 7873 7877 7879 7883 7901 7907 7919 >> 7927 7933 7937 7949 7951 7963 7993 8009 8011 8017 >> 8039 8053 8059 8069 8081 8087 8089 8093 8101 8111 >> 8117 8123 8147 8161 8167 8171 8179 8191 8209 8219 >> 8221 8231 8233 8237 8243 8263 8269 8273 8287 8291 >> 8293 8297 8311 8317 8329 8353 8363 8369 8377 8387 >> 8389 8419 8423 8429 8431 8443 8447 8461 8467 8501 >> 8513 8521 8527 8537 8539 8543 8563 8573 8581 8597 >> 8599 8609 8623 8627 8629 8641 8647 8663 8669 8677 >> 8681 8689 8693 8699 8707 8713 8719 8731 8737 8741 >> 8747 8753 8761 8779 8783 8803 8807 8819 8821 8831 >> 8837 8839 8849 8861 8863 8867 8887 8893 8923 8929 >> 8933 8941 8951 8963 8969 8971 8999 9001 9007 9011 >> 9013 9029 9041 9043 9049 9059 9067 9091 9103 9109 >> 9127 9133 9137 9151 9157 9161 9173 9181 9187 9199 >> 9203 9209 9221 9227 9239 9241 9257 9277 9281 9283 >> 9293 9311 9319 9323 9337 9341 9343 9349 9371 9377 >> 9391 9397 9403 9413 9419 9421 9431 9433 9437 9439 >> 9461 9463 9467 9473 9479 9491 9497 9511 9521 9533 >> 9539 9547 9551 9587 9601 9613 9619 9623 9629 9631 >> 9643 9649 9661 9677 9679 9689 9697 9719 9721 9733 >> 9739 9743 9749 9767 9769 9781 9787 9791 9803 9811 >> 9817 9829 9833 9839 9851 9857 9859 9871 9883 9887 >> 9901 9907 9923 9929 9931 9941 9949 9967 9973
防溢出
欧拉函数现在以及可以求出来啦,如果要求逆元的话,a^(φ(n) -1)一定是个特别大的数字。为了求最小的逆元,还有防止计算过程中求出来的数字太大,溢出,然后造成的数值误差,我们需要每次乘积的时候,都要对模n,进行取余运算。
这里把欧拉函数的值记为m,因为是φ(n) -1次幂,所以用m>2来限制。
A = a;while(m > 2)A = mod(A*a , n);m = m - 1;end
欧拉定理求逆元的代码
我再写代码的时候,出于个人习惯,写成了三个函数,第一个函数调用后两个的函数,最后输出的结果就是最小的正整数逆元。
function e = EULER_F_inv(a , n)E = EULER_F(n);e = HIGH_POWER_INV(a , n , E);
%计算欧拉函数claculate the Euler functionfunction e = EULER_F(n)isnot_prime = zeros(1 , n);%判断是否是合数prime = [];%质数集primen = [];%质因数集if(n == 1)e = 1;return;endfor i = 2:nif (isnot_prime(i) == 0)prime(end + 1) = i;endfor j = 1 : length(prime)if((i*(prime(j))>n))break;endisnot_prime(i*(prime(j))) = 1;if(mod(i , prime(j)) == 0)break;endendendfor k = 1:length(prime)if(mod(n , prime(k)) == 0)primen(end + 1) = prime(k);endendif(primen(length(primen)) == n)e = n-1;elsee = n;for i = 1 : length(primen)e = e*(1 - 1/primen(i));endende = floor(e);
%高次幂的逆元计算function f = HIGH_POWER_INV(e , n, nn)E = e;while(nn>2)E = mod(E*e , n);nn = nn - 1;endf = E;
接下来讲辗转相减法求逆元
辗转相减法求逆
这种方法是以前高中数学课堂上求公因数的更相减损术,也被称为欧几里得减法。
更相减损术
数学表达式:
a*x + b*y = 1 (a>b)
更相减损术和欧几里得算法的辗转相除法在形式上和逻辑上是类似的。但是也有很多地方不一样。
首先两钟方法的表达式是一样的,用的方法也都是迭代,除法可以看成是一次次减法的累积。
不同点在于,对于除法来说,mod(a , b)即a除以b的余数一定小于b,这样a永远是b,b一直是mod(a , b)。对于减法来说,每一次都要判断一下a - b和b的大小。
而且,a和a+b对于b的余数是一样的,这就意味着,当a小于b的时候,除法可以通过给a加上一定的b,从而可以通过迭代的方式求出a的逆,但是减法不可以。减法必须要求a>b。
同时,a和b迭代的方式会影响x和y的迭代公式,扩展欧几里得原理只有一套公式,但是辗转相除法有两套公式,并且什么时候用哪一套得基于判断。但是减法不同的,x和y的迭代公式中,没有a和b。
最后,两种方式的极限是不同的。除法的停止判断是b = 0 ,而减法的停止判断是a -b = 0;导致结束的式子,除法是a*x + 0*y= 1,那么a = 1 ,y = 0则是最小逆元的条件。但是对于减法,一般是这样的:1*x + 1*y = 1;那么最小逆元的条件是两个,要么x= 0,y = 1,要么x = 1,y = 0,无法确定是哪一种。至少我现在不知道,只是有一些猜测。
所以,用减法的优点是,从极限位置去推不需要记录每一步的a和b的取值,
缺点是,但是要记录a-b和b的大小,用来判断x和y的迭代方式,而且极限位置的x,y取值不确定,需要都算,然后最后检验,选择一个取值。同时只能有a>b的情况。
迭代式:
若b < a - b
an= an-1 - bn-1 , bn = bn-1;
xn = xn-1,yn = xn - xn-1;
若b > a - b
an = bn-1,bn = an-1 - bn-1;
xn = yn + yn-1,yn = xn-1;
从极限方向的推导式子:
b > a - b
xn-1 = yn
yn-1 = xn - yn
b < a - b
xn-1 = xn
yn-1 = yn - xn
所以要用减法的时候,需要先正向迭代,记录好b和a-b的关系,然后再从极限位置逆推,解出x,并选择正确的x。
辗转相减求逆代码
%欧几里得减法(辗转相减法)Must a>b;function f = getinv1( a ,b)A = a;B = b;sign = [];x1 = 0;y1 = 1;i = 1;while((a - b)~= 0)r = a - b;a = b;b = r;if(a < b)temp = b;b = a;a = temp;sign(end + 1) = 0;elseif(a > b)sign(end + 1) = 1;elsesign(end + 1) = 0;endi = i + 1;endwhile(i ~= 1)if(sign(i-1) == 1)z = y1;y1 = x1 - y1;x1 = z;elsey1 = y1 - x1;endi = i - 1;endwhile(x1<0)x1 = x1 + B;endsign = [];x2 = 1;y2 = 0;i = 1;a = A;b = B;while((a - b)~= 0)r = a - b;a = b;b = r;if(a < b)temp = b;b = a;a = temp;sign(end + 1) = 0;elseif(a > b)sign(end + 1) = 1;elsesign(end + 1) = 0;endi = i + 1;endwhile(i ~= 1)if(sign(i-1) == 1)z = y2;y2 = x2 - y2;x2 = z;elsey2 = y2 - x2;endi = i - 1;endwhile(x2<0)x2 = x2 + B;endif(mod((a*x1) , b) == 1)f = x1;elsef = x2;end
检验结果
对于代码正确性的检验
a = 1333n = 25r,inv = 22a = 16754678n = 199r,inv = 47a = 23n = 13r,inv = 4
小结
对于这几种求逆元的方式,小编没有去写详细的数学方面的证明和解释,只是简单的将这些理论拿来,用在了程序求解上。但是我希望读者可以通过我的文章,来了解更多的数学,对数学产生兴趣。
同样的,我也没有去特意说明每一种算法的时间复杂度和空间复杂度,只是简单介绍一下。
在四种求逆的方法中,除了辗转相减法,其他三种都可以计算a<n时的逆元,这个要记住啊。
这篇文章就到这里了,希望对你有所帮助。瑞斯拜。