[英]Restore a number from several its remainders (chinese remainder theorem)
我有一個長整數,但它不是以十進制形式存儲,而是存儲為余數。
所以,我沒有N
號碼,而是有這樣的余數:
r_1 = N % 2147483743
r_2 = N % 2147483713
r_3 = N % 2147483693
r_4 = N % 2147483659
r_5 = N % 2147483647
r_6 = N % 2147483629
我知道,N小於這些素數的乘法,所以中文余數定理在這里起作用( http://en.wikipedia.org/wiki/Chinese_remainder_theorem )。
如果我有這6個剩余部分,如何以十進制恢復N
? 精彩的將是任何程序(C / C + GMP / C ++ / perl / java / bc)。
例如,最小N可以有這組余數:
r_1 = 1246736738 (% 2147483743)
r_2 = 748761 (% 2147483713)
r_3 = 1829651881 (% 2147483693)
r_4 = 2008266397 (% 2147483659)
r_5 = 748030137 (% 2147483647)
r_6 = 1460049539 (% 2147483629)
您鏈接的文章已經提供了一個建設性的算法來找到解決方案 。
基本上,對於每個i
,求解整數方程ri*ni + si*(N/ni) = 1
,其中N = n1*n2*n3*...
ri
和si
在這里是未知的。 這可以通過擴展的歐幾里德算法來解決。 它非常受歡迎,您可以在任何語言中查找示例實現。
然后,假設ei = si*(N/ni)
,答案是每個i
sum(ei*ai)
。
所有這些都在該文章中進行了描述,並附有證據和示例。
這里是代碼(C + GMP),基於BenLen blynn @ github的 LGPL代碼; 加納算法的stanford (通過查詢garner mpz_t找到RIP谷歌代碼搜索): https : //github.com/blynn/pbc/blob/master/guru/indexcalculus.c (他的部分PBC(基於配對的加密)圖書館)
使用gcc -std=c99 -lgmp
編譯。 還可以根據您的情況更改大小。
#include <gmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
// Garner's Algorithm.
// See Algorithm 14.71, Handbook of Cryptography.
// x - result v residuals m - primes t-size of vectors
static void CRT(mpz_t x, mpz_ptr *v, mpz_ptr *m, int t) {
mpz_t u;
mpz_t C[t];
int i, j;
mpz_init(u);
for (i=1; i<t; i++) {
mpz_init(C[i]);
mpz_set_ui(C[i], 1);
for (j=0; j<i; j++) {
mpz_invert(u, m[j], m[i]);
mpz_mul(C[i], C[i], u);
mpz_mod(C[i], C[i], m[i]);
}
}
mpz_set(u, v[0]);
mpz_set(x, u);
for (i=1; i<t; i++) {
mpz_sub(u, v[i], x);
mpz_mul(u, u, C[i]);
mpz_mod(u, u, m[i]);
for (j=0; j<i; j++) {
mpz_mul(u, u, m[j]);
}
mpz_add(x, x, u);
}
for (i=1; i<t; i++) mpz_clear(C[i]);
mpz_clear(u);
}
const int size=6; // Change this please
int main()
{
mpz_t res;
mpz_ptr t[size], p[size];
for(int i=0;i<size;i++) {
t[i]=(mpz_ptr)malloc(sizeof(mpz_t));
p[i]=(mpz_ptr)malloc(sizeof(mpz_t));
mpz_init(p[i]);
mpz_init(t[i]);
}
mpz_init(res);
for(int i=0;i<size;i++){
unsigned long rr,pp;
scanf("%*c%*c%*c = %lu (%% %lu)\n",&rr,&pp);
printf("Got %lu res on mod %% %lu \n",rr,pp);
mpz_set_ui(p[i],pp);
mpz_set_ui(t[i],rr);
}
CRT(res,t,p,size);
gmp_printf("N = %Zd\n", res);
}
示例已解決:
$ ./a.out
r_1 = 1246736738 (% 2147483743)
r_2 = 748761 (% 2147483713)
r_3 = 1829651881 (% 2147483693)
r_4 = 2008266397 (% 2147483659)
r_5 = 748030137 (% 2147483647)
r_6 = 1460049539 (% 2147483629)
Got 1246736738 res on mod % 2147483743
Got 748761 res on mod % 2147483713
Got 1829651881 res on mod % 2147483693
Got 2008266397 res on mod % 2147483659
Got 748030137 res on mod % 2147483647
Got 1460049539 res on mod % 2147483629
N = 703066055325632897509116263399480311
N是703066055325632897509116263399480311
這是一個Python 3實現,基於此Rosetta Code任務: https : //rosettacode.org/wiki/Chinese_remainder_theorem
from functools import reduce
from operator import mul
def chinese_remainder(n, a):
"""
Chinese Remainder Theorem.
:param n: list of pairwise relatively prime integers
:param a: remainders when x is divided by n
"""
s = 0
prod = reduce(mul, n)
for n_i, a_i in zip(n, a):
p = prod // n_i
s += a_i * inverse(p, n_i) * p
return s % prod
def inverse(a, b):
"""
Modular multiplicative inverse.
"""
b0 = b
x0, x1 = 0, 1
if b == 1:
return 1
while a > 1:
q = a // b
a, b = b, a % b
x0, x1 = x1 - q * x0, x0
if x1 < 0:
x1 += b0
return x1
n = [2147483743, 2147483713, 2147483693, 2147483659, 2147483647, 2147483629]
a = [1246736738, 748761, 1829651881, 2008266397, 748030137, 1460049539]
print(chinese_remainder(n, a)) # 703066055325632897509116263399480311
Python的一個很好的特性是它自然地支持任意大的整數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.