views:

866

answers:

12

What I mean is the following:

  double d1 =555;
  double d2=55.343

I want to be able to tell that d1 is an integer while d2 is not. Is there an easy way to do it in c/c++?

A: 

A sample code snipped that does it:

if (  ABS( ((int) d1) - (d1)) )< 0.000000001) 

 cout <<"Integer" << endl;

else

 cout <<"Flaot" << endl;

EDIT: Changed it to reflect correct code.

VNarasimhaM
What about 100.01?
Calyth
if the # is 1.0000000001 (as can be returned, for exampleDB backend) it will not work.
DVK
That is **wrong** since you can't use % on the double d1
Jacob
+4  A: 

How about

if (abs(d1 - (round(d1))) < 0.000000001) {
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Fixed up to work using rounding to reflect bug Anna found

Alternate solutions:

if ((d1 - floor(d1) < 0.000000001) || (d1 - floor(d1) > 0.9999999999)) {
   /* Better store floor value in a temp variable to speed up */
   printf "Integer\n"; /* Can not use "==" since we are concerned about precision */
}

Theres also another one with taking floor, subtracting 0.5 and taking abs() of that and comparing to 0.499999999 but I figure it won't be a major performance improvement.

DVK
If d = 15,999997, what is returning floor(d)? I do not think this is working.
Patrice Bernassola
Integers (at least up to a certain size) are represented exactly in any real implementation of floating point numbers I can think of, so I don't think there's a need to worry about precision for this particular problem.
Laurence Gonsalves
What about the case where d1 = 0.999999999999999 ?
Anna
I believe the precision won't matter, since integers can be represented exactly at all precisions. So you could get away with ==. If there's a counter example that proves me wrong, I'd love to hear about it.
Mark Ransom
@Patrice: if d =15.999997 then (d - floor(d)) = .999997 Thus it will fail the test above and not be printed.
Martin York
@Anna - Duh. My only excuse is a fever and no sleep last night. Fixed up
DVK
Fixed? Now it's really broken - floor is much better than round.
Mark Ransom
@Lawrence - the precision loss I'm worried about is coming from external sources, not C itself.
DVK
@ Laurence Gonsalves" That's fine if the value is assigned from a const literal. But if you have been doing some calulations with the number then you __do__ need to worry about precision and you should check to a certain delta.
Martin York
@Mark - If the # is an integer (or vey close to it), round will result in that integer. Subtracting and taking abs() we will get a very small delta. What is my poor brain missing?
DVK
Use STL limits to find the minimum value instead of 0.00..1 http://stackoverflow.com/questions/1521607/check-double-variable-if-it-contains-an-integer-and-not-floating-point/1521675#1521675
Jacob
The only problem is that floor goes the wrong way for negative numbers. you should use trunc()
Martin York
DVK, you just made it a lot worse than before :-)
avakar
@Jacob: You don't want to use the minimum value. You need a value that represents the accuracy you need for the application.
Martin York
@York: Thanks, that is a better design paradigm.
Jacob
@Martin, floor is a problem for either negs of x.999999 numbers, so I solved by comparing to 0 or 1 in floor-using example
DVK
I must apologize. I was fixated on numbers that were exactly integers, not close to integer, and round is a better choice for the solution you provided.
Mark Ransom
@Mark - No prob :)
DVK
+3  A: 

int iHaveNoFraction(double d) { return d == trunc(d); }

Now, it wouldn't be C if it didn't have about 40 years of language revisions...

In C, == returns int but in C++ it returns bool. At least on my Linux distro (Ubuntu) you need to either declare double trunc(double); or compile with -std=c99, or declare the level macro, all in order to get <math.h> to declare it.

DigitalRoss
Maybe make the return type bool, since this returns a boolean?
Daniel Bingham
trunc() is better than floor(). It works for negative numbers.
Martin York
Alcon, good point, it might be C++. Of course, in C, it *is* `int`. I've clarified things...
DigitalRoss
There is no `trunc` in C++ (except for `ios::trunc`).
avakar
That's not exactly true, try it, at least with g++ it works. While 14882 does not specifically declare trunc, it does state, and I cite C++ 26.5 (2), *The contents of these headers are the same as the Standard C library headers `<math.h>`*, and conforming implementations of *that* are required to have `trunc()`. But yes, it might be safer to use floor().
DigitalRoss
There is no `trunc` in C89 either.
avakar
But there is in C99.
DigitalRoss
But, of course, C++ standard refers to C89.
avakar
+3  A: 
int i = d1;
return d1 == ((double) i);

The cast probably isn't necessary, but makes it a bit clearer whats going on.

Laurence Gonsalves
+4  A: 

Assuming you have the cmath <math.h> library, you can check the number against it's floor. If the number might be negative, make sure you get the absolute first.

