1

/* I am currently learning c++ as part of my core subjects */

Strangely, while writing another long program i ran into this instance

#include <iostream>
#include <cmath>
using namespace std;  
int main()
  {
    int a,b,res; float c;
    cin>>a;
    cin>>b;
    cin>>c;
    res=(a-b)/c;
    cout<<res;
  }

Input :

a = 2 b = 1 c = 0.2

Output :

4

Desired Output :

5

I need to find res, (the number of steps of increment c) in between the starting a and end b truncated to the closest floor integer value.

I tried defining (a-b) as another int, still same result 4 instead of 5.

But simply testing

int main()
{
    cout<<(2-1)/0.2;
}

correctly gave 5.

One more doubt: if I do not define any variable, like above, what datatype will the system assume for the result?

  • What you are saying is not possible. – SergeyA Mar 11 '16 at 22:15
  • Changing `res` and `c` to `double` may be enlightening. The answer to the question "... I do not define any variable, what datatype will the system assume for the result." is "it will not assume anything; your program will fail to compile." C++ requires you to define (the term-of-art is "declare") all variables. – zwol Mar 11 '16 at 22:15
  • I cannot reproduce your problem, I'm getting 5 – Iłya Bursov Mar 11 '16 at 22:15
  • @zwol, no, you will still get output of 5 with given input even with `float` precision. – SergeyA Mar 11 '16 at 22:17
  • @SergeyA `res` is currently an `int`. – zwol Mar 11 '16 at 22:18
  • [IDEOne link](http://ideone.com/EQPTni). There is something wrong with your run environment. There is nothing wrong with your program. – abelenky Mar 11 '16 at 22:19
  • The exact snippet i posted gave me result 4 in Codeblocks 16.01 Build and run terminal window. (I'm on windows platform). I have pasted the full code above. –  Mar 11 '16 at 22:19
  • 2
    Sounds like the old "that floating point value is not what you think it is" issue. If that 0.2 is actually 0.199995 or something equally unintuitive, it will be rounded down when stuck in the integer. You need to always avoid caring about EXACT results when using float or double. Neither are ever exact. –  Mar 11 '16 at 22:19
  • @zwol, yes, I can see that. Doesn't change the fact. – SergeyA Mar 11 '16 at 22:19
  • 3
    see [Is floating point math broken?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – M.M Mar 11 '16 at 22:21
  • 1
    @SergeyA It appears to be the back-conversion to `int` that is tripping up the OP; my comment was only meant to clue them in about that. I agree that float vs double appears to be a red herring, but because of the promotion rules, using double all the time in C++ is a good habit to be in, so that's what I typed. – zwol Mar 11 '16 at 22:21
  • It gives 5 when i define all variables as float; not with the above code –  Mar 11 '16 at 22:23
  • 1
    @VaisakMohan Because integers round down. If you make `res` float and cast the integers to float it will display 5; but it's not actually 5, it's something that is approximately 5. Tweak the output parameters and you'll see some extra cruft at the end. But the rounding happens even with floats not involved. Try doing integer division with 100/99. –  Mar 11 '16 at 22:25
  • @abelenky Use c++5.1 and you will get 4. Most likely .2 does not have an exact representation. – zdf Mar 11 '16 at 22:29
  • @ZDF, it does not. But it's representation should be always the same per IEEE 754. – SergeyA Mar 11 '16 at 22:29
  • @SergeyA IEEE754 does not specify what the representation is , for values that are not exactly representible. In C it may either be the next-highest or the next-lowest. – M.M Mar 11 '16 at 22:36
  • @sergeya I checked before I posted the comment. The standard is one thing, implementing it, is another. I am not near a computer, but I think that a debugger will show that .2 is, in fact, 0.20000somethig. I' m going to bed. – zdf Mar 11 '16 at 22:38
  • 1
    @ZDF it definitely doesn't: 0.2 is 1/5 , but any number with a finite representation in binary floating point can only be a sum of powers of 2. (and no fraction of integers is such a sum unless its denominator is a power of 2). – M.M Mar 11 '16 at 22:39
  • @ZDF, my source of confusion was that I didn't know that it could be either next-highest or next-lowest (this is what I believe tipping the scales in the example). I was sure it is mandated, this why I couldn't believe OP. – SergeyA Mar 11 '16 at 22:41
  • @M.M., yes, you explained it in the comments to the answer. Like I said, I was totally sure this is mandated in IEEE. – SergeyA Mar 11 '16 at 22:42
  • 1
    You might like to experiment with `fesetround(FE_UPWARD)` or `fesetround(FE_DOWNWARD)` which control the IEEE754 rounding direction. (I'm not sure if this will apply to storing 0.2, or if it only applies to results of calculations), maybe try `1.0f/5` instead of `0.2` – M.M Mar 11 '16 at 22:44
  • What datatype will the system assume when executing out the second snippet. Nothing has been defined. Still it gives results accordingly. Result in integer form when only integer numbers are used, or if decimals are used, result contains decimals with precision upto 7 –  Mar 11 '16 at 22:51

2 Answers2

9

You have the age old problem of rounding floats which stems from the fact that floating point numbers are base 2 and therefore cannot represent all base 10 numbers perfectly (eg. 0.3). Read this tutorial and this SO question for more information.

As for your example try adding this to your program:

cout << std::setprecision(16) << (float)(a-b)/c << endl;

You will get this print out:

4.999999925494195

And what is (int)4.9999...? It is 4.

Live example.

Community
  • 1
  • 1
Fantastic Mr Fox
  • 32,495
  • 27
  • 95
  • 175
  • `4.9999...` is not `4`. When a floating point value is converted to `int`, rounding is toward zero. – Peter Mar 11 '16 at 22:33
  • 2
    @Peter Is that not clear enough from the expression `(int)4.999...`? – Fantastic Mr Fox Mar 11 '16 at 22:35
  • So it the is one of the trade offs for using float, and machine dependent also. Thanks for the example. –  Mar 11 '16 at 22:43
  • @VaisakMohan When converting float to int, consider using `res = round( (a-b)/c );` - then you get rounding instead of truncation – M.M Mar 11 '16 at 22:47
-1

this is almost definitely a rounding error. test it for yourself ->

a = 2
b = 1
c = 0.2000000001
res = 4

i would suggest using a double instead of a float, it should provide you with the precision you need. of course, going from doubles to integers always has the risk of rounding wrong, without using some sort of rounding function to compensate

William B.
  • 85
  • 5
  • Nothing to do with rounding. – SergeyA Mar 11 '16 at 22:18
  • 1
    @SergeyA I think this answer is correct, could you post a more constructive comment than that? (or post your own answer, preferably) – M.M Mar 11 '16 at 22:20
  • 2
    actually, it does... in fact, it is the exact cause. depending on the OS and hardware, the result of that floating point division will vary. Even if you cant reproduce it, it doesnt mean its not a rounding problem – William B. Mar 11 '16 at 22:20
  • @M.M, the simple answer is that it gives 5. – SergeyA Mar 11 '16 at 22:20
  • 1
    @SergeyA on your computer it gives 5, on OP's computer it gives 4 . You've been around here long enough to know that the same program may give different output on different systems. – M.M Mar 11 '16 at 22:22
  • @M.M, it is embarassing, but still unexplained. float math is defined in IEEE 754. Compilers should follow it, shouldn't they? – SergeyA Mar 11 '16 at 22:27
  • 2
    And the answer is still incorrect, because double precision does not gurantee the whole number either. – SergeyA Mar 11 '16 at 22:28
  • @SergeyA firstly the C and C++ standards do not require IEEE754; but even if they do follow it there is a lot of latitude. One source of variation is that a compiler may do `(a-b)/c` in double precision whereas another may do it in single. (The code indicates single precision due to the use of `float`, but the standard allows the compiler to use unspecified higher precision ; this is to support the compiler using registers or hardware operations that are natively double precision without it having to write a bunch of crap to simulate single precision). – M.M Mar 11 '16 at 22:30
  • Also it is implementation-defined whether a number that cannot be represented exactly (e.g. `0.2`) is represented as the next-highest representible value, or the next-lowest. – M.M Mar 11 '16 at 22:31
  • @M.M, ok, I was wrong here. However, this particular answer of replacing float with double is still wrong, as the number is still not going to be whole. – SergeyA Mar 11 '16 at 22:34
  • 1
    @SergeyA yes, using `double` is an improvement but it still would not guarantee getting the 'right' answer – M.M Mar 11 '16 at 22:35
  • @M.M I agree with SergeyA here, double *might* be an improvement, but it also can cause headaches in high speed programs if overused. I dont think this answer can quantitatively be change to double for more luck ... – Fantastic Mr Fox Mar 11 '16 at 22:42