Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

NaNs are true

by syphilis (Archbishop)
on Feb 26, 2011 at 13:15 UTC ( [id://890299]=perlquestion: print w/replies, xml ) Need Help??

syphilis has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

A NaN (Not a Number) evaluates as "true" in both Perl and C. That seems a bit counter-intuitive to me. Are there sound, well thought out reasons for having a NaN deemed to be true, or is it just done that way for historical reasons ?

Here's a simple demo:
use warnings; use strict; my $inf = 99**99**99; my $nan = $inf / $inf; if($nan != $nan) {print "\$nan is a nan\n"} else {die "$nan is not a nan\n"} if($nan) {print "nans are true\n"} else {print "nans are false\n"} __END__ Outputs: $nan is a nan nans are true
In both Math::MPFR and Math::MPC, I've overloaded 'bool' so that a NaN is false ... mainly because it struck me as being the logical thing to do.
Now I'm wondering whether that was a mistake. (I couldn't google up any information that helped clarify things for me.)
For a Math::MPFR demo:
use warnings; use strict; use Math::MPFR; my $nan = Math::MPFR->new(); if($nan != $nan) {print "\$nan is a nan\n"} else {die "$nan is not a nan\n"} if($nan) {print "nans are true\n"} else {print "nans are false\n"} __END__ Outputs: $nan is a nan nans are false
Any thoughts ?

Cheers,
Rob

Replies are listed 'Best First'.
Re: NaNs are true
by Corion (Patriarch) on Feb 26, 2011 at 13:29 UTC

    As far as I understand it, a NaN signals more or less an error condition or the value of an operation whose result is undefined.

    If you subscribe to that understanding, then a NaN could be seen closer to undef than to a nonzero number, and because undef is false, so could be NaN.

    On the other hand, we already have undef, and I'm not sure whether it makes sense to introduce another form of undef, the "numerical undef", and what can of worms that opens (if any). I'm reminded of SQL and its various (theoretical) incarnations of NULL that you'd need if you went beyond 3NF.

      I'm mainly wondering whether someone might be astounded that I've overloaded 'bool' in such a way that the NaN value in a Math::MPFR object is false:
      "Whoa !! ... NaN is false ? Where the hell does that come from ? ... certainly not in perl or C !!"

      Probably not worth thinking too deeply about - most people won't know, and the rest won't care ;-)

      Cheers,
      Rob