bool double_is_int(double trouble) {
   double absolute = abs( trouble );
   return absolute == floor(absolute);
}
tj111
For sanity's sake, I recommend rethinking your choice of parameter name.
Alan
@Alan, good looking out. Changed it.
tj111
+22  A: 

Use modf:

modf(value, &intpart) == 0.0

Don't convert to int! The number 1.0e+300 is an integer too you know.

Edit: As Pete Kirkham points out, passing 0 as the second argument is not guaranteed by the standard to work, requiring the use of a dummy variable and, unfortunately, making the code a lot less elegant.

avakar
I had no idea `modf` existed util now.
GMan
Agreed. +1 for nuggets in the C standard library. Though I would use `NULL` instead of `0` but I understand that's a rather contentious issue in C++ for no good reason.
Chris Lutz
should read `modf(value, 0) == 0` as `modf()` returns the fractional part!
Christoph
All double values above approximately 10^16 are integers (except positive infinity).
starblue
Christoph, thanks, what a mistake. :-)
avakar
In fact, passing 0 as the second argument is not only not guaranteed to work, but will crash on many platforms.
Stephen Canon
I think you better compare modf return value to epsilon rather than zero
qrdl
qrdl, you mean for architectures, on which floating point numbers can't represent zero precisely?
avakar
Any vaguely competent implementation of modf on a host with IEEE-754 arithmetic will *always* produce an exact fractional part. If your platform doesn't have a vaguely competent implementation of the math library, you should either stick to integer or (better) find a new platform.
Stephen Canon
A: 

try:

bool isInteger(double d, double delta)
{
   double absd = abs(d);

   if( absd - floor(absd) > 0.5 )
      return (ceil(absd) - absd) < delta;

   return (d - floor(absd)) < delta;
}
Patrice Bernassola
A: 
#include <math.h>
#include <limits>

int main()
{
  double x, y, n;
  x = SOME_VAL;
  y = modf( x, &n ); // splits a floating-point value into fractional and integer parts
  if ( abs(y) < std::numeric_limits<double>::epsilon() )
  {
    // no floating part
  }
}
Kirill V. Lyadvinsky
A: 

How about this?

if ((d1 - (int)d1) == 0)
    // integer
Ashwin
+2  A: 

avakar was almost right - use modf, but the detail was off.

modf returns the fractional part, so the test should be that the result of modf is 0.0.

modf takes two arguments, the second of which should be a pointer of the same type as the first argument. Passing NULL or 0 causes a segmentation fault in the g++ runtime. The standard does not specify that passing 0 is safe; it might be that it happens to work on avakar's machine but don't do it.

You could also use fmod(a,b) which calculates the a modulo b passing 1.0. This also should give the fractional part.

#include<cmath>
#include<iostream>

int main ()
{
    double d1 = 555;
    double d2 = 55.343;

    double int_part1;
    double int_part2;

    using namespace std;

    cout << boolalpha;
    cout << d1 << " " << modf ( d1, &int_part1 ) << endl;
    cout << d1 << " " << ( modf ( d1, &int_part1 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;
    cout << d2 << " " << modf ( d2, &int_part2 ) << endl;
    cout << d1 << " " << ( modf ( d2, &int_part2 ) == 0.0 ) << endl;

    cout << d1 << " " << fmod ( d1, 1.0 ) << endl;
    cout << d1 << " " << ( fmod ( d1, 1.0 ) == 0 ) << endl;
    cout << d2 << " " << fmod ( d2, 1.0 ) << endl;
    cout << d2 << " " << ( fmod ( d2, 1.0 ) == 0 ) << endl;


    cout.flush();

    modf ( d1, 0 ); // segfault

}
Pete Kirkham
+1, I've checked the standard and indeed it does require a pointer to an object as the second argument to `modf`. Thanks.
avakar
Oh, and you don't have to `flush`, passing `endl` does that for you. :-)
avakar
+1 causes a bus error on GCC on OS X too. If only the standards were clearer!
Chris Lutz
A: 

Below you have the code for testing d1 and d2 keeping it very simple. The only thing you have to test is whether the variable value is equal to the same value converted to an int type. If this is not the case then it is not an integer.

#include<iostream>
using namespace std;

int main()
{
    void checkType(double x);
    double d1 = 555;
    double d2 = 55.343;        
    checkType(d1);
    checkType(d2);
    system("Pause");
    return 0; 
}
void checkType(double x)
{
     if(x != (int)x)
     {
          cout<< x << " is not an integer "<< endl;
     }
     else 
     {
         cout << x << " is an integer " << endl;
     }
};
KJP
Please use SO code formatting. If a line begins with four spaces, SO will format it as code.
Chris Lutz
+1  A: 

Assuming a c99 and IEEE-754 compliant environment,

(trunc(x) == x)

is another solution, and will (on most platforms) have slightly better performance than modf because it needs only to produce the integer part. Both are completely acceptable.

Note that trunc produces a double-precision result, so you don't need to worry about out of range type conversions as you would with (int)x.

Stephen Canon