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

How to create nan/inf

by syphilis (Chancellor)
on Aug 09, 2008 at 03:06 UTC ( #703222=perlquestion: print w/replies, xml ) Need Help??
syphilis has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
How do I portably create nans and infs in perl ?
Any solution that uses a core perl module would be fine. Specifically, I'm looking to create variables that Devel::Peek::Dump() as something like:
Positive inf: SV = NV(0x465ffc) at 0x42fca4 REFCNT = 1 FLAGS = (NOK,pNOK) NV = 1.#INF Negative inf: SV = NV(0x465ff4) at 0x42fcc4 REFCNT = 1 FLAGS = (NOK,pNOK) NV = -1.#INF
At least that's how they should look on Windows. Other operating systems will be essentially the same, though the precise contents of the NV slot could be different (eg 'inf').
I'm not exactly sure what the nan looks like - I guess it, too, will be an NV with 1.#NAN filling the NV slot (on Windows).

Is it possible to create an IV with 1.#INF in the IV slot, or are infinities necessarily NV's ?

Cheers,
Rob

Replies are listed 'Best First'.
Re: How to create nan/inf
by ikegami (Pope) on Aug 09, 2008 at 03:56 UTC

    You could also create the bit pattern yourself and unpack it. It's system dependant, but it will allow you to generate every possible special value.

    For example, Windows uses little-endian IEEE

    sub double_from_hex { unpack 'd', scalar reverse pack 'H*', $_[0] } use constant POS_INF => double_from_hex '7FF0000000000000'; use constant NEG_INF => double_from_hex 'FFF0000000000000'; use constant qNaN => double_from_hex '7FF8000000000000'; use constant NaN => qNaN; print(POS_INF, "\n"); # 1.#INF print(NEG_INF, "\n"); # -1.#INF print(qNaN, "\n"); # 1.#QNAN

    x86 doesn't seem to have signaled NaNs or they're not recognized when stringified. On the other hand, "FFF8000000000000" is recognized as being "-1.#IND".

      That gives me (more than) enough to play with :-)
      One of the PowInt.t tests on Math::GSL (version 0.07) fails on Windows but passes on Linux. It's to do with differing treatment of nans and infs. It helps if I can reliably and easily create nans and infs on both platforms - which I now can.

      Thanks ikegami.

      Cheers,
      Rob
Re: How to create nan/inf
by ikegami (Pope) on Aug 09, 2008 at 03:21 UTC

    There are tokens that will be understood as infinity, but it's dependant on the underlying C library. It's easier just to calculate it.

    use constant POS_INF => +(99**99**99); use constant NEG_INF => -(99**99**99);

    (Is that big enough for a long double system?)

    Active Perl 5.6.0, 5.6.1, 5.8.0, 5.8.8, 5.10.0 on Windows:

    >perl -MDevel::Peek -e"Dump +(99**99**99)" SV = NV(0x1832414) at 0x225334 REFCNT = 1 FLAGS = (PADBUSY,PADTMP,NOK,READONLY,pNOK) NV = 1.#INF >perl -MDevel::Peek -e"Dump -(99**99**99)" SV = NV(0x1832424) at 0x22531c REFCNT = 1 FLAGS = (PADBUSY,PADTMP,NOK,READONLY,pNOK) NV = -1.#INF

    Some Perl 5.8.4 on linux:

    $ perl -MDevel::Peek -e'Dump +(99**99**99)' SV = NV(0x8165bd0) at 0x8160954 REFCNT = 1 FLAGS = (PADBUSY,PADTMP,NOK,READONLY,pNOK) NV = inf $ perl -MDevel::Peek -e'Dump -(99**99**99)' SV = NV(0x8165be0) at 0x814cc9c REFCNT = 1 FLAGS = (PADBUSY,PADTMP,NOK,READONLY,pNOK) NV = -inf
Re: How to create nan/inf
by ikegami (Pope) on Aug 09, 2008 at 03:27 UTC

    I missed your second question.

    Is it possible to create an IV with 1.#INF in the IV slot

    Infinity and NaN are necessarily floats. Integers use all their bits to hold the value.

Re: How to create nan/inf
by eosbuddy (Scribe) on Aug 09, 2008 at 07:20 UTC
    It is beyond my expertise to answer your original (and interesting) question, nonetheless, I thought you and fellow monks might be interested in my bit of (research). I did an investigation on my system (using the ~0 >> 1 construct for integer type maximum number and working my way up using this number). Due to the dynamical typing of perl, integer numbers can go way beyond this maximum (usually that one finds in C).
    #!/usr/bin/perl use strict; use warnings; my $n; $n = ~0 >> 1; print "$n\n"; my $x = 999999999999999; print "$x\n"; $x = 1000000000000000; print "$x\n"; my $z = 1.79769313486231e+308; print "$z\n"; $z = 1.79769313486232e+308; print "$z\n";
    The output:
    2147483647 999999999999999 1e+15 1.79769313486231e+308 inf
    There is also another older node regarding a similar issue here: http://www.perlmonks.org/?node=657332 with an insightful summary by ysth at the end. Hope this helps.
