考虑以下代码:
#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)中的错误吗?
答案 0 :(得分:10)
std::pow()
使用浮点数,它没有无限的精度,可能你正在使用的标准库的实现以(差)方式实现pow()
,这使得这种无限的缺乏精确度变得相关。
但是,您可以轻松定义适用于整数的自己的版本。在C ++ 11中,您甚至可以使它constexpr
(以便在可能的情况下在编译时计算结果):
constexpr int int_pow(int b, int e)
{
return (e == 0) ? 1 : b * int_pow(b, e - 1);
}
这是live example。
尾递归表格(Dan Nissenbaum的积分):
constexpr int int_pow(int b, int e, int res = 1)
{
return (e == 0) ? res : int_pow(b, e - 1, b * res);
}
答案 1 :(得分:4)
到目前为止,所有其他答案都错过或围绕问题中唯一的问题跳舞:
C ++实现中的pow
质量很差。如果不需要,它会返回一个不准确的答案。
获得更好的C ++实现,或者至少替换其中的数学函数。 one pointed to by Pascal Cuoq很好。
答案 2 :(得分: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
。
来自http://www.cplusplus.com/reference/cmath/pow/
的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
。
答案 3 :(得分:3)
你的问题不是gcc中的错误,这绝对是肯定的。它可能是pow
实现中的一个错误,但我认为你的问题实际上只是因为你使用的pow
给出了一个不精确的浮点结果(因为它的实现类似于{ {1}}和exp(power * log(base));
永远不会绝对准确[除非基数是e的力量]。
答案 4 :(得分:3)
如果你只是写
#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之后你将在全球范围内拥有pow功能。
请记住,所有重载至少都在std
命名空间中。有pow
函数采用整数指数,并且有pow
函数采用浮点指数。您的C ++实现很可能只在全局范围内声明C pow函数。此函数采用浮点指数。问题是这个函数可能有一些近似和舍入误差。例如,实现该功能的一种可能方式是:
double pow(double base, double power)
{
return exp(log(base)*power);
}
由于舍入和逼近误差,很可能pow(10.0,2.0)产生类似99.99999999992543453265的东西。结合浮点到整数转换产生小数点前的数字的事实,这解释了你的结果122,因为99 + 3 = 122。
尝试使用pow的重载,它采用整数指数和/或从float到int进行适当的舍入。采用整数指数的重载可能会给出10到2次幂的确切结果。
编辑:
正如您所指出的,尝试使用std :: pow(double,int)重载似乎也会产生略低于100的值。我花时间检查ISO标准和libstdc ++实现以查看从C ++ 11由于解析defect report 550而导致整数指数的重载被删除。启用C ++ 0x / C ++ 11支持实际上删除了libstdc ++实现中的重载,这可以解释为什么你没有看到任何改进。
无论如何,依赖这种函数的准确性可能是一个坏主意,尤其是涉及转换为整数时。如果您期望浮点值是一个整数(如100)然后将其转换为int类型值,则向零的轻微错误显然会产生很大的差异。所以我的建议是编写你自己的pow函数,它采用所有整数或者使用你自己的round函数对double-gt; int转换特别小心,这样零的小错误就不会改变结果。