4
#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;
}

For I/P:

3
5
2.98
3.16

O/P:

1

If my code is:

#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;
}

For the same input O/P is:

1
50
25

The only extra line added in 2nd code is: cout<<"";

Can anyone please help in finding why there is such a difference in output just because of the cout statement added in the 2nd code?

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • 2
    http://stackoverflow.com/questions/3962724/problems-in-floating-point-comparison - This might help – novice Jan 21 '16 at 12:15
  • 1
    x==ceilf(x) - There is a problem with this line , ceilf is a float and x a double – novice Jan 21 '16 at 12:22
  • Thank You Now it is working – Priyanshu Kumar Jan 21 '16 at 12:24
  • Sorry For Changing the ques. but I was getting irrelevant answers....but I think now I have put my view forward correctly....now I think you can understand what I am really asking. – Priyanshu Kumar Jan 21 '16 at 12:37
  • 2
    Tried with visual studio compiler and didn't experience your described difference... so what is your compiler? – grek40 Jan 21 '16 at 12:41
  • C++14(G++ 4.9.2) Codechef ide – Priyanshu Kumar Jan 21 '16 at 12:43
  • As a side note, continued fractions are a more efficient way to calculate an (approximate) denominator, e.g. see: http://stackoverflow.com/questions/95727/how-to-convert-floats-to-human-readable-fractions and particularly http://www.ics.uci.edu/~eppstein/numth/frap.c – Arne Vogel Jan 21 '16 at 15:56

4 Answers4

4

Well this is a veritable Heisenbug. I've tried to strip your code down to a minimal replicating example, and ended up with this (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;
}

The behaviour of ceilf appears to depend on the particular sequence of iostream operations that occur around it. Unfortunately I don't have the means to debug in any more detail at the moment, but maybe this will help someone else to figure out what's going on. Regardless, it seems almost certain that it's a bug in gcc-4.9.2 and gcc-5.1. (You can check on ideone that you don't get this behaviour in gcc-4.3.2.)

atkins
  • 1,963
  • 14
  • 27
  • So, what you exactly want to say is this problem is because of ceilf in some specific compiler. – Priyanshu Kumar Jan 21 '16 at 15:32
  • How did you compile iostream in gcc? – Priyanshu Kumar Jan 21 '16 at 15:38
  • 1
    it smacks of an optimisation opportunity being taken/not taken. – Tom Tanner Jan 21 '16 at 15:41
  • 2
    Yea... since 2.98 has no exact binary representation in floatingpoints, the register-hold value of `x = n * 50` may be more accurate than the stored value and when a context-switch appears before the `ceilf(x)`, only the stored value accuracy is available, while otherwise the register accurate value is reused in next operation. (don't kill me if I got the details wrong :D) – grek40 Jan 21 '16 at 15:59
  • be interesting to see if -g -O0 did the same – Tom Tanner Jan 21 '16 at 16:00
2

"Comparing for equality Floating point math is not exact. Simple values like 0.2 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations can change the result. Different compilers and CPU architectures store temporary results at different precisions, so results will differ depending on the details of your environment. If you do a calculation and then compare the results against some expected value it is highly unlikely that you will get exactly the result you intended.

In other words, if you do a calculation and then do this comparison: if (result == expectedResult)

then it is unlikely that the comparison will be true. If the comparison is true then it is probably unstable – tiny changes in the input values, compiler, or CPU may change the result and make the comparison be false."

From http://www.cygnus-software.com/papers/comparingfloats/Comparing%20floating%20point%20numbers.htm

Hope this answers your question.

Also you had a problem with

if(x==ceilf(x))

ceilf() returns a float value and x you have declared as a double. Refer to problems in floating point comparison as to why that wont work.

change x to float and the program runs fine,

Community
  • 1
  • 1
novice
  • 545
  • 3
  • 16
2

You're probably getting an issue with floating point representations - which is to say that computers cannot perfectly represent all fractions. So while you see 50, the result is probably something closer to 50.00000000001. This is a pretty common problem you'll run across when dealing with doubles and floats.

A common way to deal with it is to define a very small constant (in mathematical terms this is Epsilon, a number which is simply "small enough")

const double EPSILON = 0.000000001;

And then your comparison will change from

if (x==ceilf(x))

to something like

double difference = fabs(x - ceilf(x));
if (difference < EPSILON)

This will smooth out those tiny inaccuracies in your doubles.

swinefish
  • 559
  • 6
  • 22
0

I made a plain try on my laptop and even online compilers.
g++ (4.9.2-10) gave the desired output (3 outputs), along with online compiler at geeksforgeeks.org. However, ideone, codechef did not gave the right output.
All I can infer is that online compilers name their compiler as "C++(gcc)" and give wrong output. While, geeksforgeeks.org, which names the compiler as "C++" runs perfectly, along with g++ (as tested on Linux).
So, we could arrive at a hypothesis that they use gcc to compile C++ code as a method suggested at this link. :)

Community
  • 1
  • 1
Himanshu Shekhar
  • 318
  • 9
  • 15