4

使用 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

我不知道这是什么原因,它在我的程序中产生了一些丑陋的错误。任何见解将不胜感激。提前致谢。

4

2 回答 2

3

所以当我输出这样的第一个结果时:

std::cout << std::fixed << x << std::endl << y << std::endl;

我看到这个:

2138415301692701661114266637060519453227273059369895888628790658837784821760.000000
206.000000

当我将上面的这个数字用于xs 值时,如下所示:

double y = fmod(2138415301692701661114266637060519453227273059369895888628790658837784821760.000000, 221);

然后我从第一个示例中得到206for的结果y,主要问题是您使用IEEE double达到了限制。

更新

该算法用于模块化电源

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;
}

我从这里找到的会给你正确的结果。

于 2014-03-28T03:15:23.323 回答
0

这里有几个问题。

首先,您的 print 语句会截断实际值。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 提供机械手。

其次,由于 double 的精度不足,即使上面打印的值也不正确。IEEE double 使用 52 位来存储尾数。这对于 15 到 17 位的精度来说已经足够了。您需要使用任意精度计算器来确定实际结果(例如,bc 命令行实用程序)。

% bc
142^35
2138415301692701650291828893190357329823022421032574372998179511073104723968
(142^35)%221
12

查看这两个值,前 17 位数字符合预期。

有关IEEE 双精度限制的更多详细信息,请参见http://en.wikipedia.org/wiki/Double-precision_floating-point_format 。

于 2014-03-28T03:46:28.070 回答