【问题标题】:std::pow with integer parameters, comparing to an integer type带有整数参数的 std::pow,与整数类型相比
【发布时间】:2014-11-15 01:35:56
【问题描述】:

根据http://en.cppreference.com/w/cpp/numeric/math/pow,当std::pow与整数参数一起使用时,结果将提升为double

我的问题如下:

将整数类型与std::pow(int1, int2) 的结果进行比较有多安全? 例如,下面的if 可以评估为真吗?

std::size_t n = 1024;
if(n != std::pow(2, 10))
    cout << "Roundoff issues..." << endl;

也就是说,rhs 上的结果是否可能是 1023.99...9 这样转换为 size_t 时变为 1023?

我的猜测是,响应中的一个很大的 NO,但想知道肯定。在检查矩阵等的维度时,我正在使用这些比较,并且我不想在任何地方使用std::round

【问题讨论】:

  • 2、10 和 1024 都可以用double 完美表示。只要输入和输出适合 53 位(假设 IEEE-754 double),您应该没问题
  • @Praetorian 你应该告诉 user1257。 stackoverflow.com/questions/15851636/is-this-a-g-bug
  • @PascalCuoq 这很有趣,也很可怕。我无法在 gcc4.4.7、4.8、4.9 或 MinGW gcc4.9 上重现它;但最好能意识到这个问题。谢谢。
  • 所以我想最安全的选择是在分配给整数类型之前使用std::lround。谢谢大家的回答!

标签: c++ c++11 floating-point floating-point-conversion


【解决方案1】:

你应该问这很有趣,因为someone else on StackOverflow 有一个问题是因为pow 应用于小整数并没有在他们的平台上计算出明显的结果(另见我的writeup)。

所以是的,当将pow 应用于小整数时,参数和理想的数学结果都可以精确表示。这并不强制exp 的实现返回数学结果,因为没有标准规定pow 不能有多个ULP 不准确。并且至少有一个非常流行的平台默认提供了一个pow 函数,它不会将pow(10, 2) 计算为100,但您可以随意尝试pow(2, N),也许它总是会返回您有权获得的整数期待。

【讨论】:

  • 除非你永远不应该使用pow(2, N),因为ldexp(1, N)更好(更快并保证准确的结果)
  • @BenVoigt 很高兴知道,谢谢,尽管我以 2^N 为例。实际上我使用的是 D^N,其中 D 可以是任何整数,而不仅仅是 2。
【解决方案2】:

pow 当结果完全可表示时,在整数参数上应该始终为您提供正确的答案。问题是,它没有。有现代平台(许多 Linux 发行版,例如,旧的和最近的),但它没有。找到一堆 SO 问题并不难,人们给 pow 提供了非常好的输入,但它返回了一个可怕的错误答案。

【讨论】:

    【解决方案3】:

    对于该特定示例,它应该始终返回 false,尤其是因为您使用的是 int 类型,因此不会出现舍入错误。

    当您比较两个不同的算术函数时,您需要对舍入误差保持谨慎,这些算术函数返回浮点数或带长小数的双精度数。很多时候,由于发生了不同的舍入和不同的操作,它们会返回不相等。

    【讨论】:

      【解决方案4】:

      正如几个答案所指出的那样,即使对于少量的结果应该是完全可表示的,但仍有一些低质量的实现。

      对于您使用 const 表达式 的情况,例如:

      std::pow(2, 10)
      

      许多编译器将使用builtin functions,例如gccclang 都将使用内置函数,这些函数可能会使用查找表或更简单的公式来处理这些琐碎的情况。对于上述使用godbolt 的情况,我们可以看到gcc 在编译时计算值:

      movl    $1024, %esi     
      

      正如问题C: i got different results with pow(10,2) and pow(10,j), j=2; 所展示的那样,这些结果更有可能是正确的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-19
        • 2013-08-19
        • 2021-12-03
        • 2011-12-16
        • 1970-01-01
        • 2014-04-19
        • 2013-02-13
        相关资源
        最近更新 更多