我正试图从this (old) implementation on github了解沙米尔秘密分享计划的实施情况,而我正在努力应对霍纳在扩展领域GF(p ^ n)中的统治:
void horner(int n, mpz_t y, const mpz_t x, const mpz_t coeff[])
{
int i;
mpz_set(y, x);
for(i = n - 1; i; i--) {
field_add(y, y, coeff[i]);
field_mult(y, y, x);
}
field_add(y, y, coeff[0]);
}
为什么add
是第一个而且只有mult
?什么是算法?为什么不能这样:
mpz_set(y,coeff[n-1]);
for(i = n - 2; i!=-1; i--) {
field_mult(y, y, x);
field_add(y,y,coeff[i]);
}
答案 0 :(得分:1)
使用正常的加法和乘法符号翻译此horner
函数,我们得到:
y = x; // mpz_set(y, x);
for(i = n - 1; i; i--) {
y = y + coeff[i]; // field_add(y, y, coeff[i]);
y = y * x // field_mult(y, y, x);
}
y = y + coeff[0] // field_add(y, y, coeff[0]);
你可以看到它不计算任何多项式,但它是Horner算法的一种变体来计算monic polynomial。
现在提出建议:
y = coeff[n-1]; // mpz_set(y,coeff[n-1]);
for(i = n - 2; i!=-1; i--) {
y = y * x; // field_mult(y, y, x);
y = y + coeff[i]; // field_add(y,y,coeff[i]);
}
如果你想在循环体内进行所有操作,你可以。 毕竟,只有两种不同方式分解一系列交替指令的方法:
operation value of y loop iteration
add-mult loop mult-add loop
x initialization n-1
add x + coeff[n-1] n-1 n-1
mult (x + coeff[n-1]) * x n-1 n-2
add (x + coeff[n-1]) * x + coeff[n-2] n-2 n-2
mult ((x + coeff[n-1]) * x + coeff[n-2]) * x n-2 n-3
...etc...
但是您需要将y
显式初始化为值1
(隐式coeff[n]
),这样您就可以开始乘以x
并获得正确的结果最高阶词。
y = 1; // mpz_set(y,1);
for(i = n - 1; i!=-1; i--) { // NOTICE n - 1 NOT n - 2
y = y * x; // field_mult(y, y, x);
y = y + coeff[i]; // field_add(y,y,coeff[i]);
}
你可以指望你现在再执行一次乘法,它乘以1 * x
。在有限域上,这通常使用log和antilog表来完成,因此您也可以避免这种无用的乘法,特别是如果您要经常评估多项式。
TL; DR:这种编写Horner算法的方法将最后一次加法和第一次乘法置于循环体之外。因为最高阶系数是1
,所以这个乘法就完全消除了。
澄清:保留最高阶词,但是x^n
而不是1 * x^n
。为完全相同的结果省略一次乘法。