C++ 求幂函数pow()的输出问题
前言
最近在打一些算法题目的时候,遇到了不少cpp的一些bug,在其中有不少让我困惑了很久!
今天的主角就是如此,本文的pow函数,在不同编程环境下,出现了不同的输出情况。
问题现状
先上代码
#include<cstdio>
#include<string>
#include<cmath>
typedef long long ll;
#define endl '\n'
typedef std::string string;
int main()
{
int num;
scanf("%d", &num);
string snum = std::to_string(num);
int len = snum.length();
int k = std::pow(10, len);
printf("%d\n", k);
return 0;
}
这个代码的逻辑是,输入一个字符串,根据输入字符串的长度len,然后输出10^len(10的len次幂)。
然后我选取 devc++
和 visual studio 2022
两个IDE来测试这个代码。
devcpp
visual studio
可以看到在不同的 IDE
下的运行结果是截然不同的。且可以看出来,devcpp的结果是我们在编写程序时不希望或者不在我们预料范围内,而visual 的结果则是符合预期的。
那么,为什么会出现这样的问题呢,为了能让问题更加清楚,我将代码修改了一下。
#include<cstdio>
#include<string>
#include<cmath>
typedef long long ll;
#define endl '\n'
typedef std::string string;
int main()
{
int num;
int i = 0;
while(~scanf("%d", &num))
{
num = std::pow(10, i++);
printf("%d\n", num);
}
return 0;
}
改动后,每次循环输入一个数字,当然这个数字是个没用的 临时变量
,我们会0开始,用pow函数得到10的幂次。
运行结果如下
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f368c5a9570eaab18494c9cf2a9be9b1.png)
可以看到,在 int
变量范围内时,原本应该输出100,10000,100000000,1000000000 四个数字,pow输出了该值 - 1的结果。
问题原因
在逛了很多blog,和像百度回答,stackoverflow等网站后,对这个问题有了比较合理的解释。
感兴趣的可以看这个关于C ++:幂函数输出错误-C | 码农家园 (codenong.com)
这是我找到的对这个问题比较好的讨论。
我们先看下百度对pow的解释
我们发现,pow有多个重载,且我们在使用的时候编译器应该会有警告,但是这和我们遇到的问题是没有特别大的关系。
我们再看这个解释,这里结合百度百科关于pow函数的重载,我的解释是:
在使用变量的时候,函数会将变量转化,而求值(返回值)的结果会最终转化为double,在double转int的过程中,会出现精度丢失的问题,这里其实是pow函数的问题,运算的结果会出现一个小于100,但极度接近100的数,比如99.99996之类的,然后由于cpp 的 double
转 int
发生的 精度丢失
的问题,从而使结果变为99。
那,为什么,不同的ide的输出结果会不同?
我想这应该是两个ide对pow的解释不同,或者说优化处理不同。
visual 的环境是window cpp开发, 而devcpp则是基于MinGW
,不同的环境确实会在这些库函数的细节之处有所不同。
解决方法
如何避免这个问题,或者怎么解决呢?我们可以这样子。
在函数的输出后加一个很小的浮点数,或者可以直接加0.5,确保实现四舍五入。
代码如下
Code(cpp)
#include<cstdio>
#include<string>
#include<cmath>
typedef long long ll;
#define endl '\n'
typedef std::string string;
int main()
{
int num;
int i = 0;
while(~scanf("%d", &num))
{
num = std::pow(10, i++) + 0.5;
printf("%d\n", num);
}
return 0;
}
运行结果
这样就可以避免出现因为pow函数精度丢失引起的数值错误问题了!
后话
好久没更新了,之前一直在高强度上课+集训,以及一些其他的事情影响,后续加油吧!