Re: NaNs are true
by CountZero (Bishop) on Feb 26, 2011 at 16:33 UTC
    Isn't it much simpler than that?:
    • The number zero (0) is false.
    • The string zero ('0') is false.
    • The empty string ('') is false.
    • undef is false
    Everything else is true.

    Seems perfectly logical to me.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      Yes - that's simple and logical enough.
      It's a bit arbitrary, however. You could add NaN to that list of "falsehoods" - lose a bit of simplicity, but gain a bit of logicality, imo.

      I have this notion of perl developers sitting around deciding upon what is "true" and what is "false" .... and the NaN was not considered.
      If it *had* been considered, I would like to think that it would have been added to that list. But, for whatever reason, it's not on the list ... and I would think it will stay that way because that's the way it has always been.

      What I'm wondering is:
      Does the absence of NaN from that list mean that, in my own modules, I shouldn't overload bool to treat NaNs as false ?
      It would take a compelling argument to make me accept that "Yes, I shouldn't do that", but I don't assume that such a compelling argument doesn't exist.

      Cheers,
      Rob
        It would take a compelling argument to make me accept that "Yes, I shouldn't do that", but I don't assume that such a compelling argument doesn't exist.

        Probably not what you want to hear, but IMO Math modules should treat NaN in accordance with the following paragraphs:

        Floating point operations other than comparisons normally propagate a quiet NaN (qNaN). Floating point operations on a signaling NaN (sNaN) signal an invalid operation exception, the default exception action is then the same as for qNaN operands and they produce a qNaN if producing a floating point result.

        A comparison with a NaN always returns an unordered result even when comparing with itself. The comparison predicates are either signaling or non-signaling, the signaling versions signal an invalid exception for such comparisons. The equality and inequality predicates are non-signaling so x = x returning false can be used to test if x is a quiet NaN. The other standard comparison predicates all signal if they receive a NaN operand, the standard also provides non-signaling versions of these other predicates. The predicate isNaN(x) determines if a value is a NaN and never signals an exception.

        Which I interprete to mean that: given one or more NaN values to compare, equality operators should return false if they are of the non-signalling variety and raise an exception if the are signalling.

        As (TTBOMK), there is no concept of non-signalling/signalling NaNs anywhere else in Perl, I think there are 3 possibilities for Math modules:

        1. Opt to implement non-signalling NaNs.

          Any equality operator involving a NaN value, and any other value including NaN, +/-inf or an numeric value returns false.

          To allow the programmer to detect when they are dealing with NaN value, you either a) provide an isNaN( $x ) function; or b) allow the (somewhat bemusing) suggestion above of using die "We got a NaN\n" unless $x == $x;

        2. Opt to implement signalling NaNs.

          Any operation involving (being passed, rather than resulting in) a NaN value raises an exception.

          This at least forces the programmer to deal with the possibility.

        3. Make it configurable.

          Offer both modes of operation and let the programmer choose.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        I have this notion of perl developers sitting around deciding upon what is "true" and what is "false"
        It was probably Larry Wall sitting all by himself who decided that. And even more probable that it were just the underlying C-libraries which already used these rules.

        That being said, the real problem is that Perl5 and before do not have the concept of a "boolean" type and therefore a rule --somewhat arbitrarily-- had to be made to decide what was true and what was false.

        It is all just convention: why do people in most parts of the world nod to mean "yes", but in Greece it means "no"(*)? And why does the word "nod" contain the word "no" although it means (most of the time) "yes"? that is languages, just go with the flow or you will confuse everybody to no end.

        (*) Yes, I know it is a different kind of "nod", but it still confuses the hell out of us poor tourists.

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: NaNs are true
by jdporter (Paladin) on Feb 26, 2011 at 13:43 UTC

    From a Perl worldview, "foo" (a string) is also not a number, and is true. So, by analogy between NaN and other common things which are not a number, NaN should be true as well.

    Just an idea.

    I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
      The NaN, being an NV, is being evaluated in numeric context, not "string" context. And the string "foo", when evaluated in numeric context, will be false (0).
      I don't think there's any inconsistency there ... except perhaps that "foo", when evaluated in numeric context should really be NaN, not 0 ;-)

      Cheers,
      Rob

        "The Unicode Bug" is what happens when you have values whose meaning change based on how they are stored.

        False is "", "0" and what stringifies to these. For NaN to be false, it would have to stringify to one of these, or "NaN" would have to be false too.

        I never said anything about string context. And I thought it was pretty well understood we were talking about boolean context anyway, since you're going on about whether things evaluate to true or false.

        "foo" in boolean context is true, not false. And that was my point: "foo", being "not a number", is true; and so NaN, being "not a number", ought to be true as well (if one follows this line of reasoning). So, yes, there is no inconsistency, if one buys this logic. In which case — what are you complaining about?

        Update: Argh. I meant inconsistency. Corrected. :-P

        I reckon we are the only monastery ever to have a dungeon stuffed with 16,000 zombies.
