[英]Modulo division returning negative number
我正在C程序中执行以下模除法运算:
(5 ^ 6)mod 23 = 8
(5 ^ 15)mod 23 = 19
为了方便起见,我使用以下功能:
int mod_func(int p, int g, int x) {
return ((int)pow((double)g, (double)x)) % p;
}
但是调用该函数时的操作结果不正确:
mod_func(23, 5, 6) //returns 8
mod_func(23, 5, 15) //returns -6
模运算符是否对操作数的大小有一定限制?
的整数部分pow(5, 15)
不处于表示的int
(假设的宽度int
是32位)。 转换(在double
转换表达式中从double
到int
)是C和C ++中未定义的行为。
为避免未定义的行为,应使用fmod
函数执行浮点余数运算。
5的幂15是30,517,578,125
您可以在int
存储的最大值是2,147,483,647
您可以使用64位整数,但要注意,最终从double
转换时会出现精度问题。
从内存来看,数论中有一条关于您正在执行的计算的规则,这意味着您无需计算整个功率扩展即可确定模结果。 但是我可能是错的。 自从我学到这些东西以来已经有很多年了。
啊,这是: 模幂
阅读该内容,并停止使用double
和pow
=)
int mod_func(int p, int g, int x)
{
int r = g;
for( int i = 1; i < x; i++ ) {
r = (r * g) % p;
}
return r;
}
我的猜测是问题是5 ^ 15 = 30517578125,它大于INT_MAX
(2147483647)。 您当前正在将其强制转换为int
,这是失败的。
如前所述,您的第一个问题
int mod_func(int p, int g, int x) {
return ((int)pow((double)g, (double)x)) % p;
}
是pow(g,x)
通常超出int
范围,然后您将其结果转换为int
行为未定义,并且无论所得int
是什么,都没有理由相信它与所需的模数有关。
下一个问题是pow(g,x)
为double
可能不准确。 除非g
为2的幂,否则即使在一定范围内,数学结果也无法精确表示为足够大的指数的double
,但是如果数学结果可精确表示(取决于pow
的实现),也可能会发生。
如果您进行数论计算-并且以整数为模计算幂的余数为1-您应该仅使用整数类型。
对于手头的情况,可以通过重复平方来使用幂运算,计算所有中间结果的残差。 如果模数p
足够小以至于(p-1)*(p-1)
不会溢出,
int mod_func(int p, int g, int x) {
int aux = 1;
g %= p;
while(x > 0) {
if (x % 2 == 1) {
aux = (aux * g) % p;
}
g = (g * g) % p;
x /= 2;
}
return aux;
}
可以。 如果p
可以更大,则需要使用更大的类型进行计算。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.