How do I create or test for NaN or infinity in Perl?

心已入冬 提交于 2019-11-27 23:29:22
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.

ysth

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

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.

cliveholloway

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?

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 '=='

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")}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!