考虑以下代码:
#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)中的错误吗?
考虑以下代码:
#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)中的错误吗?
std::pow()
适用于没有无限精度的浮点数,并且可能您正在使用的标准库的实现pow()
以一种(较差的)方式实现,这使得这种缺乏无限精度变得相关。
但是,您可以轻松定义自己的整数版本。在 C++11 中,您甚至可以制作它constexpr
(以便尽可能在编译时计算结果):
constexpr int int_pow(int b, int e)
{
return (e == 0) ? 1 : b * int_pow(b, e - 1);
}
这是一个活生生的例子。
尾递归形式(归功于Dan Nissenbaum):
constexpr int int_pow(int b, int e, int res = 1)
{
return (e == 0) ? res : int_pow(b, e - 1, b * res);
}
到目前为止,所有其他答案都会错过或围绕问题中唯一的问题:
您的pow
C++ 实现中的质量很差。它在不需要时返回不准确的答案。
获得更好的 C++ 实现,或者至少替换其中的数学函数。Pascal Cuoq 指出的那个很好。
如果你只是写
#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 重载和/或从浮点数到整数进行一些适当的舍入。采用整数指数的重载可能会为您提供 10 的 2 次方的确切结果。
编辑:
正如您所指出的,尝试使用 std::pow(double,int) 重载似乎也产生了一个略小于 100 的值。我花时间检查了 ISO 标准和 libstdc++ 实现,看看从 C++ 开始在图11中,作为解决缺陷报告550的结果,采用整数指数的过载已被丢弃。启用 C++0x/C++11 支持实际上消除了 libstdc++ 实现中的重载,这可以解释为什么您没有看到任何改进。
无论如何,依赖这种函数的准确性可能是一个坏主意,尤其是在涉及到整数的转换时。如果您期望浮点值是整数(如 100),然后将其转换为 int 类型的值,那么朝向零的轻微错误显然会产生很大的不同。因此,我的建议是编写您自己的 pow 函数,该函数采用所有整数,或者使用您自己的 round 函数特别注意 double->int 转换,以便零的轻微错误不会改变结果。
您的问题不是 gcc 中的错误,这是绝对肯定的。这可能是 的实现中的一个错误pow
,但我认为您的问题实际上只是您正在使用的事实,pow
它给出了一个不精确的浮点结果(因为它被实现为类似的东西exp(power * log(base));
并且log(base)
永远不会是绝对准确的 [除非 base是 e] 的幂。
至少不是我的:
$ 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
。