Perl’s special not a numbers

Perl has some “numbers” that aren’t really numbers. Or, it has them if your underlying C library supports them.

The first, the “not a number”, is the string “NaN”, in any case. This isn’t a single value. The standard for floating-point numbers, IEEE 754. This value, which isn’t a number, returns itself in any mathematical operation.

Before we look at that, though, remember what Perl does with strings that might be numbers. As we explain in the “Scalars” chapter, Perl grabs decimal number characters from the start of the string. When it encounters something that doesn’t look like it belongs in a decimal number, it stops. Whatever it grabbed so far becomes the number. For instance, "1234fred" becomes 1234 while "fred" becomes the empty string which becomes 0.

$ perl -le 'print "1234fred" + 1'
1235

$ perl -le 'print "fred" + 1'
1

$ perl -le 'print "1234fred" * 1'
1234

$ perl -le 'print "fred" * 1'
0

NaN

If we applied Perl’s basic rule to the string "NaN", we’d expect to get 0, because we didn’t tell you about this special value in Learning Perl. It’s one of the white lies we tell so we don’t fill your head with stuff you probably won’t need. Now here’s some stuff you might not need:

$ perl -le 'print "NaN" + 1'
nan

$ perl -le 'print "NaN" * 1'
nan

$ perl -le 'print log( "NaN" )'
nan

$ perl -le 'print sin( "NaN" )'
nan

Any calculations we try to do with this value turns the rest of the results into "NaN". It won’t accidentally turn into 0, making you think that your calculation is accurate or destroying all values in multiplication.

But, it gets trickier. It’s more than just the string "NaN" that turns into this special value. Any string that starts with "NaN" also turns into “not a number”:

$ perl -le 'print "Nandor" + 1'
nan

Is that it? Not quite. Perl will allow ignore a leading + or - sign as well:

$ perl -le 'print "+NaN"'
nan

$ perl -le 'print "-Nandor"'
nan

$ perl -le 'print "+Nandor"'
nan

There’s another curious thing. The spaceship operator <=> normally returns 1, 0, or -1. If one of the operands is "NaN", the operator returns undef. We didn’t tell you that <=> could do that.

Also, "NaN" isn’t numerically equal to itself, which is curious since undef is:

$ perl -le 'print "Not the same!" unless "NaN" == "NaN"'
Not the same!

$ perl -le 'print "Not the same!" unless undef == undef'

In fact, "NaN" is never equal to anything, so "NaN" != "NaN" if true. This means, then, that to check if a perl supports "NaN", we can test:

die "This perl does not support NaN!\n" if "NaN" == "NaN";

In the case where a perl does not support this, we’re back to the original string-to-number conversion rule that returns 0.

See the perlop documentation.

Infinity

Similarly, Perl recognizes the special value Inf, +Inf, -Inf, Infinity. These and their variations return "inf". When we use them in a multiplication, we get "inf" again:

$ perl -le 'print 1 * "inf"'
inf

$ perl -le 'print 1 + "inf"'
inf

Normally, dividing by a zero or a non-number string kills the program:

$ perl -le 'print 1/0'
Illegal division by zero at -e line 1.

$ perl -le 'print 1/"fred"'
Illegal division by zero at -e line 1.

Dividing by an Infinity variant, however, returns its limit, which is 0:

$ perl -le 'print 1/"inf"'
0

$ perl -le 'print 1/"-inf"'
0

There is the possibility of a -0 too, if the underlying C library handles that. It’s the same as regular 0. From my normal Mac OS X I switched to FreeBSD to find a negative zero:

freebsd$ perl -le 'print 1 / "inf"'
0

freebsd$ perl -le 'print 1 / "-inf"'
-0

3 thoughts on “Perl’s special not a numbers”

  1. Using Strawberry Perl 5.12 (Windows command prompt): >perl -le “print ‘NaN’ + 1” returns >1

  2. 2 important additional points:

    1. Perl changed Inf returns since you wrote this. This breaks code that checks equality with eq instead of ==. You should test with == instead of eq, but not all code can do this because some people like to use Perl because they like to mix types.

    $ perl -e '$x="inf"+1; print $x'
    Inf
    

    2. You can’t assign inf directly. In the example below, $x==, but it is not yet Inf, so if you test it as a string it will return ‘inf’.

    $ perl -e '$x="inf"; print $x'
    inf
    
    1. I haven’t had a problem assigning Inf or NaN directly on macOS on Perl v5.28. Some differences in behavior are likely due to the underlying libraries and how they handle these.

Comments are closed.