【发布时间】:2021-12-20 00:23:27
【问题描述】:
说明
定义函数
unsigned mod(unsigned a, unsigned b, unsigned c);作用是计算并返回a*b%c的结果。测试a、b、c的范围要求大于0小于2^31,程序不能使用64位整数(如long long类型或__int64)求解。
问题:a*b 可能溢出(超出 32 位 unsigned int 类型的表示范围)。为了解决这个问题,可以使用以下算法。 假设无符号变量b的每个二进制位为xi(i=0,1,…,31),i=0为最低位,i=31为最高位,则
和
上式中,a*xi的结果要么是a要么是0; *2 运算可以通过左移1位来实现(小于2^31的整数 *2 结果必须小于2^32,不会溢出); %c的结果小于c,c小于2^31,和a之和不会溢出。 编写一个完整的程序,通过迭代的方式实现上述算法。
我的代码
#pragma warning(disable:4996)
#include <stdio.h>
unsigned mod(unsigned a, unsigned b, unsigned c) {
unsigned sum = a * ((b >> 30) & 1);
for (int i = 29; i >= 0; i--) {
sum = (sum << 1) % c + a * ((b >> i) & 1);
}
return sum % c;
}
int main() {
//to achieve the subject requirements
unsigned a, b, c;
printf("Input unsigned integer numbers a, b, c:\n");
scanf("%u %u %u", &a, &b, &c);
printf("%u*%u%%%u=%u\n", a, b, c, mod(a, b, c));
//to verify output results
unsigned long long ab, bb, cb;
ab = a;
bb = b;
cb = c;
printf("%llu*%llu%%%llu=%llu", ab, bb, cb, ab * bb % cb);
}
问题
用较小的数字(如 100*500/3)进行计算时,结果是正确的。但是当数字接近问题的上限时(如2147483647*2147483647/3),你会得到错误的答案。我不知道这是为什么,因为我只是根据问题中给出的公式进行编程,我不知道数学原理。
【问题讨论】:
-
中间结果到底在什么时候不符合预期?
-
删除所有这些整数类型,只使用 stdint.h 中的
uint64_t。