使用 cmath 的 fmod (C++) 时的不一致
Posted
技术标签:
【中文标题】使用 cmath 的 fmod (C++) 时的不一致【英文标题】:Inconsistencies when using cmath's fmod (C++) 【发布时间】:2014-03-28 03:03:24 【问题描述】:使用 fmod 函数时,我得到了一些非常令人困惑的结果。
以下代码:
double x = pow(142, 35);
double y = fmod(x, 221);
std::cout << x << std::endl << y;
输出:
2.13842e+75
206
但是当对 x 值进行硬编码时:
double x = pow(142, 35);
double y = fmod(2.13842e+75, 221);
std::cout << x << std::endl << y;
输出改为:
2.13842e+75
14
我不知道这是什么原因,它在我的程序中产生了一些丑陋的错误。任何见解将不胜感激。提前致谢。
【问题讨论】:
使用模块化幂算法更新答案,应该可以解决您的问题。 【参考方案1】:所以当我像这样输出第一个结果时:
std::cout << std::fixed << x << std::endl << y << std::endl;
我看到了:
2138415301692701661114266637060519453227273059369895888628790658837784821760.000000
206.000000
当我将上面的这个数字用于x
s 值时,如下所示:
double y = fmod(2138415301692701661114266637060519453227273059369895888628790658837784821760.000000, 221);
然后我从第一个示例中得到206
for y
的结果,主要问题是您使用IEEE double 达到了限制。
更新
此算法适用于modular power:
template <typename T>
T modpow(T base, T exp, T modulus)
base %= modulus;
T result = 1;
while (exp > 0)
if (exp & 1) result = (result * base) % modulus;
base = (base * base) % modulus;
exp >>= 1;
return result;
我从here 找到的内容将为您提供正确的结果。
【讨论】:
那时我很困惑。如果您在 wolfram alpha 中键入 142^35 mod 221,则结果为 12。我猜 14 不是我之前提到的所需结果。该代码用于 RSA 解密,因此结果应该在 0 到 25 之间,并且对应于一个字母字符。 12 是正确答案。即使是双精度数也不足以容纳答案。 142^35的实际值为2138415301692701650291828893190357329823022421032574372998179511073104723968;只有前 17 位数字匹配。您需要一个任意精度的计算器,例如 Linux 上的 bc 才能正确执行计算。 @esorton 我只是在检查,这是我的怀疑 @legends2k 似乎和它通常用于 RSA,这是 OP 使用它的目的,请参阅 Wikipedia article on it。 是的,我不知道这个,谢谢!而不是首先计算功率(这将导致本机数据类型溢出)然后尝试修改它,这两者都在限制范围内,很高兴知道:)【参考方案2】:这里有几个问题。
首先,您的打印语句会截断实际值。 C++ 的默认值 cout 的精度为 6。它只会打印 6 位小数。就这样 以下两次打印会产生不同的结果,即使它们打印相同 变量:
double x = pow(142, 35);
std::cout << x << std::endl << y;
// prints 2.13842e+75
std::cout << std::fixed << x << std::endl << y << std::endl;
// prints 2138415301692701661114266637060519453227273059369895888628790658837784821760.0000000
请注意,std::fixed 操纵器用于更改输出。谢谢 @Shafik Yaghmour 提供了机械手。
第二,即使上面打印的值也不正确,因为精度不够
双的。 IEEE double 使用 52 位来存储尾数。这是
足以达到 15 到 17 位的精度。您需要使用仲裁
精度计算器来确定实际结果(例如,bc
命令行实用程序)。
% bc
142^35
2138415301692701650291828893190357329823022421032574372998179511073104723968
(142^35)%221
12
查看这两个值,前 17 位数字符合预期。
见http://en.wikipedia.org/wiki/Double-precision_floating-point_format 有关 IEEE double 限制的更多详细信息。
【讨论】:
以上是关于使用 cmath 的 fmod (C++) 时的不一致的主要内容,如果未能解决你的问题,请参考以下文章
double long float类型读入读出 double取模 fmod