Thread: Most Efficient Way to Check a Variable Is A Whole Number

  1. #16
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by iMalc View Post
    Less likely to be a problem of course, but a double still far exceeds the range of a long long. So 2^100 (which is exactly representable in a double) isn't a whole number with that approach.
    But then you probably already knew that.
    I forgot to add that this will actually work if you check the double for being outside the range of about say -2^60 to 2^60 first, returning true in that case, because a double doesn't have enough significand bits to represent such large numbers with any decimal places at all.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  2. #17
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Daved View Post
    What about my example? It gives incorrect output.
    As a matter of fact, it gives correct output. Your code correctly detected that a floating point variable with the value (approximately) 42.993 does not contain an integral value.

    Your error was in expecting that the series of calculations that produced the value would yield an integral value.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #18
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    You're telling me that (1000.43 - 1000.00)*100 is not a whole number?

    I'm sure you can understand the point that I was making. If you'd like to address that feel free, but your comments don't make sense in the context of my original advice, which I still think is important for the OP to understand.

  4. #19
    Registered User
    Join Date
    Oct 2007
    Posts
    166
    You could do it like:

    Code:
    if (!(a_dbl - (int)a_dbl))
    {
    }

  5. #20
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    See iMalc's first post to see why that might not work.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  6. #21
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    There's also modf. It breaks a floating-point number into an integral and a fractional part. I'm not sure how efficient it is, but it's perfect for this situation.

    Sorry for the C example code; I didn't notice what forum I was in. [edit] See the C++ code below. [/edit]
    Code:
    #include <stdio.h>
    #include <math.h>
    
    void check(double x) {
        double fractional, integral;
        fractional = modf(x, &fractional);
        printf(fractional == 0.0 ? "an integer" : "not an integer");
    }
    
    int main() {
        printf("3.0 is ");
        check(3.0);
        putchar('\n');
    
        printf("3.5 is ");
        check(3.5);
        putchar('\n');
    
        return 0;
    }
    [edit] In C++:
    Code:
    #include <cmath>
    
    bool is_integer(double number) {
        double fractional;  // ignored
        return modf(number, &fractional) == 0.0;
    }
    I used the dummy variable fractional since modf doesn't support passing NULL for the integral part parameter.

    I know I'm comparing floating point numbers with == here, but since I'm comparing with 0.0 it should be okay in most cases.
    [/edit]
    Last edited by dwks; 05-27-2009 at 04:56 PM.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  7. #22
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    dwks, the second parameter should be the buffer for the integral part (typo, I'm assuming?).
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #23
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Umm, not as far as I know? The "buffer" here is of type double, as I've supplied. Seriously, try my C++ function. It should work.

    Where exactly is the suspect phrase in my post?

    What I was trying to say is that modf doesn't let you supply NULL for the second parameter if you don't want to get the integral part of it. You have to supply a double pointer for it to overwrite.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  9. #24
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Oh, ok, well it's just a little misleading then (ie: perhaps using "integral" or similar (or even "unused" as the variable name might be more appropriate then "fractional"). At any rate, the code works correctly.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  10. #25
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Daved View Post
    You're telling me that (1000.43 - 1000.00)*100 is not a whole number?

    I'm sure you can understand the point that I was making. If you'd like to address that feel free, but your comments don't make sense in the context of my original advice, which I still think is important for the OP to understand.
    I agree with grumpy. The calculation preceeding the check for a whole number could be introducing far more error than just making it a little off from a whole number when logically it should be equal to a whole number.

    Consider starting with a double value of 2^50+0.5 and then looping 1 million times, adding 0.0000005 each iteration. Clearly mathematics will tell you that the result should be 2^50+1 exactly. However the computer scientist in you knows that the result will be 2^50+0.5 since each addition of 0.0000005 will have no effect as the magnitudes are too different.
    To be consistent you're earlier statement, you'd be claiming that the variable which now holds a number exactly half way between to whole numbers should be detected as being a whole number.

    All grumpy is saying is that the point at which a variable is a no longer whole number must be considered to be where calculations to obtain its value introduce the inaccuracy, and not where the actual test is performed.

    Afterall, if I then deleted the loop described above and just went straight for the whole number test, I'd be testing a variable holding the exact same value (same bit pattern of ones and zeros in memory), yet you'd desire a different result when the loop is omitted. That simply isn't possible.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  11. #26
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Daved View Post
    You're telling me that (1000.43 - 1000.00)*100 is not a whole number?
    I didn't tell you that but, yes, it will work out that way if the expression (1000.43 - 1000.00)*100 is computed using floating point.

    Floating point calculations introduce errors due to finite rounding/precision. To start with, negative powers of 10 cannot be represented exactly in binary, so 1000.43 will not be represented exactly. And the errors will propagate from there with floating point operations (addition, multiplication of values, etc)
    Quote Originally Posted by Daved View Post
    I'm sure you can understand the point that I was making. If you'd like to address that feel free, but your comments don't make sense in the context of my original advice, which I still think is important for the OP to understand.
    I understood your point, but I consider you're mistaken. iMalc has captured my meaning perfectly.
    Last edited by grumpy; 05-28-2009 at 07:08 AM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  12. #27
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    I understand the potential for rounding/accuracy errors in floating point calculations. That is what I was warning about.

    If you write a program and ask the user to enter three numbers a, b, c. Your program promises to tell the user whether (a-b)*c is a whole number. The user enters 1000.43, 1000.00 and 100. You output: "Sorry, (a-b)*c is not a whole number because I use floating point computations which aren't always accurate." Of course not.

    iMalc's example is irrelevant unless you think it means that the advice in 29.17 of the C++ FAQ Lite should never be followed. Is that what you're arguing? I doubt it. There are times when using == to compare floating point numbers leads to inaccurate results. You can adjust for that. This is one of those cases.

    Just because there are other potential errors in floating point calculations doesn't mean you should ignore one that can be combated. Just because your adjustment won't fix all possible problems doesn't mean you shouldn't fix as many of them as you reasonably can.

    >> All grumpy is saying is that the point at which a variable is a no longer whole number must
    >> be considered to be where calculations to obtain its value introduce the inaccuracy, and not
    >> where the actual test is performed.

    I disagree. It should be the point at which you can no longer reasonably account for the inaccuracy. Using a decent epsilon value will reduce many of these errors and greatly improve the accuracy of the whole number check.

  13. #28
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If you write a program and ask the user to enter three numbers a, b, c. Your program promises to tell the user whether (a-b)*c is a whole number. The user enters 1000.43, 1000.00 and 100. You output: "Sorry, (a-b)*c is not a whole number because I use floating point computations which aren't always accurate." Of course not.
    What if the user enters 1000.42999999994381, 1000.00 and 100?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  14. #29
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> What if the user enters 1000.42999999994381, 1000.00 and 100?

    Just because your adjustment won't fix all possible problems doesn't mean you shouldn't fix as many of them as you reasonably can.

  15. #30
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Daved View Post
    It should be the point at which you can no longer reasonably account for the inaccuracy. Using a decent epsilon value will reduce many of these errors and greatly improve the accuracy of the whole number check.
    Actually I think that's fair enough too.

    I think in most cases a test such as this would ususally be used directly after inputting a value from the user, where the point is of course moot.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. fscanf with variable number of entries
    By cfdprogrammer in forum C Programming
    Replies: 5
    Last Post: 04-20-2009, 02:02 AM
  2. HELP!!!!emergency Problem~expert please help
    By unknowppl in forum C++ Programming
    Replies: 9
    Last Post: 08-21-2008, 06:41 PM
  3. HELP!!!!emergency ~expert please help
    By unknowppl in forum C Programming
    Replies: 1
    Last Post: 08-19-2008, 07:35 AM
  4. Using loops for check a roman number input.
    By eryell in forum C++ Programming
    Replies: 9
    Last Post: 04-12-2006, 11:04 AM
  5. How is to check prime number?
    By Unregistered in forum C Programming
    Replies: 7
    Last Post: 10-04-2001, 11:36 PM