我需要用C语言计算一个#localhost
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot "C:/xampp/htdocs/"
ServerName localhost
ServerAlias www.localhost
ErrorLog "logs/localhost-error.log"
CustomLog "logs/localhost-access.log" common
</VirtualHost>
#subdomain
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot "C:/xampp/htdocs/subdomain"
ServerName subdomain.localhost
ServerAlias www.subdomain.localhost
ErrorLog "logs/localhost-error.log"
CustomLog "logs/localhost-access.log" common
</VirtualHost>
函数,其中除数q被确定为非常大(15,383,399,235,709,406,497),指数n 可能也是如此。 / p>
基于模乘的属性a^n mod q
,我的尝试如下:
(a * b) mod n = ((a mod n) * (b mod n)) mod n
从上面的主要函数中可以看出,我使用基数3,指数(189 + 50 * 223)和除数15383399235709406497测试了modExp函数。它为输出#include <stdio.h>
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
unsigned long long int cnt;
for (cnt=expo; cnt>0; cnt--)
{
out = (out * base) % mod;
}
return out;
}
int main()
{
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
return 0;
}
给出了一些警告,
3915400295876975163
为验证此答案,我将结果(由C函数提供)与通过评估用Haskell编写的表达式In function ‘findxA’:
findxA.c:17:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:17:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int h = 12036625823877237123;
^
findxA.c:18:32: warning: integer constant is so large that it is unsigned [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c:18:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
unsigned long long int q = 15383399235709406497;
^
findxA.c: In function ‘main’:
findxA.c:34:48: warning: integer constant is so large that it is unsigned [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
findxA.c:34:5: warning: this decimal constant is unsigned only in ISO C90 [enabled by default]
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
^
给出的输出进行了比较。该Haskell表达式的计算结果为不同的十进制3^(189 + 50 * 223) `mod` 15383399235709406497
。我认为这是我的C函数错了,因为我相信Haskell在处理如此大的小数方面做得更好。
如何改善C函数modExp?
编辑:我尝试使用the first answer of this question.选项,但是由于我试图处理unsigned long long int的小数,因此我将每个输入和返回类型都从int切换了为unsigned long long int。这导致了细分错误。
Edit2 :我以错误的方式使用了上面链接中描述的功能。它不会产生细分错误;但它仍无法输出正确的小数。
答案 0 :(得分:1)
要减少溢出的机会,可以依靠unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int baseMod = base%mod;
unsigned long long int out = 1;
unsigned long long int cnt;
for (cnt=expo; cnt>0; cnt--)
{
out = ( (out%mod) * baseMod) % mod;
}
return out;
}
。
例如(未试用):
x ** 5 == 1*(x**4) * 0*(x**2) * 1*(x**1)
还请注意,幂运算可以作为“平方积”更有效地完成。例如,5 == 1*4 + 0*2 + 1*1
是因为5 == 101b
(或unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
unsigned long long int temp = base%mod;
while(exp0 > 0) {
if( (exp0 & 1) != 0) {
out = (out * temp) % mod;
}
temp = (temp*temp) % mod;
exp0 >>= 1;
}
return out;
}
)。
例如(未试用):
modExp()
对于大指数,这应该会在性能上产生巨大差异(例如,如果指数为123456,则该循环将具有17次迭代,而不是123456次迭代)。
也;如果这是用于某种加密技术(并非不可能);那么您应该清楚地说明这一点,因为您可能希望使用“恒定时间”(以减少计时副通道的机会-例如,从执行unsigned long long
所需的时间中推断出有关指数的信息)。
最后;即使进行了更改,对于mod * mod <= ULLONG_MAX
来说,最大数量为15,383,399,235,709,406,497的数字可能仍然太大(您需要确保typedef struct { uint32_t digit[4]; } MY_NUMBER_TYPE
);这意味着您可能需要使用/实现“大整数”运算(例如,Table 1
id details
1 abc
2 def
3 xyz
Table 2
id details
1 rst
1 uvw
东西可以处理128位整数,并具有乘法和模运算功能)。
答案 1 :(得分:-1)
这将永远不会这样!
仅在这里乘法的结果
out = (out * base) % mod;
可能需要比基础数据类型的64位更多的位。而且,如果发生整数溢出(即最高有效位被切除),则mod操作结果是错误的!
使用较大的数据类型,或使用其他方法:-)
顺便说一句,顺便说一句,请使用以下测试代码来查看输入中实际上发生了两次整数溢出:
#include <stdio.h>
unsigned long long int modExp(unsigned long long int base, unsigned long long int expo, unsigned long long int mod)
{
unsigned long long int out = 1;
while(expo>0)
{
if(expo % 2 == 1)
out = (out * base) % mod;
expo = expo >> 1;
if (base * base < base) printf("WARNING! INTEGER OVERFLOW!!!!\n");
base = (base * base) % mod;
}
return out;
}
int main()
{
printf("%llu", modExp(3, (189 + 50 * 223), 15383399235709406497));
return 0;
}