Re: How to create nan/inf
by swampyankee (Parson) on Aug 09, 2008 at 05:28 UTC

    iirc, FFFFFFFFFFFFFFFF is NaN on Windows boxes (at least with Intel Visual Fortran and C), but I can't swear that's guaranteed to be true on all x86 machines, let alone all machines using IEEE arithmetic. I know that some platforms, e.g., IBM mainframes, don't have floating point models capable of representing NaN or Inf, so a completely portable solution is impossible.


    Information about American English usage here and here. Floating point issues? Please read this before posting. — emc

      so a completely portable solution is impossible

      That's not really an issue for me. I was just after some way of getting test 6 of PowInt.t to pass on Windows, leaving all other systems unaffected. I think I've now achieved that.

      One of the things that was throwing me was that, on Linux, the strings 'nan' and 'inf' are converted to a nan/inf when used in numeric context. That is, on Linux:
      perl -MDevel::Peek -e 'Dump "inf" + 1';
      outputs:
      SV = NV(0x...) at 0x.... REFCNT = 1 FLAGS = (NOK,READONLY,pNOK) NV = inf
      But there's no comparable behaviour (that I can find) on Windows. The strings '1.#INF' and '1.#QNAN' are not interpreted as inf/nan when used in numeric context. Instead they're just numified according to the usual rules that apply to the numification of strings - ie they take on a numeric value of 1:
      C:\>perl -MDevel::Peek -e "Dump '1.#INF' + 1" SV = IV(0x218fe28) at 0x218fe2c REFCNT = 1 FLAGS = (PADTMP,IOK,READONLY,pIOK) IV = 2
      I wasn't expecting such different behaviour - and that added significantly to my confusion.

      Cheers,
      Rob

      Double FFFFFFFFFFFFFFFF is *a* IEEE 754 NaN. Anything of the form [7F]FFFxxxxxxxxxxxx where "x" is nonzero is a NaN.

      There are at least two kinds of NaN: signaled and quiet. IEEE 754 doesn't define the how to encode them, but recommends using the most significant bit of "x" (0 for signaled).

Re: How to create nan/inf
by repellent (Priest) on Aug 17, 2008 at 19:42 UTC
    my $inf = exp(~0 >> 1); my $nan = $inf / $inf; my $neg_inf = -$inf;
    Note that any sufficiently large number will suffice instead of (~0 >> 1).
Re: How to create nan/inf
by Anonymous Monk on Sep 01, 2008 at 14:05 UTC
    bigint/bigrat export NaN and inf
    D:\>perl -MDevel::Peek -Mbigint -e"Dump(NaN())" SV = PV(0x225ec4) at 0x18a5984 REFCNT = 1 FLAGS = (TEMP,ROK,OVERLOAD) RV = 0x224f58 SV = PVHV(0x2299c4) at 0x224f58 REFCNT = 1 FLAGS = (OBJECT,SHAREKEYS) IV = 2 NV = 0 STASH = 0x185c2e4 "Math::BigInt" ARRAY = 0x1824734 (0:6, 1:2) hash quality = 125.0% KEYS = 2 FILL = 2 MAX = 7 RITER = -1 EITER = 0x0 Elt "value" HASH = 0x1e720953 SV = RV(0x183b380) at 0x19a5b88 REFCNT = 1 FLAGS = (ROK) RV = 0x197f954 SV = PVAV(0x199f354) at 0x197f954 REFCNT = 1 FLAGS = () IV = 0 NV = 0 ARRAY = 0x1830244 FILL = 0 MAX = 0 ARYLEN = 0x0 FLAGS = (REAL) Elt No. 0 SV = IV(0x182d3e8) at 0x19a5b64 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 0 Elt "sign" HASH = 0xe7455c8f SV = PV(0x225ea0) at 0x19a5b58 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x182281c "NaN"\0 CUR = 3 LEN = 4 PV = 0x224f58 "" CUR = 0 LEN = 0 D:\>perl -MDevel::Peek -Mbigrat -e"Dump(NaN())" SV = PV(0x225ec4) at 0x188c97c REFCNT = 1 FLAGS = (TEMP,ROK,OVERLOAD) RV = 0x224f58 SV = PVHV(0x229ae4) at 0x224f58 REFCNT = 1 FLAGS = (OBJECT,SHAREKEYS) IV = 2 NV = 0 STASH = 0x188be6c "Math::BigInt" ARRAY = 0x1824734 (0:6, 1:2) hash quality = 125.0% KEYS = 2 FILL = 2 MAX = 7 RITER = -1 EITER = 0x0 Elt "value" HASH = 0x1e720953 SV = RV(0x183b34c) at 0x19a6fb4 REFCNT = 1 FLAGS = (ROK) RV = 0x197d210 SV = PVAV(0x19a56b4) at 0x197d210 REFCNT = 1 FLAGS = () IV = 0 NV = 0 ARRAY = 0x1830244 FILL = 0 MAX = 0 ARYLEN = 0x0 FLAGS = (REAL) Elt No. 0 SV = IV(0x19fab0c) at 0x19a6f90 REFCNT = 1 FLAGS = (IOK,pIOK) IV = 0 Elt "sign" HASH = 0xe7455c8f SV = PV(0x225ea0) at 0x19a6f84 REFCNT = 1 FLAGS = (POK,pPOK) PV = 0x182281c "NaN"\0 CUR = 3 LEN = 4 PV = 0x224f58 "" CUR = 0 LEN = 0 D:\>

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://703222]
Approved by ikegami
Front-paged by Arunbear
help
Chatterbox?
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2017-12-11 20:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    What programming language do you hate the most?




















    Results (311 votes). Check out past polls.

    Notices?