c++ - 为什么在评估多项式时horners方法没有溢出
问题描述
评估多项式
基本上我正在使用以下公式计算字符串的哈希值。
我正在评估多项式,并且我正在使用天真的方法评估多项式的天真方法是逐项评估所有项。首先计算 x^n,将该值与 cn 相乘,对其他项重复相同的步骤并返回总和。使用以下算法
struct hashFunction {
std::size_t operator() (const std::string& str) const {
unsigned int uiHashValue = 0;
unsigned int uiPowerValueIdx = 0;
std::uint64_t uiSum = 0;
for(unsigned int uiIdx = 0; uiIdx < str.length(); uiIdx++, uiPowerValueIdx++) {
unsigned int uiCharAsciiVal = (str[uiIdx]);
// calculate power of x ^ uiPowerValue
std::uint64_t uiXToPowerValue = 1;
std::uint64_t uiIntermediateValue = uiXValue;
unsigned int uiPowerValue = uiPowerValueIdx;
std::cout << uiIdx << " char is " << str[uiIdx] << " ascii value " << uiCharAsciiVal ;
while(uiPowerValue > 0) {
// if power value is multiply x value with intermediate value
if((uiPowerValue & 1) == 1) {
uiXToPowerValue = ((uiXToPowerValue % uiLargePrime) * (uiIntermediateValue %uiLargePrime)) %uiLargePrime ;
}
uiPowerValue = uiPowerValue >> 1;
uiIntermediateValue = ((uiIntermediateValue % uiLargePrime) * (uiIntermediateValue % uiLargePrime)) % uiLargePrime;
}
std::cout << " power value " << uiXToPowerValue<< std::endl;
uiSum = uiSum + (((uiCharAsciiVal % uiLargePrime )* (uiXToPowerValue % uiLargePrime)))%uiLargePrime;
} // for loop
std::cout << (uiSum % uiMValue) << std::endl;
return uiSum % uiMValue;
}
};
现在使用horners方法我计算如下
struct hashFunctionNew {
std::size_t operator() (const std::string& str) const {
unsigned int uiHashValue = 0;
unsigned int uiPowerValueIdx = 0;
std::uint64_t uiSum = 0;
std::uint64_t ans = 0;
for( int uiIdx = str.length(); uiIdx >= 0; uiIdx--) {
unsigned int uiCharAsciiVal = (str[uiIdx]);
ans = (ans * uiXValue +uiCharAsciiVal) % uiLargePrime;
}
std::cout << "New function hash value: " << ans % uiMValue << std::endl;
return ans % uiMValue;
}
};
我的问题如下
- 为什么 Horners 方法没有溢出,虽然这里我们也计算 x^n,而在朴素方法中存在溢出。在这两种方法中,我都使用 mod 运算符来避免溢出,所以在幼稚的方法中也不应该溢出。
- 我天真的方法返回错误的哈希值?我调试但不确定为什么我得到错误的值。例如,“世界”的哈希值为 4,但天真的方法返回 1。什么是错误?
谢谢您的帮助。
解决方案
您的两个问题的答案都在这一行:
uiSum = uiSum + (((uiCharAsciiVal % uiLargePrime )* (uiXToPowerValue % uiLargePrime)))%uiLargePrime;
这就是溢出发生的地方。你也需要在这里取模。
uiSum = (uiSum + (((uiCharAsciiVal % uiLargePrime )* (uiXToPowerValue % uiLargePrime)))%uiLargePrime) % uiLargePrime;
推荐阅读
- c# - TryParse 从字符串到浮点数不给出结果
- c# - 如何计算文本框中的数学运算?
- javascript - 向图像添加文本 VueJS
- javascript - 扩展运算符 + keys() 方法:添加附加值
- python - TypeError: __init__() 接受 2 个位置参数,但给出了 4 个
- bluetooth - windows ble 界面 - HCI_VS_MSFT_LE_Monitor_Advertisement 示例?
- python - 使用 Tensorflow Slim 重现 TensorFlow Hub 模块输出
- matlab - 30分钟后Matlab崩溃
- java - System.currentTimeMillis() 方法:返回巨大的执行时间值,然后是实际执行时间
- scala - 如何解决scala中的错误“类型不匹配,预期:_$1,实际:任何”?