2

I have a program in C++ where I divide two numbers, and I need to know if the answer is an integer or not. What I am using is:

if(fmod(answer,1) == 0)

I also tried this:

if(floor(answer)==answer)

The problem is that answer usually is a 5 digit number, but with many decimals. For example, answer can be: 58696.000000000000000025658 and the program considers that an integer.

Is there any way I can make this work?

I am dividing double a/double b= double answer

(sometimes there are more than 30 decimals)

Thanks!

EDIT: a and b are numbers in the thousands (about 100,000) which are then raised to powers of 2 and 3, added together and divided (according to a complicated formula). So I am plugging in various a and b values and looking at the answer. I will only keep the a and b values that make the answer an integer. An example of what I got for one of the answers was: 218624 which my program above considered to be an integer, but it really was: 218624.00000000000000000056982 So I need a code that can distinguish integers with more than 20-30 decimals.

8
  • Should true be reported only for numbers slightly greater than an integer and not for numbers slightly less than an integer, such as 2.999999999999999555910790149937383830547332763671875? How much difference is acceptable? How did you come to have numbers that should be integers or not (what prior calculations gave rise to this)? Where did a and b in your a/b example come from? Commented Oct 27, 2013 at 0:27
  • a and b are numbers in the thousands (about 100,000) which are then raised to powers of 2 and 3, added together and divided (according to a complicated formula). So I am plugging in various a and b values and looking at the answer. I will only keep the a and b values that make the answer an integer. An example of what I got for one of the answers was: 218624 which my program above considered to be an integer, but it really was: 218624.00000000000000000056982 So I need a code that can distinguish integers with more than 20-30 decimals. Commented Oct 27, 2013 at 2:52
  • @ItM You will not be able to do that with the precision of a double. You'd need to use a high precision floating point library. Commented Oct 27, 2013 at 4:11
  • I was considering GMP but I don't know how to use it. Commented Oct 27, 2013 at 5:02
  • 218624.00000000000000000056982 cannot be represented as a double in the format most C++ implementations use. Did you obtain this result in double (implying your implementation uses a very long format for double), obtain it in long double or another built-in type in a C++ program (possibly a type that is an extension in your implementation), obtain it with other software, or obtain it by other mathematics (e.g., pen and paper)? Is it an example of a number that should be treated as an integer because the fractional part is only the result of floating-point approximations or… Commented Oct 27, 2013 at 8:53

3 Answers 3

1

You can use std::modf in cmath.h:

double integral;
if(std::modf(answer, &integral) == 0.0)

The integral part of answer is stored in fraction and the return value of std::modf is the fractional part of answer with the same sign as answer.

Sign up to request clarification or add additional context in comments.

4 Comments

Why would you name the integral part fraction?
@DwayneTowell Maybe because its over 05:00 and I am still awake. Thanks edited :)
Because of the way floating point numbers are stored in memory, you don't want to do the == 0.0 check. Instead, you will want to do std::modf(answer, &integral) < SOME_REALLY_SMALL_NUMBER.
This does not provide the requested operation, which is to report true for numbers that are close to integers. And, even if were modified to report true if the fraction part is very small, it will continue to report false for numbers such as 2.999999999999999555910790149937383830547332763671875, which I suspect the OP prefers true.
1

The usual solution is to check if the number is within a very short distance of an integer, like this:

bool isInteger(double a){
    double b=round(a),epsilon=1e-9; //some small range of error
    return (a<=b+epsilon && a>=b-epsilon); 
}

This is needed because floating point numbers have limited precision, and numbers that indeed are integers may not be represented perfectly. For example, the following would fail if we do a direct comparison:

double d=sqrt(2); //square root of 2
double answer=2.0/(d*d); //2 divided by 2

Here, answer actually holds the value 0.99999..., so we cannot compare that to an integer, and we cannot check if the fractional part is close to 0. In general, since the floating point representation of a number can be either a bit smaller or a bit bigger than the actual number, it is not good to check if the fractional part is close to 0. It may be a number like 0.99999999 or 0.000001 (or even their negatives), these are all possible results of a precision loss. That's also why I'm checking both sides (+epsilon and -epsilon). You should adjust that epsilon variable to fit your needs.

Also, keep in mind that the precision of a double is close to 15 digits. You may also use a long double, which may give you some extra digits of precision (or not, it is up to the compiler), but even that only gets you around 18 digits. If you need more precision than that, you will need to use an external library, like GMP.

Comments

-1

Floating point numbers are stored in memory using a very different bit format than integers. Because of this, comparing them for equality is not likely to work effectively. Instead, you need to test if the difference is smaller than some epsilon:

const double EPSILON = 0.00000000000000000001; // adjust for whatever precision is useful for you
double remainder = std::fmod(numer, denom);
if(std::fabs(0.0 - remainder) < EPSILON)
{
    //...
}

Alternatively, if you want to include values that are close to integers (based on your desired precision), you can modify the if condition slightly (since the remainder returned by std::fmod will be in the range [0, 1)):

if (std::fabs(std::round(d) - d) < EPSILON)
{
    // ...
}

You can see the test for this here.

Floating point numbers are generally somewhat precise to about 12-15 digits (as a double), but as they are stored as a mantissa (fraction) and a exponent, rational numbers (integers or common fractions) are not likely to be stored as such. For example,

double d = 2.0; // d might actually be 1.99999999999999995

Because of this, you need to compare the difference of what you expect to some very small number that encompasses the precision you desire (we will call this value, epsilon):

double d = 2.0;
bool test = std::fabs(2 - d) < epsilon; // will return true

So when you are trying to compare the remainder from std::fmod, you need to check it against the difference from 0.0 (not for actual equality to 0.0), which is what is done above.

Also, the std::fabs call prevents you from having to do 2 checks by asserting that the value will always be positive.

If you desire a precision that is greater than 15-18 decimal places, you cannot use double or long double; you will need to use a high precision floating point library.

6 Comments

This will report false for numbers slightly less than integers, such as 2.999999999999999555910790149937383830547332763671875, but I suspect the OP prefers true. Additionally, the OP likely needs help figuring out what value should be used for EPSILON, so writing “adjust for whatever precision is useful for you” is not helpful.
@EricPostpischil That depends on what he selects as EPSILON, but I'll expound a bit.
There is still no code here that will work. std::fabs(0.0 - remainder) < EPSILON does not work because remainder is not near zero when numer is slightly below an integer; it is near one. And the code bool test = std::fabs(2 - d) < epsilon; only works to test for two; it does not show how one might get another integer to test against.
@EricPostpischil The actual tests disagree with you: ideone.com/HVcCe0 as does the math (when a floating point number x is close to an integer number y, |x - y| will be close to 0, not close to 1. If it is close to 1 (or any other number other than 0), the remainder indicates that the numerator is not evenly divisible by the denominator.
The double numer = 1.9999999999999999999999999; in your test code does not result in numer being slightly less than two. It results in exactly two. Try double numer = nexttoward(2, 0);.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.