Re: NaNs are true
by BrowserUk (Patriarch) on Feb 26, 2011 at 18:15 UTC

    Any attempt to use (a variable set to) NaN for anything, including numerical comparison with anything, including another (variable set to) NaN, or implicitly with either true or false in a conditional statement, should cause an exception.

    It is the numerical equivalent of dereferencing a null pointer.

    The only tests of NaN that (possibly) should not cause an exception, are for numerical equivalence with a predefined constant NaN, or (perhaps) stringified equivalence to a predefined constant NaN.

    Even comparison of one variable set to NaN with another variable set to NaN should raise an exception because to do otherwise would be equivalent to allowing:

    char *a = null, *b = null; if( ! strcmp( a, b ) ) { printf( "They are the same string\n"; }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Any attempt to use (a variable set to) NaN .... should cause an exception.

      That'd make it too easy ;-)

      The mpfr library actually initialises the mpfr_t data type with a value of NaN.
      It's something I sort of like - it implies (to me, anyway) that the developers, having no idea what value should be assigned initially, have quite appropriately assigned no value. It's up to the program to assign a value to the mpfr_t variable - and until that variable is assigned a value, it stays as NaN.

      With mpfr, there's also the matter of ANSI/IEEE-754 compliance - which has a strong influence on the things it does.

      If only the IEEE-754 standard had decreed "nans are to be consdered false in a boolean sense". (I don't think it does, but I'd love to be wrong about that ... otoh, I'd hate to learn that it decrees the converse.)

      I think I might run this by the mpfr folk. It's quite OT there, of course, but knowing if there's some compelling reason to keep NaNs as "true" is something that's probably "right up their alley", so to speak.

      Cheers,
      Rob
        The mpfr library actually initialises the mpfr_t data type with a value of NaN. It's something I sort of like - it implies (to me, anyway) that the developers, having no idea what value should be assigned initially, have quite appropriately assigned no value. It's up to the program to assign a value to the mpfr_t variable - and until that variable is assigned a value, it stays as NaN.

        That, to me, makes perfect sense. If the programmer creates an mpfr_t variable, and subsequently tries to perform an operation upon it withouthaving initialised it, the operation raises an exception.

        That seems to me to be directly analogous to:

        my $x; $x *= 2; Use of uninitialized value $x in multiplication (*) at ...

        Albeit that's a warning rather than fatal.

        And equivalent to the trap that occurs when:

        void something( char *x ) { printf( "%s\n", *x ); } ... char *s; something( s );

        Raising an exception if teh programmer attempt to use a NaN value in an operation means that he will know about it if it happens, but can deal with it if it is a possibility and there is something sensible that he can do.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: NaNs are true
by Anonymous Monk on Feb 26, 2011 at 14:02 UTC
    http://en.wikipedia.org/wiki/NaN
    Systematic use of NaNs was introduced by the IEEE 754 floating-point standard in 1985, along with the representation of other non-finite quantities like infinities.
Re: NaNs are true
by PeterPeiGuo (Hermit) on Feb 26, 2011 at 17:40 UTC

    For example, the square root of -1 is supposed to be nan, since it cannot be precisely represented (within the domain of real numbers). However sqrt(-1) is not 0. It makes a lot more sense to treat i (which is a non-zero number in an extended domain) as true than false.

    Peter (Guo) Pei

      Yes, there might be something in what you say that supports having NaNs evaluate as "true" in the boolean sense - but I don't think there's any compelling argument there (and I'm a bit suspicious of the way you move about between the real and complex fields :-)

      I personally don't have an issue with sqrt(-1) being "false" in the real field && "true" in the complex field.

      Cheers,
      Rob
Re: NaNs are true (!"NaN")
by tye (Sage) on Feb 27, 2011 at 05:26 UTC

    There are several Perl-like languages that decided that string '0' should be "true". While I understand the temptation to only have one string that is "false", my experience is that this choice was a mistake (in each case) -- I have seen repeated cases of bugs due to "as a string" vs "as a number" causing opposite behavior. It would be an even bigger mistake in Perl where the transformation between strings and numbers is even more implicit.

    Since you will never make the string "NaN" (or the other stringifications of NaNs) "false", I believe it would be a mistake to make a (non-string) NaN "false" in Perl.

    I also disagree that a NaN should be "false" even ignoring the stringification problem. For numbers, 0 is false. NaN is very much not zero. I assume you aren't making any of the "Inf"s "false". A NaN is more like an Inf than like a zero, so I find it unnatural to draw the circle of "is false" around such different things as zeros and NaNs while having it separate NaNs from Infs.

    I appreciate that a NaN is similar to undef. However, an undef becomes a zero whenever you treat it like a number and there are even ways for an undef to silently become a zero ($undefined++). So undef is much more like zero than a NaN is like zero.

    So I think it is very natural for undef to be "false". And I find it natural in Perl for "uninitialized" to be "false".

    So I need to address the case of an "uninitialized number". I can appreciate the value in having an uninitialized number being a NaN. And I can see the expectation that "uninitialized" would be "false" (though a bit less strongly for a strictly numeric data type since, when I test a number for "truth", I usually think of it as short-hand for comparing a number to 0). But I would be very bothered by doing a calculation like $x/$y and ending up with an "uninitialized" value, or even a false value.

    So I'd probably have an uninitialized number be a special undef type of NaN, a value that could never be generated from a calculation and that stringifies to an empty string (with a warning). I very much would not have a non-zero result of a calculation be "false" (especially when it stringifies to a "true" value).

    - tye        

      NaN is very much not zero

      More than that - in the world of numbers, NaN is very much not anything ... and I can't think of anything falser than "not anything".

      I assume you aren't making any of the "Inf"s "false"

      That's correct - an Inf is just like any other non-zero number, except bigger. No doubt in my mind that Inf should be true.

      when I test a number for "truth", I usually think of it as short-hand for comparing a number to 0

      You're probably not the only one who does that - yet I've created a situation where that's not what "truth" is testing.
      That provides an opportunity for confusion and misunderstanding to arise, which is definitely not such a good thing.

      Cheers,
      Rob

      That's all very logical, except that at the end you seem to have arrived at the situation where you would have an implicit test of a NaN against zero be true?

      NaN == 0 -> true cannot be right.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        What about idea that NaN never matches numerical comparison?
        NaN == 0 #false NaN != 0 #false NaN == NaN #false NaN != NaN #false

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://890299]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2024-04-25 19:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found