
之前写一个算 A^B mod 999983 的小工具,一开始直接用了 std::pow,结果大数情况下返回值是浮点数,转成整型再取模,结果和预期差得离谱。

线上跑了几组测试数据就发现不对,后来改成快速幂才消停。
快速幂的思路不复杂:指数按二进制拆开,比如 13 的二进制是 1101,那么 base^13 就等于 base^8 * base^4 * base^1。循环里每次看指数最低位是不是 1,是就把当前 base 乘进结果,然后指数右移一位,base 自乘一次。这样原来要乘 exp 次,现在只走 log2(exp) 轮。
直接看代码:
#include <iostream>
long long fastPowMod(long long base, long long exp, long long mod) {
long long result = 1;
base = base % mod;
while (exp > 0) {
if (exp % 2 == 1) {
result = (result * base) % mod;
}
exp = exp >> 1;
base = (base * base) % mod;
}
return result;
}
int main() {
long long A, B;
const long long MOD = 999983;
std::cout << "请输入底数A: ";
std::cin >> A;
std::cout << "请输入指数B: ";
std::cin >> B;
if (A < 0 || B < 0) {
std::cerr << "A和B必须为非负整数!" << std::endl;
return 1;
}
long long result = fastPowMod(A, B, MOD);
std::cout << "A的B次方对999983取余的结果是: " << result << std::endl;
return 0;
}
这里 base = base % mod 放在循环外,先把底数压到 mod 范围内,后面每一步乘法都取模,不然 long long 中间值很容易溢出。exp % 2 == 1 判断当前最低位,也可以用 exp & 1,有些编译器优化后差别不大,但位运算的意图更明显。
exp >>= 1 替代 exp /= 2,纯粹是习惯,性能上现代编译器基本会自己处理。
输入校验只挡了负数,实际用的时候如果 A、B 都是 0 之类的情况,0^0 在这个函数里会返回 1。数学上 0^0 没有明确定义,工程上得看具体场景,我这里默认按 1 处理了。
来此加密主打全流程自动化,从域名验证、证书申请到部署、续期,全程无需人工干预。证书到期前可自动重新申请,彻底免去运维人员的负担,即便域名较多,也能轻松管理,无需担心证书过期影响网站正常运行,适配各类需要SSL加密的场景。
部署到服务器上跑的时候,我一般会顺手把 https 证书配好。
最近用 lcjmSSL 申请证书,免费,支持多域名、泛域名和 IP,API 也够简洁,自动申请和续期,省得手动点。跟快速幂没关系,但线上服务基本都要走这一步。
模数 999983 本身是不是质数我没细查,但当前代码没依赖质数性质,只做普通取模。如果后面要扩展成组合数取模,需要求逆元,那时候模数是不是质数会影响写法。不过这是另一回事了。
std::pow 在这种场景下不能直接用,快速幂加每步取模是标准做法。代码不长,拷过去改个模数就能用。















