26

How do I create or test for NaN or infinite values in Perl?

ysth
  • 96,171
  • 6
  • 121
  • 214

6 Answers6

15

Here's a fairly reliable way:

my $inf    = 9**9**9;
my $neginf = -9**9**9;
my $nan    = -sin(9**9**9);

sub isinf { $_[0]==9**9**9 || $_[0]==-9**9**9 }
sub isnan { ! defined( $_[0] <=> 9**9**9 ) }
# useful for detecting negative zero
sub signbit { substr( sprintf( '%g', $_[0] ), 0, 1 ) eq '-' }

for my $num ( $inf, $neginf, $nan ) {
   printf("%s:\tisinf: %d,\tisnan: %d,\tsignbit: %d\n", $num, isinf($num), isnan($num), signbit($num));
}

Output is:

inf:    isinf: 1,   isnan: 0,   signbit: 0
-inf:   isinf: 1,   isnan: 0,   signbit: 1
nan:    isinf: 0,   isnan: 1,   signbit: 0
Borodin
  • 126,100
  • 9
  • 70
  • 144
ysth
  • 96,171
  • 6
  • 121
  • 214
  • 6
    On 5.10 and above, where the C library supports it, just 0+"nan", 0+"inf", or 0+"-inf" work too. – ysth Jul 26 '09 at 23:09
  • 1
    Very energetic of you: 13 minutes ago, you ask the question; 11 minutes ago, you answer it; 9 minutes ago, you post a comment. You should buy yourself a beer or something. – Telemachus Jul 26 '09 at 23:21
  • Interesting, where does the 9 to the 9th to the 9th power come from? Is there a special significance or is it just an easy way to get a number big enough to blow up a variety of float specifications? – daotoad Jul 27 '09 at 03:17
  • 2
    @daotoad: yes, just an easy way. Some code unfortunately used things like 100**1000, which is infinite with IEEE double precision, but not infinite with long doubles. – ysth Jul 27 '09 at 03:31
  • 9
    Just don't use this under bigint or you'll wonder why your program is hung. – brian d foy Jul 27 '09 at 04:17
  • 6
    Right, under bigint, use Math::BigInt->bnan(), ->binf(), or ->binf('-'). – ysth Jul 27 '09 at 04:41
  • 3
    I was more concern with cases where someone turned on bigint and you didn't notice. :) – brian d foy Jul 27 '09 at 21:57
  • -1 because any copy/pasted solution is bad. Use the CPAN. See my answer. – dolmen Mar 20 '13 at 14:51
  • 1
    @dolmen Such a fundamental check should be possible without using the CPAN. It should be a core functionality. – Slaven Rezic Jun 10 '14 at 12:13
15
print "Is NaN\n" if $a eq 'nan';
print "Is Inf\n" if $a eq 'inf' or $a eq '-inf';

EDIT: Fixed for negative infinity.

Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
7

Personally, I would use Math::BigFloat (or BigInt) for anything that is going to touch infinity of NaN.

Why reinvent the wheel with a hack solution when there are already modules that do the job?

serenesat
  • 4,611
  • 10
  • 37
  • 53
cliveholloway
  • 368
  • 1
  • 2
  • 13
7

Use Data::Float from CPAN. It exports the following functions:

  • float_is_infinite()
  • float_is_nan()
  • ...

And contrary to the others half-working solutions posted here, it has a testsuite.

dolmen
  • 8,126
  • 5
  • 40
  • 42
0

When I searched I got this site (here) and http://www.learning-perl.com/2015/05/perls-special-not-a-numbers/

The linked article points out that "nan" == "nan" is never true, when the underlying c implementation supports NaN because Nan cannot match itself.

This is nicely illustrated with

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

I guess the risk of running you code in an environment where perl has degraded gracefully and your code has not might be low enough so that you don't worry too much.

And of course if you don't want perl to interpolate as a number, use 'eq' not '=='

jwal
  • 630
  • 6
  • 16
-1

Succinct answer that works follows.

1: How to create a "NAN" variable for output (to printf, for example):

 {no strict 'subs'; $NAN="NAN"+1;}

2: How to test for "NAN" (looks like ascii art):

 sub isnan {!($_[0]<=0||$_[0]>=0)}

3: How to create an "INF" and INFN variables:

{$INF="INF"+1; $INFN=-"INF"+1}

4: How to test for "INF" (of any sign):

sub isinf {($_[0]==+"INF")||($_[0]==-"INF")}
Erik Aronesty
  • 11,620
  • 5
  • 64
  • 44
  • 1
    (1) and (3) are no different than just `$NAN = "NAN"+1;`, `$INF = "INF"+1; $INFN = -"INF";` just more verbose – ysth Oct 19 '12 at 19:07
  • oh, I see (4) uses barewords too, only without disabling strict. And all of these that rely on strings like "NAN" and "INF" becoming the appropriate "number" in numeric context will fail on older perls or where the C runtime doesn't support it (e.g. strawberry perl or activeperl on windows) – ysth Oct 19 '12 at 19:42
  • 1
    A _comprehensive_ answer would include a testsuite. – dolmen Mar 20 '13 at 16:12
  • Changed it to be more clear... it's a succinct, correct answer. Also works on activeperl/windows, etc. – Erik Aronesty Mar 22 '13 at 12:52
  • You don't need the `no strict 'subs'` anymore if you don't use barewords. So your solution (still without testsuite) could be more succint. And `isinf` is still not efficient. – dolmen Apr 09 '13 at 16:40
  • 1
    i removed all the barewords – Erik Aronesty Jun 04 '13 at 15:19