为什么我用的std ::战俘给错误的答案整数运算?(Why is my integer math w

2019-08-20 01:13发布

考虑下面的代码:

#include <iostream>
#include <cmath>

int main() {
    int i = 23;
    int j = 1;
    int base = 10;
    int k = 2;
    i += j * pow(base, k);
    std::cout << i << std::endl;
}

情况下输出“122”,而不是“123”。 它是在G ++ 4.7.2(MinGW的,Windows XP中)的错误吗?

Answer 1:

std::pow()的工作原理与浮点数,不具有无限的精度,也可能是标准库的实现您正在使用工具pow()的(差)的方式,使这个缺乏无限精度变得重要。

然而,你可以很容易地定义你自己的版本,与整数工作。 在C ++ 11,你甚至可以让它constexpr (这样的结果可能在编译时能够计算):

constexpr int int_pow(int b, int e)
{
    return (e == 0) ? 1 : b * int_pow(b, e - 1);
}

这是一个活生生的例子 。


尾递归形式(学分丹尼森鲍姆 ):

constexpr int int_pow(int b, int e, int res = 1)
{
    return (e == 0) ? res : int_pow(b, e - 1, b * res);
}


Answer 2:

所有其他的答案为止错过或围绕这一问题的唯一问题舞蹈:

pow在C ++实现的质量不高。 当没有必要返回一个不准确的答案。

得到一个更好的C ++实现,或至少更换其中的数学函数。 在一个由Pascal Cuoq指向性好。



Answer 3:

不与我至少包括:

$ g++ --version | head -1
g++ (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2)

$ ./a.out 
123

IDEone还运行版本4.7.2,并给出123


的签名pow()从http://www.cplusplus.com/reference/cmath/pow/

     double pow (      double base,      double exponent );
long double pow ( long double base, long double exponent );
      float pow (       float base,       float exponent );
     double pow (      double base,         int exponent );
long double pow ( long double base,         int exponent );

你应该设置double base = 10.0;double i = 23.0



Answer 4:

如果你简单的写

#include <iostream>
#include <cmath>

int main() {
    int i = 23;
    int j = 1;
    int base = 10;
    int k = 2;
    i += j * pow(base, k);
    std::cout << i << std::endl;
}

你认为什么是pow应该是指什么? C ++标准甚至不保证其中CMATH你必须在全局范围战俘功能之后。

请记住,所有重载都至少在std命名空间。 还有就是在pow称取整数指数和有功能的pow称取浮点指数函数。 这很可能是你的C ++实现仅声明在全局范围内的C战俘功能。 该函数接受一个浮点指数。 问题是,这个功能很可能有一对夫妇近似和舍入误差。 例如,实现该功能的一种可能的方式是:

double pow(double base, double power)
{
    return exp(log(base)*power);
}

这很可能是战俘(10.0,2.0)产生类似99.99999999992543453265由于四舍五入的原因,并逼近误差。 的事实,浮点到整数转换合并产生小数点前这解释了您的122因为99 + 3 = 122结果的数目。

尝试使用POW的过载它接受一个整数指数和/或从浮做一些适当的四舍五入为INT。 超载将整数指数可能会给你确切的结果为10到第二电源。

编辑:

正如你指出的那样,试图使用的std :: POW(双,INT)超载似乎也产生一个值略少100我把检查ISO标准和的libstdc ++实现的时候,看到那个开头C ++ 11个取整数指数重载已经下降作为解决的结果, 缺陷报告550 。 启用的C ++ 0x / C ++ 11的支持实际上除去了的libstdc ++实现这可以解释为什么你没有看到任何改善的过载。

总之,它可能是一个坏主意,依靠特别是如果到整数转换涉及这样的功能的精确度。 向零略有误差显然有很大的不同,如果你期望一个浮点值,它是一个整数(如100),然后将其转换为int类型值。 所以我的建议是写自己的POW函数,它所有的整数或特别小心对于使用自己的回合功能,使轻微错误torwards零不改变结果的双> INT转换。



Answer 5:

你的问题是不是在gcc的一个bug,那是绝对肯定的。 这可能是在执行中的错误pow ,但我觉得你的问题实在是简单的事实是,你正在使用pow ,因为它是为像实施这给出了一个不精确的浮点结果( exp(power * log(base));log(base)是永远不会绝对准确[除非碱为e的功率。



文章来源: Why is my integer math with std::pow giving the wrong answer?