为什么我的整数数学与std::pow给出错误的答案
Why is my integer math with std::pow giving the wrong answer?
考虑以下代码:
#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"。这是一个bug在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);
}
到目前为止,所有其他答案都忽略了这个问题中唯一的问题:
您的c++实现中的pow
质量很差。当没有必要时,它返回一个不准确的答案。
获得一个更好的c++实现,或者至少替换其中的数学函数。Pascal Cuoq所指的那个是好的
至少不是我的:
$ 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
如果你只是写
#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函数。这个函数接受一个浮点指数。问题是这个函数可能有一些近似误差和舍入误差。例如,实现该函数的一种可能方法是:
double pow(double base, double power)
{
return exp(log(base)*power);
}
由于舍入和近似误差,pow(10.0,2.0)很可能产生类似于99.9999999999992543453265的结果。结合浮点数到整数的转换产生小数点前的数字这一事实,这解释了您的结果122,因为99+3=122。
尝试使用pow重载,它接受整数指数和/或从float到int进行一些适当的舍入。采用整数指数的重载可能会为您提供10的2次方的确切结果。
编辑:正如您所指出的,尝试使用std::pow(double,int)重载似乎也会产生略小于100的值。我花时间检查了ISO标准和libstdc++实现,看到从c++ 11开始,由于解决了缺陷报告550,采用整数指数的重载已经被删除了。启用c++ 0x/c++ 11支持实际上消除了libstdc++实现中的重载,这可以解释为什么你没有看到任何改进。 无论如何,依赖这样一个函数的准确性可能是一个坏主意,特别是在涉及到整数转换的情况下。如果您期望的浮点值是整数(如100),然后将其转换为int型值,那么向零的轻微错误显然会产生很大的差异。因此,我的建议是编写自己的pow函数,该函数接受所有整数,或者使用自己的round函数特别注意double->int转换,以便向零的轻微误差不会改变结果。你的问题不是gcc中的bug,这是绝对肯定的。这可能是pow
实现中的一个bug,但我认为你的问题真的很简单,你正在使用pow
,它给出了一个不精确的浮点结果(因为它被实现为exp(power * log(base));
和log(base)
这样的东西永远不会绝对准确[除非基数是e的幂]。
- 访问者访问变体并返回不同类型时出错
- 在Linux for Windows上编译C++代码时出错
- 读取文件的最后一行并输入到链接列表时出错
- 重载操作程序时出错>>用于类中的字符串 memebr
- 调用专用模板时出错"no matching function for call to [...]"
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- LINK 尝试使用 OpenSSL evp aes 256 c++ 时出错
- 在Google Kick start中提交时出错
- 在c++中访问int到类对象的映射时出错
- 分段错误当我试图运行程序时出错
- 使用dynamic_cast和构造函数时出错
- CHECK(调用)函数在Google Colab中出错
- 用pybind11包装C++抽象类时出错
- 在C++中如何在没有pow的情况下进行基础计算
- 为x86而非x64编译时出错
- 从R调用C++函数并对其进行集成时出错
- 这个函数哪里出错了
- C++ 创建包含链表和字符串的对象的链接列表时出错
- 理解GCC中的std::pow实现
- 在C++中使用 pow() 时出错