【问题标题】:Modulo operation on power function幂函数的模运算
【发布时间】:2020-05-14 15:53:38
【问题描述】:

我在对幂函数执行模运算时遇到此错误。

 invalid operands of types ‘int’ and ‘__gnu_cxx::__promote_2<int, int, double, double>::__type {aka double}’ to binary ‘operator%’

这是我的一段代码。

#include <bits/stdc++.h>
using namespace std;

int main() {
  int t, n;
  cin >> t;
  int i, j, sum = 0;
  for (i = 0; i < t; i++) {
    cin >> n;
    for (j = 1; (n % pow(5, j)) == 0; j++)
      sum = sum + (n / pow(5, j));
    cout << sum;
  }
  return 0;
}

【问题讨论】:

标签: c++ c++14


【解决方案1】:

pow 返回一个 double,模只能对 int 进行运算。加入一些解释变量,这将变得更加明显。代码也将更具可读性和性能。

【讨论】:

  • 我已经编辑了问题,并添加了完整的代码sn-p
  • 类型不必是int。它必须是任何整数/枚举类型。
【解决方案2】:

就像@Keynan 提到的那样,pow 返回一个double,而% 要求参数是int。要使其正常工作,您可以使用 static_cast 或 C 样式转换将结果转换为 int。

// static_cast
for (j = 1; (n % static_cast<int>(pow(5, j))) == 0; j++)
// c-style cast
for (j = 1; (n % (int)pow(5, j)) == 0; j++)

相关链接:

【讨论】:

  • 类型不必是int。它必须是任何整数/枚举类型。将pow 的结果转换为int 也不是好的建议。结果可能无法在double 中准确表示,pow 可能会累积错误,因此结果可能与数学预期的结果不同。
  • 不考虑隐式转换(double 将隐式转换为int)。见timsong-cpp.github.io/cppwp/n4659/expr.mul#2。我会写一个整数pow(参见stackoverflow.com/questions/101439/…),或者在这种特殊情况下根本不使用pow。 5在n的素数分解中的多重性可以通过简单的重复除法/模数5来计算。
  • 将pow 结果转换为int 不是一个好的解决方案。使用pow 既浪费又存在问题(包括因为在可能得到精确结果的情况下,有些糟糕的实现会返回不精确的结果,有时会导致转换为int 产生的结果低于预期)。相反,应该将此代码更改为使用简单的整数乘法或除法,而不是 pow。
  • @EricPostpischil 我明白你的意思。但即使是简单的整数乘法,你仍然需要检查结果是否溢出int,对吧?
  • @Maverobot:不,不是在正确编写代码时。可以重复将n 除以 5,而不是使用 5 的递增幂,这样就不会溢出。
【解决方案3】:

错误的类型

编译器错误消息是因为pow 例程例程使用double 类型,但% 运算符只接受整数操作数。

pow 是一个用于求幂的诱人例程,但它返回浮点类型,您通常不应混合使用浮点和整数运算,原因包括:

  • 在使用浮点运算时存在相当多的问题和微妙之处,包括处理舍入错误的问题。
  • pow 的某些实现存在缺陷,因为当精确答案可以在 double 类型中表示时,它们会返回不精确的答案。例如,pow(5, 3) 可能会返回一个略低于 125 的数字,然后取一个余数模(或将其截断为整数)不会得到您想要的结果。

更好的方法

解决当前问题的一种方法是将pow 替换为您自己的例程,该例程只需通过重复相乘即可将整数提升为非负整数幂。但是,有更好的方法。更改这两行:

for (j = 1; (n % pow(5, j)) == 0; j++)
    sum = sum + (n / pow(5, j));

到这里:

for (j = 1; n % 5 == 0; j++)
{
    n /= 5;
    sum = sum + n;
}

因此,我们不是重复使用 5 的幂(5、25、125,...)与 n,而是重复将 n 除以 5。

其他问题

如果pow 返回整数类型,这些更改将提供代码执行您问题中的代码所执行的操作,以防溢出。但是,我怀疑您的代码中还有其他问题,它无法计算出您想要的结果。

我认为你的任务很可能是编写一个程序来计算 n 中尾随零的数量! (n 阶乘) 以十进制书写。 n 中尾随零的数量!是除以 n! 的 10 的最大幂的指数。此功效由可用的 5 因子决定,因为每个尾随的零都需要 n! 中的因子 2 和因子 5(使 10),但它受到因子的约束5,因为 2 的因数很多。

因此,1!、2!、3! 和 4!没有尾随零,因为它们没有因子 5. 5!有一个尾随零,6!、7!、8! 和 9! 也是如此。然后10!有两个尾随零,正如我们所见,因为 1•2•3•4•5•6•7•8•9•10 有两个因数 5。尾随零在 15 处增加到 3! 20 岁时有四个!到目前为止,n! 的尾随零的数量!为 n/5,截断为整数。然后,在 25! 处,我们添加的不是一个,而是两个 5,因为 25 是 52。现在尾随零的数量不是 n/5 而是 n/5 + n/5/5。经过一番思考,我们可以看到,一般来说,n! 的尾随零的数量!是 n/5 + n/5/5 + n/5/5/5 + n/5 /5/5/5 + ...,在项达到零的地方结束。

如果您的程序在 n / 5j 不为零而不是 n 模 5j 为零,它会计算这个总和。您的程序与此计算的相似性使我怀疑这是意图。如果是这样,请将这些行更改为:

for (j = 1; 0 < n; j++)
{
    n /= 5;
    sum = sum + n;
}

(为了简单起见,我这样表述,但我们也可以看到,如果 n 0 < n 到 5 &lt;= n。)

此外,读取新的n 时不会重置总和。在第一个for循环之前删除sum的声明,并在第一个for之后和second之前插入int sum = 0;。

一般来说,最好不要在需要之前声明它们。因此,从main 的顶部删除n 的声明,并将其放在第一个for 之后。在for循环之前删除i和j的声明,并在其for循环中定义每一个:for (int i = 0; i &lt; t; i++)和for (int j = 1; 5 &lt;= n; j++)。

在cout &lt;&lt; sum; 中,您可能需要换行符:cout &lt;&lt; sum &lt;&lt; '\n'; 或cout &lt;&lt; sum &lt;&lt; std::endl;。

Do not include &lt;bits/stdc++.h&gt;. 而是包含标准标头,例如此程序的&lt;iostream&gt;。

避免使用using namespace std;。在你的代码中使用std::(例如,std::cin而不是cin),即使它需要更多的输入或者选择性地从命名空间中获取一些特定的东西,例如using std::cin;整个命名空间。虽然这最初需要更多的工作,但它避免了程序并训练您更好地了解您的程序正在使用什么。

【讨论】:

  • 非常感谢您的回答,我喜欢您猜到我遇到的问题,然后帮助我获得了第一次成功提交。这也是我在 Stack 中的第一个问题,我得到的回应是,我现在爱上了这个社区。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2017-04-03
  • 2014-08-21
  • 1970-01-01
  • 2011-01-13
  • 2017-02-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多