isnan or isntnan?

Discussion in 'C Programming' started by JohnF, Nov 13, 2010.

  1. JohnF

    JohnF Guest

    I'm having trouble debugging some apparent nan problem.
    Checking with isnan() seems okay, but printf() just prints
    nan anyway. I'm running gcc 4.2.4, under linux (slackware 12.2
    with default packages/libs/etc), and for debugging purposes
    have compiled with -ffast-math. It's the y2 arg that's the
    apparent culprit in the following code (which log-linearly
    interpolates and returns the y-value at input x, given known
    points x1,y1 and x2,y2)...
    double loglinterp(x, x1, y1, x2, y2)
    double x,x1,y1,x2,y2;
    {
    double weight;
    int nanerror = (isnan(y1)?1:0);
    if ( isnan(y2) ) nanerror += 2;
    if ( nanerror!=0 || y1<=0.0 || y2<=0.0 )
    { printf("loglinterp> y-arg<=0.0(isnan=%d): x=%8.5f; "
    "x1=%8.5f, y1=%8.5f; x2=%8.5f, y2=%8.5f\n",
    nanerror,x,x1,y1,x2,y2);
    return (-1.0); }
    if ( x2 == x1 ) weight = .5;
    else weight = (x - x1)/(x2 - x1);
    return exp( (1.0 - weight)*log(y1) + weight*log(y2) );
    }
    And here's some output where it appears to be catching
    what it apparently thinks is a y2<=0 (I've manually wrapped
    and indented the long lines)...
    loglinterp> y-arg<=0.0(isnan=0): x= 0.17131; x1= 0.16615,
    y1= 0.59367; x2= 0.17910, y2= nan
    loglinterp> y-arg<=0.0(isnan=0): x= 0.16898; x1= 0.16615,
    y1= 0.59367; x2= 0.17910, y2= nan
    loglinterp> y-arg<=0.0(isnan=0): x= 0.16668; x1= 0.16615,
    y1= 0.59367; x2= 0.17910, y2= nan
    It seems that isnan(y2) must be false since it prints 0 for
    the nanerror variable, but then it prints nan for y2 anyway.
    What could be going on, and how do I proceed to debug it?
    Thanks,
    --
    John Forkosh ( mailto: where j=john and f=forkosh )
     
    JohnF, Nov 13, 2010
    #1
    1. Advertising

  2. JohnF

    Eric Sosman Guest

    On 11/13/2010 11:48 AM, JohnF wrote:
    > I'm having trouble debugging some apparent nan problem.
    > Checking with isnan() seems okay, but printf() just prints
    > nan anyway. I'm running gcc 4.2.4, under linux (slackware 12.2
    > with default packages/libs/etc), and for debugging purposes
    > have compiled with -ffast-math. [...]
    > What could be going on, and how do I proceed to debug it?


    The info for my copy of gcc says that -ffast-math "can
    result in incorrect output..." The info doesn't describe the
    kinds of incorrectness that might occur, but perhaps if you
    dig into the matter you'll find an explanation.

    Or you could omit -ffast-math and see what happens ...

    --
    Eric Sosman
    lid
     
    Eric Sosman, Nov 13, 2010
    #2
    1. Advertising

  3. JohnF

    James Waldby Guest

    On Sat, 13 Nov 2010 16:48:42 +0000, JohnF wrote:

    > I'm having trouble debugging some apparent nan problem. Checking with
    > isnan() seems okay, but printf() just prints nan anyway.


    [snip three lines of code like
    double loglinterp(x, x1, y1, x2, y2) double x,x1,y1,x2,y2; {
    compiled with gcc 4.2.4 on slackware 12.2 with -ffast-math switch
    etc]
    > if ( isnan(y2) ) nanerror += 2;
    > if ( nanerror!=0 || y1<=0.0 || y2<=0.0 )
    > { printf("loglinterp> y-arg<=0.0(isnan=%d): x=%8.5f; "
    > "x1=%8.5f, y1=%8.5f; x2=%8.5f, y2=%8.5f\n",
    > nanerror,x,x1,y1,x2,y2);


    [snip other code and some output like next:]

    > loglinterp> y-arg<=0.0(isnan=0): x= 0.16668; x1= 0.16615,
    > y1= 0.59367; x2= 0.17910, y2= nan
    > It seems that isnan(y2) must be false since it prints 0 for the nanerror
    > variable, but then it prints nan for y2 anyway. What could be going on,
    > and how do I proceed to debug it? Thanks,


    For more discussion of debugging, perhaps try comp.programming,
    not c.l.c. (Added c.p to newsgroups and set followups there.)

    If Eric Sosman's suggestion re -ffast-math doesn't help, try
    printing y2 also in hex, both before calling loglinterp() and
    within loglinterp(). Eg, write a function printFX (double y)
    and in printFX() declare a union u with double and long or long
    long members u.f and u.l; set u.f to y; and printf ("...%f...%0lx...",
    u.f, u.l). Use an integer type of the same size as a double.
    If you want to print characters as well, have a member u.c
    declared with char c[sizeof(double)], and putchar each u.c.

    Then, if the hex versions look like characters or like integers,
    look for a string copy or array copy spilling out of bounds, or
    assignment to an integer alias of y2, etc.

    --
    jiw
     
    James Waldby, Nov 14, 2010
    #3
  4. JohnF

    JohnF Guest

    Eric Sosman wrote:
    > JohnF wrote:
    >> I'm having trouble debugging some apparent nan problem.
    >> Checking with isnan() seems okay, but printf() just prints
    >> nan anyway. I'm running gcc 4.2.4, under linux (slackware 12.2
    >> with default packages/libs/etc), and for debugging purposes
    >> have compiled with -ffast-math. [...]
    >> What could be going on, and how do I proceed to debug it?

    >
    > The info for my copy of gcc says that -ffast-math "can
    > result in incorrect output..." The info doesn't describe the
    > kinds of incorrectness that might occur, but perhaps if you
    > dig into the matter you'll find an explanation.
    > Or you could omit -ffast-math and see what happens ...


    Thanks, Eric. Actually, I first compiled it without any
    special -switches at all, and got some nan's in the output.
    The -ffast-math helped pin down the culprit by exaggerating
    the nan problem. Otherwise, it didn't show up in loglinterp()
    at all. And anyway, I wouldn't want to "solve" the problem by
    hiding it. I'd think a correct program should run correctly
    with or without -ffast-math.
    --
    John Forkosh ( mailto: where j=john and f=forkosh )
     
    JohnF, Nov 14, 2010
    #4
  5. JohnF

    Alan Curry Guest

    In article <ibmfh9$foe$>,
    JohnF <> wrote:
    >I'm having trouble debugging some apparent nan problem.
    >Checking with isnan() seems okay, but printf() just prints
    >nan anyway. I'm running gcc 4.2.4, under linux (slackware 12.2


    This is plausibly a compiler bug, so before digging too deep, you should
    first try to reproduce the result with the newest version of the compiler you
    can get your hands on.

    The first rule of compiler bugs is that if you think you found one, you
    probably didn't. The second rule is if you did find one, it's probably
    already been found and fixed by someone else.

    Besides, gcc-4.2 is no longer a maintained branch, which means that even if
    you did find a previously unknown bug, nobody will care unless a newer
    version is also affected.

    --
    Alan Curry
     
    Alan Curry, Nov 14, 2010
    #5
  6. JohnF

    Tim Prince Guest

    On 11/14/2010 2:06 PM, JohnF wrote:
    > Eric Sosman wrote:
    >> JohnF wrote:
    >>> I'm having trouble debugging some apparent nan problem.
    >>> Checking with isnan() seems okay, but printf() just prints
    >>> nan anyway. I'm running gcc 4.2.4, under linux (slackware 12.2
    >>> with default packages/libs/etc), and for debugging purposes
    >>> have compiled with -ffast-math. [...]
    >>> What could be going on, and how do I proceed to debug it?

    >>
    >> The info for my copy of gcc says that -ffast-math "can
    >> result in incorrect output..." The info doesn't describe the
    >> kinds of incorrectness that might occur, but perhaps if you
    >> dig into the matter you'll find an explanation.
    >> Or you could omit -ffast-math and see what happens ...

    >
    > Thanks, Eric. Actually, I first compiled it without any
    > special -switches at all, and got some nan's in the output.
    > The -ffast-math helped pin down the culprit by exaggerating
    > the nan problem. Otherwise, it didn't show up in loglinterp()
    > at all. And anyway, I wouldn't want to "solve" the problem by
    > hiding it. I'd think a correct program should run correctly
    > with or without -ffast-math.

    -ffast-math can easily provoke a NaN from a sequence of operations which
    would produce finite results without that option. For example, x/y could
    in effect become (1/y) * x; should 1/y overflow, a zero could be
    produced "erroneously," then, further arithmetic involving those
    results could produce NaN. Also, -ffast-math allows parentheses to be
    treated K&R fashion (ignored, according to usual algebraic rules), in
    violation of standard C rules.
    It's certainly possible that making your code more reliable will allow
    it to work with and without -ffast-math.

    --
    Tim Prince
     
    Tim Prince, Nov 15, 2010
    #6
  7. JohnF

    JohnF Guest

    Tim Prince wrote:
    > JohnF wrote:
    >> Eric Sosman wrote:
    >>> JohnF wrote:
    >>>> I'm having trouble debugging some apparent nan problem.
    >>>> Checking with isnan() seems okay, but printf() just prints
    >>>> nan anyway. I'm running gcc 4.2.4, under linux (slackware 12.2
    >>>> with default packages/libs/etc), and for debugging purposes
    >>>> have compiled with -ffast-math. [...]
    >>>> What could be going on, and how do I proceed to debug it?
    >>>
    >>> The info for my copy of gcc says that -ffast-math "can
    >>> result in incorrect output..." The info doesn't describe the
    >>> kinds of incorrectness that might occur, but perhaps if you
    >>> dig into the matter you'll find an explanation.
    >>> Or you could omit -ffast-math and see what happens ...

    >>
    >> Thanks, Eric. Actually, I first compiled it without any
    >> special -switches at all, and got some nan's in the output.
    >> The -ffast-math helped pin down the culprit by exaggerating
    >> the nan problem. Otherwise, it didn't show up in loglinterp()
    >> at all. And anyway, I wouldn't want to "solve" the problem by
    >> hiding it. I'd think a correct program should run correctly
    >> with or without -ffast-math.

    >
    > -ffast-math can easily provoke a NaN from a sequence of operations which
    > would produce finite results without that option. For example, x/y could
    > in effect become (1/y) * x; should 1/y overflow, a zero could be
    > produced "erroneously," then, further arithmetic involving those
    > results could produce NaN.


    Thanks, Tim. As mentioned to Eric, I first compiled without any
    special -switches, and noticed nan's in the output. So that probably
    reflects some actual code error on my part, rather than some compiler
    artifact from order of execution, or whatever. The -ffast-math did,
    in fact, produce a few more nan's than without it, helping me locate
    a common "bottleneck" at loglinterp() through which all the bad
    numbers seem to pass. Now I can try to trace back from there to the
    source (and then hopefully cause) of the bad numbers. And that can
    probably now be done with or without -ffast-math in the compile.

    > Also, -ffast-math allows parentheses to be
    > treated K&R fashion (ignored, according to usual algebraic rules), in
    > violation of standard C rules.
    > It's certainly possible that making your code more reliable will allow
    > it to work with and without -ffast-math.


    I'll be happy to get it working without. I had no particular interest
    in the switch until I noticed nan errors in the output and started
    trying to debug.
    --
    John Forkosh ( mailto: where j=john and f=forkosh )
     
    JohnF, Nov 15, 2010
    #7
  8. JohnF

    JohnF Guest

    Alan Curry <> wrote:
    > JohnF <> wrote:
    >>I'm having trouble debugging some apparent nan problem.
    >>Checking with isnan() seems okay, but printf() just prints
    >>nan anyway. I'm running gcc 4.2.4, under linux (slackware 12.2

    >
    > This is plausibly a compiler bug, so before digging too deep, you should
    > first try to reproduce the result with the newest version of the compiler you
    > can get your hands on.
    >
    > The first rule of compiler bugs is that if you think you found one, you
    > probably didn't. The second rule is if you did find one, it's probably
    > already been found and fixed by someone else.
    >
    > Besides, gcc-4.2 is no longer a maintained branch, which means that even if
    > you did find a previously unknown bug, nobody will care unless a newer
    > version is also affected.


    Thanks, Alan, but I'm not all that concerned about following up
    on a (rather benign in this case) putative compiler bug.
    It's not affecting (as far as I know) my program, just my
    debugging process. So the compiler bug, if that's what it is,
    won't affect me at all after the program is debugged.
    And James, from the other post, suggested a workaround --
    sprintf the number and check the string for "nan".
    If printf is printing nan, then that ought to work
    regardless of isnan()'s inconsistent return value.
    And that'll solve my immediate problem, compiler bug or not.
    (Now all I have to do is actually debug the silly program.)
    --
    John Forkosh ( mailto: where j=john and f=forkosh )
     
    JohnF, Nov 15, 2010
    #8
  9. JohnF

    Nick Bowler Guest

    On Sat, 13 Nov 2010 16:48:42 +0000, JohnF wrote:
    > It seems that isnan(y2) must be false since it prints 0 for the nanerror
    > variable, but then it prints nan for y2 anyway. What could be going on,
    > and how do I proceed to debug it? Thanks,


    Since I didn't see it posted elsewhere in this thread, it should be
    noted that GCC's -ffast-math option implies -ffinite-math-only, which
    tells the compiler that it may assume all floating point values are
    finite. This means that GCC can and will replace all calls to isnan or
    isinf with a constant 0.
     
    Nick Bowler, Nov 16, 2010
    #9
  10. JohnF

    jacob navia Guest

    Le 16/11/10 20:04, Nick Bowler a écrit :
    > On Sat, 13 Nov 2010 16:48:42 +0000, JohnF wrote:
    >> It seems that isnan(y2) must be false since it prints 0 for the nanerror
    >> variable, but then it prints nan for y2 anyway. What could be going on,
    >> and how do I proceed to debug it? Thanks,

    >
    > Since I didn't see it posted elsewhere in this thread, it should be
    > noted that GCC's -ffast-math option implies -ffinite-math-only, which
    > tells the compiler that it may assume all floating point values are
    > finite. This means that GCC can and will replace all calls to isnan or
    > isinf with a constant 0.
    >



    !!!!!!!!!!!!!!!!!!!!!!!!

    This is one of the worst bugs of gcc I have ever seen.

    Buggy by design!

    How can the compiler possibly replace all isnan() by zero?
    And by an IMPLICIT RULE. Nowhere in the documentation is mentioned that
    calls to isnan() will be ignored. It just says:

    -ffinite-math-only
    Allow optimizations for floating-point arithmetic that assume that
    arguments and results are not NaNs or +-Infs.

    This option should never be turned on by any -O option since it can
    result in incorrect output for programs which depend on an exact
    implementation of IEEE or ISO rules/specifications.

    The default is -fno-finite-math-only.

    Reading this, I understand that the compiler "assumes that arguments and
    results are not NANs. Nowhere is said that a function call to isnan()
    will be IGNORED.

    Well...

    THERE IS NO WARRANTY FOR THE PROGRAM, THE ENTIRE RISK AS TO THE QUALITY
    AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
    DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
    CORRECTION.
     
    jacob navia, Nov 16, 2010
    #10
  11. jacob navia <> writes:
    > Le 16/11/10 20:04, Nick Bowler a écrit :
    >> On Sat, 13 Nov 2010 16:48:42 +0000, JohnF wrote:
    >>> It seems that isnan(y2) must be false since it prints 0 for the nanerror
    >>> variable, but then it prints nan for y2 anyway. What could be going on,
    >>> and how do I proceed to debug it? Thanks,

    >>
    >> Since I didn't see it posted elsewhere in this thread, it should be
    >> noted that GCC's -ffast-math option implies -ffinite-math-only, which
    >> tells the compiler that it may assume all floating point values are
    >> finite. This means that GCC can and will replace all calls to isnan or
    >> isinf with a constant 0.

    >
    > !!!!!!!!!!!!!!!!!!!!!!!!
    >
    > This is one of the worst bugs of gcc I have ever seen.
    >
    > Buggy by design!
    >
    > How can the compiler possibly replace all isnan() by zero?
    > And by an IMPLICIT RULE. Nowhere in the documentation is mentioned that
    > calls to isnan() will be ignored. It just says:
    >
    > -ffinite-math-only
    > Allow optimizations for floating-point arithmetic that assume that
    > arguments and results are not NaNs or +-Infs.
    >
    > This option should never be turned on by any -O option since it can
    > result in incorrect output for programs which depend on an exact
    > implementation of IEEE or ISO rules/specifications.
    >
    > The default is -fno-finite-math-only.
    >
    > Reading this, I understand that the compiler "assumes that arguments and
    > results are not NANs. Nowhere is said that a function call to isnan()
    > will be IGNORED.


    The option is not enabled by default, and the documentation, which
    you've just quoted, says what it does. It's obviously intended
    for use with programs that are known not to generate anything other
    than finite real numbers (no NaNs, no infinities, etc.).

    If your program is calling isnan(), you obviously care about
    whether some value in your program is a NaN -- and you obviously
    shouldn't be using -ffinite-math-only to compile it. That option
    doesn't prevent the generation of NaNs and infinities, it permits
    the compiler to assume that *your program* doesn't generate them.

    You're complaining that an option that, according to its
    documentation, "can result in incorrect output" can result in
    incorrect output.

    Note that isnan() is provided by glibc, not by gcc, though gcc
    might optimize calls to it in some cases.

    And you're assuming that Nick's statement about gcc's behavior is
    correct. It's not an unreasonable inference from the documentation,
    but a quick experiment doesn't support his statement; in a small test
    program compiled with -ffinite-math-only, isnan() returns 1. Nick,
    do you know something about this beyond what gcc's documentation
    states?

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Nov 16, 2010
    #11
  12. JohnF

    jacob navia Guest

    Le 16/11/10 22:36, Keith Thompson a écrit :
    You are confusing

    The option given by the user was

    -ffast-math

    and THAT option turns on IMPLICITELY finite-math

    But obviously, you are right.

    When I buy a coffee machine "guaranted 3 months",
    I can't fix it in the store because in a very small paragraph
    of the thick contract (that was less than gcc's doc about options)
    was written in small print that "I have to pay the transport to
    the workshop"... that costs more than the machine

    Clever isn't it?
     
    jacob navia, Nov 17, 2010
    #12
  13. On Nov 16, 5:36 pm, Keith Thompson <> wrote:
    > jacob navia <> writes:
    > > Le 16/11/10 20:04, Nick Bowler a écrit :
    > >> On Sat, 13 Nov 2010 16:48:42 +0000, JohnF wrote:
    > >>> It seems that isnan(y2) must be false since it prints 0 for the nanerror
    > >>> variable, but then it prints nan for y2 anyway. What could be going on,
    > >>> and how do I proceed to debug it? Thanks,

    >
    > >> Since I didn't see it posted elsewhere in this thread, it should be
    > >> noted that GCC's -ffast-math option implies -ffinite-math-only, which
    > >> tells the compiler that it may assume all floating point values are
    > >> finite.  This means that GCC can and will replace all calls to isnan or
    > >> isinf with a constant 0.

    >
    > > !!!!!!!!!!!!!!!!!!!!!!!!

    >
    > > This is one of the worst bugs of gcc I have ever seen.

    >
    > > Buggy by design!

    >
    > > How can the compiler possibly replace all isnan() by zero?
    > > And by an IMPLICIT RULE. Nowhere in the documentation is mentioned that
    > > calls to isnan() will be ignored. It just says:

    >
    > >      -ffinite-math-only
    > >      Allow optimizations for floating-point arithmetic that assume that
    > >      arguments and results are not NaNs or +-Infs.

    >
    > >      This option should never be turned on by any -O option since it can
    > >      result in incorrect output for programs which depend on an exact
    > >      implementation of IEEE or ISO rules/specifications.

    >
    > >      The default is -fno-finite-math-only.

    >
    > > Reading this, I understand that the compiler "assumes that arguments and
    > > results are not NANs. Nowhere is said that a function call to isnan()
    > > will be IGNORED.

    >
    > The option is not enabled by default, and the documentation, which
    > you've just quoted, says what it does.  It's obviously intended
    > for use with programs that are known not to generate anything other
    > than finite real numbers (no NaNs, no infinities, etc.).
    >
    > If your program is calling isnan(), you obviously care about
    > whether some value in your program is a NaN -- and you obviously
    > shouldn't be using -ffinite-math-only to compile it.  That option
    > doesn't prevent the generation of NaNs and infinities, it permits
    > the compiler to assume that *your program* doesn't generate them.
    >
    > You're complaining that an option that, according to its
    > documentation, "can result in incorrect output" can result in
    > incorrect output.
    >
    > Note that isnan() is provided by glibc, not by gcc, though gcc
    > might optimize calls to it in some cases.
    >
    > And you're assuming that Nick's statement about gcc's behavior is
    > correct.  It's not an unreasonable inference from the documentation,
    > but a quick experiment doesn't support his statement; in a small test
    > program compiled with -ffinite-math-only, isnan() returns 1.  Nick,
    > do you know something about this beyond what gcc's documentation
    > states?
    >




    It may depend on optimization level. If you specify
    -ffinite-math-only and pass isnan a NAN there is no
    expected behaviour. At low opimzation isnan(x) may
    in fact determine if x is a NAN, and since the compiler
    thinks it knows that x is not a NAN the compiler thinks
    this is a slow way of getting 0. At higher optimizations
    the compiler may choose a fast way of getting 0.

    - William Hughes




    > --
    > Keith Thompson (The_Other_Keith)  <http://www.ghoti.net/~kst>
    > Nokia
    > "We must do something.  This is something.  Therefore, we must do this."
    >     -- Antony Jay and Jonathan Lynn, "Yes Minister"- Hide quoted text -
    >
    > - Show quoted text -
     
    William Hughes, Nov 17, 2010
    #13
  14. jacob navia <> writes:
    > Le 16/11/10 22:36, Keith Thompson a écrit :
    > You are confusing
    >
    > The option given by the user was
    >
    > -ffast-math
    >
    > and THAT option turns on IMPLICITELY finite-math
    >
    > But obviously, you are right.
    >
    > When I buy a coffee machine "guaranted 3 months",
    > I can't fix it in the store because in a very small paragraph
    > of the thick contract (that was less than gcc's doc about options)
    > was written in small print that "I have to pay the transport to
    > the workshop"... that costs more than the machine
    >
    > Clever isn't it?


    You are misrepresenting the situation.

    Surely you wouldn't consider using -ffast-math without reading the
    documentation. If you did so, you would know that it can result in
    incorrect output, because the documentation says so in so many words.
    And if you hadn't read the documentation, you probably wouldn't know
    that -ffast-math exists, and you'd be safe.

    This is not fine print.

    (Nor is it really about C.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Nov 17, 2010
    #14
  15. JohnF

    JohnF Guest

    Keith Thompson <> wrote:
    >
    > If your program is calling isnan(), you obviously care about
    > whether some value in your program is a NaN -- and you obviously
    > shouldn't be using -ffinite-math-only to compile it. That option
    > doesn't prevent the generation of NaNs and infinities, it permits
    > the compiler to assume that *your program* doesn't generate them.
    >
    > You're complaining that an option that, according to its
    > documentation, "can result in incorrect output" can result in
    > incorrect output.


    I'm sorry for starting this sequence of posts. Note that I've
    already twice explained above how I wasn't too clear in my
    original post. Here's what happened...
    o I resurrected some old code from 1991-1992, which was
    exhaustively tested (by groups in both New York, which
    included me, and in Tampa) and it all worked fine then.
    That archived code includes test suites of data and
    their output.
    o Made a few changes, e.g., our function valloc() subsequently
    became part of gcc, so I #define'd it away to a non-colliding
    name.
    o Got it to all compile/link fine, but execution now generates
    occasional nan's in the output. 24 nan's in the usual output.
    o So I scattered some isnan()'s where I thought they'd do the
    most good, along with some extra output if signalled by a nan.
    For example,
    Coarse Price Tree
    ---------nan---------nan---------nan---------nan---------nan-------
    (37) (38) (39) (40) (41)
    nan (0)
    nan
    nan 0.48621625 (1)
    nan 0.50008069
    nan 0.51509498 0.51001222 (2)
    0.53033953 0.52437862
    0.54581746 0.53987707 0.53454707 (3)
    0.55560027 0.54939660
    0.57155027 0.56535715 0.55977253 (4)
    0.58153494 0.57508219
    0.59793103 0.59147873 0.58563206 (5)
    That's very helpful and suggestive, but deeper checks still didn't
    isolate the "obvious" (or so I thought) problem.
    o ***ONLY THEN*** did I look at man gcc for some debugging
    ideas, and gave -ffast-math a try, just to see what might
    happen. I was kind of hoping program might just segfault
    somewhere useful, but no such luck.
    o My original post didn't explain all that correctly.
    o Nevertheless, James Walby suggested a good trick --
    write my own isnan macro that first uses isnan, and
    if that's zero then sprintf the number and strstr() the
    buffer for "nan". That'll work even with -ffast-math.
    o Still haven't found the problem, and haven't bothered
    with -ffast-math any more, either, since it provides
    no additional information, anyway.

    So -ffast-math seems to behave as documented, suppressing the
    isnan() signal. That's no problem with James' workaround,
    but it unfortunately still didn't provide any additional helpful
    debugging info to me for my particular situation.
    --
    John Forkosh ( mailto: where j=john and f=forkosh )
     
    JohnF, Nov 17, 2010
    #15
  16. William Hughes <> writes:
    > On Nov 16, 5:36 pm, Keith Thompson <> wrote:

    [...]
    >> And you're assuming that Nick's statement about gcc's behavior is
    >> correct.  It's not an unreasonable inference from the documentation,
    >> but a quick experiment doesn't support his statement; in a small test
    >> program compiled with -ffinite-math-only, isnan() returns 1.  Nick,
    >> do you know something about this beyond what gcc's documentation
    >> states?

    >
    > It may depend on optimization level. If you specify
    > -ffinite-math-only and pass isnan a NAN there is no
    > expected behaviour. At low opimzation isnan(x) may
    > in fact determine if x is a NAN, and since the compiler
    > thinks it knows that x is not a NAN the compiler thinks
    > this is a slow way of getting 0. At higher optimizations
    > the compiler may choose a fast way of getting 0.


    Using higher optimization levels doesn't guarantee that isnan() returns
    0, but it can do so, even when the program logic otherwise implies that
    the argument is a NaN.

    Consider this program:

    #include <stdio.h>
    #include <math.h>
    #include <time.h>
    int main (void)
    {
    double x = 0.0;
    if (time(NULL) > 1290000000) {
    puts("setting x to NaN");
    x = nan("");
    }
    printf("x = %g, isnan(x) = %d\n", x, isnan(x));
    return 0;
    }

    The time() test is intended to cause the assignment to occur
    without letting the optimizer know that it's certain to happen.
    (time_t)1290000000 was a few hours ago. I'm making a non-portable
    assumption about how time_t represents times. I could have made
    it more portable using mktime(), but I didn't bother.

    With "gcc -O0 -ffast-math -std=c99 c.c -lm -o c", the output is:

    setting x to NaN
    x = nan, isnan(x) = 1

    With "gcc -O1 -ffast-math -std=c99 c.c -lm -o c", the output is:

    setting x to NaN
    x = 0, isnan(x) = 0

    Using -ffinite-math-only rather than -ffast-math produces the same
    results.

    So these options *are behaving as their documentation describes
    them*. The program depends on IEEE and/or ISO rules for math
    functions, and the options result in incorrect output. The solution
    is simple: don't use "-ffast-math" or "-ffinite-math-only" for
    this program; use them only for programs that don't depend on
    correct behavior for infinities and NaNs, and for which the speed
    improvement is worth the loss of standard conformance. (I haven't
    measured it, but I'd guess that they can be quite useful for some
    programs that are numerically well-behaved.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Nov 17, 2010
    #16
  17. JohnF

    Nick Bowler Guest

    On Wed, 17 Nov 2010 11:04:37 -0800, Keith Thompson wrote:
    [...]
    >> On Nov 16, 5:36 pm, Keith Thompson <> wrote:
    >>> And you're assuming that Nick's statement about gcc's behavior is
    >>> correct.  It's not an unreasonable inference from the documentation,
    >>> but a quick experiment doesn't support his statement; in a small test
    >>> program compiled with -ffinite-math-only, isnan() returns 1.  Nick, do
    >>> you know something about this beyond what gcc's documentation states?

    [...]
    > Using higher optimization levels doesn't guarantee that isnan() returns
    > 0, but it can do so, even when the program logic otherwise implies that
    > the argument is a NaN.


    Sorry, I didn't mean to imply that isnan was *guaranteed* to be replaced
    with a constant zero (my use of the word "all" was not a good one). I
    was intending to suggest that the compiler is well within its rights to
    optimize the calls away, and that it will do so in some cases.

    As a side note, one can elicit more reliable behaviour (I still have no
    idea if we can *guarantee* a particular result) from GCC by calling its
    builtins directly instead of using the macros provided by the C library
    (which may or may not be implemented using GCC's builtins).
     
    Nick Bowler, Nov 17, 2010
    #17
  18. JohnF

    James Waldby Guest

    On Wed, 17 Nov 2010 11:04:37 -0800, Keith Thompson wrote:
    > William Hughes writes:
    >> On Nov 16, 5:36 pm, Keith Thompson wrote:

    ....
    >> It may depend on optimization level. If you specify -ffinite-math-only
    >> and pass isnan a NAN there is no expected behaviour. At low optimization
    >> isnan(x) may in fact determine if x is a NAN, and since the compiler

    ....
    > Using higher optimization levels doesn't guarantee that isnan() returns
    > 0, but it can do so, even when the program logic otherwise implies that
    > the argument is a NaN.

    ....
    > #include <stdio.h>
    > #include <math.h>
    > #include <time.h>
    > int main (void)
    > {
    > double x = 0.0;
    > if (time(NULL) > 1290000000) {
    > puts("setting x to NaN");
    > x = nan("");
    > }
    > printf("x = %g, isnan(x) = %d\n", x, isnan(x)); return 0;
    > }
    >
    > The time() test is intended to cause the assignment to occur without

    ....
    > With "gcc -O0 -ffast-math -std=c99 c.c -lm -o c", the output is:
    >
    > setting x to NaN
    > x = nan, isnan(x) = 1
    >
    > With "gcc -O1 -ffast-math -std=c99 c.c -lm -o c", the output is:
    >
    > setting x to NaN
    > x = 0, isnan(x) = 0

    [snip conclusions]

    On my linux (old fedora) system with gcc 4.1.2 I was unable to replicate
    your second result, ie got "x = nan, isnan(x) = 1" for both cases.

    Although you didn't explicitly conclude that isnan(x) got optimized away,
    that seemed to be the drift of your thoughts. Conceivably nan() got
    optimized away instead of (or as well as) isnan(). Replacing the middle
    lines of your code with something like following could check if so:

    union {double x; long unsigned int y; } u = { 1.0 };
    printf("sizeof x = %ld sizeof y = %ld\n", sizeof u.x, sizeof u.y);
    printf("x = %8g = %16lx, isnan(x) = %d\n", u.x, u.y, isnan(u.x));
    if (time(NULL) > 1290000000) {
    puts("setting x to NaN");
    u.x = nan("");
    }
    printf("x = %8g = %16lx, isnan(x) = %d\n", u.x, u.y, isnan(u.x));

    On my system, output in both compile cases is:

    sizeof x = 8 sizeof y = 8
    x = 1 = 3ff0000000000000, isnan(x) = 0
    setting x to NaN
    x = nan = 7ff8000000000000, isnan(x) = 1

    --
    jiw
     
    James Waldby, Nov 17, 2010
    #18
  19. James Waldby <> writes:
    > On Wed, 17 Nov 2010 11:04:37 -0800, Keith Thompson wrote:
    >> William Hughes writes:
    >>> On Nov 16, 5:36 pm, Keith Thompson wrote:

    > ...
    >>> It may depend on optimization level. If you specify -ffinite-math-only
    >>> and pass isnan a NAN there is no expected behaviour. At low optimization
    >>> isnan(x) may in fact determine if x is a NAN, and since the compiler

    > ...
    >> Using higher optimization levels doesn't guarantee that isnan() returns
    >> 0, but it can do so, even when the program logic otherwise implies that
    >> the argument is a NaN.

    > ...
    >> #include <stdio.h>
    >> #include <math.h>
    >> #include <time.h>
    >> int main (void)
    >> {
    >> double x = 0.0;
    >> if (time(NULL) > 1290000000) {
    >> puts("setting x to NaN");
    >> x = nan("");
    >> }
    >> printf("x = %g, isnan(x) = %d\n", x, isnan(x)); return 0;
    >> }
    >>
    >> The time() test is intended to cause the assignment to occur without

    > ...
    >> With "gcc -O0 -ffast-math -std=c99 c.c -lm -o c", the output is:
    >>
    >> setting x to NaN
    >> x = nan, isnan(x) = 1
    >>
    >> With "gcc -O1 -ffast-math -std=c99 c.c -lm -o c", the output is:
    >>
    >> setting x to NaN
    >> x = 0, isnan(x) = 0

    > [snip conclusions]
    >
    > On my linux (old fedora) system with gcc 4.1.2 I was unable to replicate
    > your second result, ie got "x = nan, isnan(x) = 1" for both cases.
    >
    > Although you didn't explicitly conclude that isnan(x) got optimized away,
    > that seemed to be the drift of your thoughts. Conceivably nan() got
    > optimized away instead of (or as well as) isnan(). Replacing the middle
    > lines of your code with something like following could check if so:
    >
    > union {double x; long unsigned int y; } u = { 1.0 };
    > printf("sizeof x = %ld sizeof y = %ld\n", sizeof u.x, sizeof u.y);
    > printf("x = %8g = %16lx, isnan(x) = %d\n", u.x, u.y, isnan(u.x));
    > if (time(NULL) > 1290000000) {
    > puts("setting x to NaN");
    > u.x = nan("");
    > }
    > printf("x = %8g = %16lx, isnan(x) = %d\n", u.x, u.y, isnan(u.x));
    >
    > On my system, output in both compile cases is:
    >
    > sizeof x = 8 sizeof y = 8
    > x = 1 = 3ff0000000000000, isnan(x) = 0
    > setting x to NaN
    > x = nan = 7ff8000000000000, isnan(x) = 1


    Here's the program with your suggested changes. (I used unsigned long
    long rather than unsigned long, which is only 32 bits on my system; I
    also fixed a couple of other things):

    #include <stdio.h>
    #include <math.h>
    #include <time.h>
    int main (void)
    {
    union { double x; long long unsigned int y; } u = { 1.0 };
    printf("sizeof u.x = %zu sizeof u.y = %zu\n",
    sizeof u.x, sizeof u.y);
    printf("u.x = %8g, u.y = %16llx, isnan(u.x) = %d\n",
    u.x, u.y, isnan(u.x));
    if (time(NULL) > 1290000000) {
    puts("setting u.x to NaN");
    u.x = nan("");
    }
    printf("u.x = %8g, u.y = %16llx, isnan(u.x) = %d\n",
    u.x, u.y, isnan(u.x));

    return 0;
    }

    With "-O0 -ffinite-math-only" and "-O1 -ffinite-math-only", the output is:

    sizeof u.x = 8 sizeof u.y = 8
    u.x = 1, u.y = 3ff0000000000000, isnan(u.x) = 0
    setting u.x to NaN
    u.x = nan, u.y = 7ff8000000000000, isnan(u.x) = 1

    With "-O2 -ffinite-math-only" and "-O3 -ffinite-math-only", the output is:

    sizeof u.x = 8 sizeof u.y = 8
    u.x = 1, u.y = 3ff0000000000000, isnan(u.x) = 0
    setting u.x to NaN
    u.x = 1, u.y = 7ff8000000000000, isnan(u.x) = 0

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Nov 17, 2010
    #19
  20. JohnF

    Nobody Guest

    On Tue, 16 Nov 2010 20:45:59 +0100, jacob navia wrote:

    > Reading this, I understand that the compiler "assumes that arguments and
    > results are not NANs. Nowhere is said that a function call to isnan()
    > will be IGNORED.


    Which amounts to the same thing. If you don't understand this, you should
    choose a different field of endeavour.

    If the compiler assumes that values are never NaN, it can optimise isnan()
    to constant zero. The usual point of making assumptions is to enable such
    optimisations.

    If isnan() actually did something, the compiler *wouldn't* be assuming
    that values are never NaN, would it?
     
    Nobody, Nov 19, 2010
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?c2lhag==?=

    isNaN function jscript

    =?Utf-8?B?c2lhag==?=, Mar 8, 2005, in forum: ASP .Net
    Replies:
    4
    Views:
    2,801
    =?Utf-8?B?c2lhag==?=
    Mar 8, 2005
  2. Christopher Benson-Manica
    Replies:
    0
    Views:
    434
    Christopher Benson-Manica
    May 11, 2004
  3. Skybuck Flying
    Replies:
    5
    Views:
    867
  4. Priya

    isinf() & isnan()

    Priya, Sep 19, 2006, in forum: C++
    Replies:
    2
    Views:
    636
    Priya
    Sep 19, 2006
  5. jacob navia

    isnan() for complex data

    jacob navia, Feb 4, 2008, in forum: C++
    Replies:
    5
    Views:
    543
    Barry
    Feb 5, 2008
Loading...

Share This Page