模幂C ++的问题

问题描述

我正在尝试对大值(最多64位)执行模幂运算,并为此编写了以下函数

uint64_t modularExp(uint64_t num,uint64_t exp,uint64_t mod) 
{
    string expBits = bitset<64>(exp).to_string();   
    expBits = expBits.substr(expBits.find("1")+1);
    
    string operations = "";
    
    uint64_t result = num;
    for (int i = 0; i < expBits.length(); ++i)
    {
        result = (uint64_t)pow(result,2) % mod;
        if (expBits[i] == '1')
            result = (result * num) % mod;
    }   
            
    return result;  
}

这对于较小的数字(8位或更少)有效,但对于较大的数字,即使它们在64位范围内,结果也会显示错误

此外,当mod的值超过4294967296(最大32位值)时,结果仅为零。我怀疑pow函数可能在此问题中起作用,但是我不能确定。

任何建议将不胜感激。

解决方法

首先,一些一般性建议:

  • 使用整数时最好不要使用字符串,因为使用字符串的操作要慢得多,并且可能会成为性能瓶颈。还不清楚当涉及字符串时实际上在做什么。
  • 您不应该将std::pow与整数一起使用,因为它对浮点数进行运算并且会失去精度。

对于主要问题,作为一种解决方法,可以使用此O(log^2(n))解决方案,该解决方案应适用于最大63位的参数(因为它只使用2的加法和乘法)。请注意,如果只是以小到大的顺序遍历位,那么所有这些字符串魔术都是不必要的:

#include <cstdint>

uint64_t modular_mul(uint64_t a,uint64_t b,uint64_t mod) {
    uint64_t result = 0;
    for (uint64_t current_term = a; b; b >>= 1) {
        if (b & 1) {
            result = (result + current_term) % mod;
        }
        current_term = 2 * current_term % mod;
    }
    return result;
}

uint64_t modular_pow(uint64_t base,uint64_t exp,uint64_t mod) {
    uint64_t result = 1;
    for (uint64_t current_factor = base; exp; exp >>= 1) {
        if (exp & 1) {
            result = modular_mul(result,current_factor,mod);
        }
        current_factor = modular_mul(current_factor,mod);
    }
    return result;
}

此外,在gcc中,某些目标可以使用(非标准)__uint128_t。 (可用于将modular_mul替换为普通乘法)