#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;
int main() {
int t;
double n;
cin>>t;
while(t--)
{
cin>>n;
double x;
for(int i=1;i<=10000;i++)
{
x=n*i;
if(x==ceilf(x))
{
cout<<i<<endl;
break;
}
}
}
return 0;
}
对于I / P:
3 5 2.98 3.16
O / P:
1
如果我的代码是:
#include <iostream>
#include <iomanip>
#include <math.h>
using namespace std;
int main() {
int t;
double n;
cin>>t;
while(t--)
{
cin>>n;
double x;
for(int i=1;i<=10000;i++)
{
x=n*i;
cout<<"";//only this statement is added;
if(x==ceilf(x))
{
cout<<i<<endl;
break;
}
}
}
return 0;
}
对于相同的输入,O / P是:
1 50 25
第二个代码中添加的唯一额外行是:cout<<"";
任何人都可以帮助找出为什么仅仅因为第二个代码中添加的cout语句而导致输出存在这样的差异?
答案 0 :(得分:4)
这是一个名副其实的Heisenbug。我尝试将您的代码删除到最小的复制示例,最后得到了这个(http://ideone.com/mFgs0S):
#include <iostream>
#include <math.h>
using namespace std;
int main()
{
float n;
cin >> n; // this input is needed to reproduce, but the value doesn't matter
n = 2.98; // overwrite the input value
cout << ""; // comment this out => y = z = 149
float x = n * 50; // 149
float y = ceilf(x); // 150
cout << ""; // comment this out => y = z = 150
float z = ceilf(x); // 149
cout << "x:" << x << " y:" << y << " z:" << z << endl;
}
ceilf
的行为似乎取决于围绕它发生的iostream
操作的特定顺序。不幸的是,目前我还没有更多细节调试的方法,但也许这将有助于其他人弄清楚发生了什么。无论如何,似乎几乎可以肯定它是gcc-4.9.2和gcc-5.1中的一个错误。 (你可以检查一下你在gcc-4.3.2中没有得到这种行为的想法。)
答案 1 :(得分:2)
“比较平等 浮点数学并不准确。像0.2这样的简单值无法使用二进制浮点数精确表示,浮点数的有限精度意味着操作顺序的微小变化可能会改变结果。不同的编译器和CPU架构以不同的精度存储临时结果,因此结果将根据您的环境的详细信息而有所不同。如果您进行计算,然后将结果与某些预期值进行比较,那么您很可能无法获得预期的结果。
换句话说,如果您进行计算然后进行此比较: if(result == expectedResult)
那么比较不太可能。如果比较为真,那么它可能不稳定 - 输入值,编译器或CPU的微小变化可能会改变结果并使比较变为假。“
来自http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating%20point%20numbers.htm
希望这能回答你的问题。
你也遇到了问题
if(x==ceilf(x))
ceilf()返回一个浮点值,x声明为double。 请参阅problems in floating point comparison,了解为何不起作用。
将x更改为float并且程序运行正常,
答案 2 :(得分:2)
您可能遇到浮点表示问题 - 也就是说计算机无法完美地表示所有分数。所以当你看到50时,结果可能接近50.00000000001。在处理double
和float
时,这是一个非常常见的问题。
处理它的常用方法是定义一个非常小的常数(在数学术语中,这是Epsilon,这个数字只是“足够小”)
const double EPSILON = 0.000000001;
然后你的比较将从
改变if (x==ceilf(x))
类似
double difference = fabs(x - ceilf(x));
if (difference < EPSILON)
这将消除你双打中那些微小的不准确之处。
答案 3 :(得分:0)
我在我的笔记本电脑甚至在线编译器上做了一个简单的尝试。
g ++(4.9.2-10)给出了所需的输出(3个输出),以及geeksforgeeks.org的在线编译器。然而,ideone,codechef没有给出正确的输出。
我可以推断的是,在线编译器将其编译器命名为&#34; C ++(gcc)&#34;并给出错误的输出。而geeksforgeeks.org,将编译器命名为&#34; C ++&#34;完美运行,以及g ++(在Linux上测试)。
因此,我们可以得出一个假设,即他们使用gcc编译C ++代码作为this link建议的方法。 :)