Sixtease has asked for the wisdom of the Perl Monks concerning the following question:
Hello friends,
this is more an expression of confusion and surprise than a question.
@a = (5 .. 10);
print
$a['Infinity'], "\n",
$a[Infinity], "\n";
#outputs 10 and 5
Is this documented anywhere?
use strict; use warnings; print "Just Another Perl Hacker\n";
Re: $array[ 'Infinity' ]
by ysth (Canon) on Dec 17, 2007 at 03:32 UTC

There are some perl bugs here. Some are very highly likely to be never fixed in perl5, some only highly likely to never be fixed.
First of all, just to be clear, perl 5.8.8 and later (as well as perl 5.6.2 and before, for some value of before)
may treat a string that looks like a stringized infinite or NaN number as that number in numeric context. But only if the underlying libc provides support for that. (The 5.8.0 to 5.8.7 gap is due to perl moving away from using libc to convert strings to floating point, after the boneheaded decision by the ISO C folk to radically change the rules for how "0x..." and the like were converted. The
inf/nan stuff was left out of perl's homegrown atof for that period.)
The other special thing perl does is not give the "Argument "..." isn't numeric"
warning when encountering these string values in numeric context. This is the
case all through the 5.8.x series (and even in 5.8.8 on platforms where the libc doesn't translate "Inf" to Inf), even though the numeric value will be 0, just
as if the string had been "xyzzy".
Now one interesting and potentially dangerous thing when dealing with infinites
in perl is that perl doesn't really have a separate "integer context". When
you use something as an array index, it is in a general numeric context, and
will get converted to a number. If it's an "Inf" string, that will be a NV
containing Inf (where supported). But an array index is an integer; the aelem
op that looks up an array element given an array and index blindly converts
the NV to an IV (usually with range 2**31 .. 2**311 or 2**63 .. 2**631),
and if the value was outside that range, uses the closest endpoint. So on
a perl using 64 bit ints, the index will be 2**63 for Inf or 2**631 for
Inf. Now the fun part comes... The underlying array access routines expect
the element to be a 32 bit int, so 2**63 is truncated (taking the least
significant 32 bits) to 0 and 2**631 is truncated to 1.
So with 64 bit
ints and Inf string conversion support, $x[Inf] is $x[1] and $x[Inf] is $x[0]. But with 32 bit ints, $x[Inf] is $x[2**311] and $x[Inf] is $x[2**31], both of which are undef.
The only problem is that even with a 32 bit int perl 5.8.8, I'm seeing $x[Inf]
be 10 (which I've just logically deduced can't be the case) and haven't yet figured out why.
Update: oh, right! I remember now. When an IV or UV is requested from an NV,
the result is restricted to the range IVMIN to UVMAX, regardless of whether
an unsigned or signed value was requested. So "Inf" is essentially cast to
an NV, becoming Inf, then to a UV, becoming 2**321, then to an IV, becoming
1 (same bit pattern as the unsigned 2**321) when "Inf" is used as an array
element and hence coerced to an IV. And $x[Inf] becomes $x[1]
whether on a 64 bit in or 32 bit int perl.
 [reply] [d/l] [select] 
Re: $array[ 'Infinity' ]
by Sixtease (Friar) on Dec 16, 2007 at 23:28 UTC

No, this is not caused by numerical equivalence to zero. Nor is it caused by Infinity/inf differences:
@a = (5 .. 10);
print
$a['inf'], "\n",
$a[inf], "\n",
inf==0 ? "inf is zero\n" : "inf isn't zero\n",
'inf'==0 ? "inf is zero\n" : "inf isn't zero\n";
# still outputs 10 and 5 and states that the infinities aren't zeroes
perl version says "This is perl, v5.8.8 built for x86_64linuxthreadmulti"
Update: The weird thing is that indexing by inf gives the first element and indexing by inf gives the last one. That's not what I'd expect.
use strict; use warnings; print "Just Another Perl Hacker\n";
 [reply] [d/l] 

Using perl MO=Deparse may shed some light on some of this weirdness, although I have no idea why on Earth anyone would implement 'inf' the way it works on my box.
perl MO=Deparse e 'print $n[inf]'
prints
print $n[9**9**9];
as does
perl MO=Deparse e 'print $n["inf"]'
On the other hand,
perl MO=Deparse e 'print $n[inf]'
prints
print $n['inf'];
perl MO=Deparse e 'print "", inf==0 ? "a" : "b", 'inf'==0 ? "c" : "d
+", inf==0 ? "e" : "f"'
prints
print '', 'inf' == 0 ? 'a' : 'b', 'inf' == 0 ? 'c' : 'd', 'inf' == 0
+? 'e' : 'f';
As nearly as I can tell at the moment, inf is only equivalent 9**9**9 if it is used by itself as a subscript; it is taken as a bareword in a simple assignment, so
perl MO=Deparse e '$n[inf], $n[1+inf], $n[inf] = inf'
prints
$n[9**9**9], $n[1 + 'inf'], $n['inf'] = 'inf';
My perl v shows,
This is perl, v5.8.8 built for i486linuxgnuthreadmulti
Does anyone know why?
 quester
 [reply] [d/l] [select] 

 [reply] [d/l] [select] 

Oddly (or maybe not so oddly) I get different output on a w2k box from the first cited by quester:
perl MO=Deparse e "print $n[inf]"
print $n[0];
e syntax OK
from...
perl v
This is perl, v5.8.8 built for MSWin32x86multithread
(with 33 registered patches, see perl V for more detail)
...
Binary build 819 [267479] provided by ActiveState http://www.ActiveSta
+te.com
Built Aug 29 2006 12:42:41
 [reply] [d/l] [select] 


As to the "why", X = 9**9**9 == 9**(9**9) = 9**387420489. Nine to that power is a number aproximately 1.2 billion bits long. (log(9)/log(2) * (9**9)). So, for all intents and purposes, it's infinity. Since it's odd, X will be negative infinity So, it avoids the (possible?) nonportability of a raw 'inf' or 'inf'.
Update: Duh, Ben. Re: strikeout. Plus it's specifically negated. I was thinking (9)**9**9)
 [reply] 

Interesting. I can confirm your results for "v5.8.8 built for
x86_64linuxthreadmulti". For "v5.8.8 built for
i486linuxgnuthreadmulti", however, I'm just getting 10 for
'Infinity' (or inf) and nothing (undef) for Infinity (or inf).
 [reply] [d/l] [select] 
Re: $array[ 'Infinity' ]
by shmem (Chancellor) on Dec 17, 2007 at 01:56 UTC

Is this documented anywhere?
Yes, in sv.c in the perl source ("use the source, luke" ;)
Line 1680 ff:
/*
=for apidoc looks_like_number
Test if the content of an SV looks like a number (or is a number).
C<Inf> and C<Infinity> are treated as numbers (so will not issue a
nonnumeric warning), even if your atof() doesn't grok them.
=cut
*/
and so  suprise!  perlapi tells the same.
Read through sv.c to see what happens. The perl5 spec is coherent with its implementation ;)
shmem
_($_=" "x(1<<5)."?\n".q·/)Oo. G°\ /
/\_¯/(q /
 \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"y/#z/;$e.e && print}
 [reply] [d/l] [select] 
Re: $array[ 'Infinity' ]
by ikegami (Pope) on Dec 16, 2007 at 23:19 UTC

>perl e "use Devel::Peek; $x="bareword"; Dump($x); $x=bareword; Dum
+p($x)"
SV = PV(0x226150) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1835404 "bareword"\0
CUR = 9
LEN = 12
SV = PV(0x226150) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1835404 "bareword"\0
CUR = 9
LEN = 12
There's nothing special about Infinity.
>perl e "use Devel::Peek; $x="Infinity"; Dump($x); $x=Infinity; Dum
+p($x)"
SV = PV(0x226150) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1835404 "Infinity"\0
CUR = 9
LEN = 12
SV = PV(0x226150) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1835404 "Infinity"\0
CUR = 9
LEN = 12
A string that doesn't look like a number is the same as 0 in a numerical context (although it will give a warning if warnings enabled).
The index expression of an array is evaluated in a numerical context.
So they both print 5.
>perl e"@a = (5 .. 10); print qq{$a['Infinity']\n$a[Infinity]\n};"
5
5
Update: There appears to be a bug. 'Infinity' and Infinity don't trigger the warning.
 [reply] [d/l] [select] 
Re: $array[ 'Infinity' ]
by moritz (Cardinal) on Dec 16, 2007 at 23:17 UTC

It prints only 5\n\n for me (with perl 5.8.8).
The $a['Infinity'] part is not surprising, because the string is coerced into an integer, which is 0.
I was quite surprised though that Infinity is evaluated as inf (and $a[inf] is undef; no surprises here). A quick grep through the pod files in my perl distribution show that Infinity was introduced in perl561delta as a synonym for inf.
It's a bit weird that it dies under strict, IMHO.  [reply] [d/l] [select] 

If you really want a strict version:
use strict;
my @a = (5 .. 10);
print
$a['Infinity'], "\n",
$a['Infinity'], "\n";
print
$a['Infinity'], "\n",
$a['Infinity'], "\n";
print 0+"Infinity" . "\n";
print 0+"Infinity" . "\n";
You still get: 10
5
10
5
inf
inf
The version:
perl v
This is perl, v5.8.8 built for cygwinthreadmulti64int...
 [reply] [d/l] 
Re: $array[ 'Infinity' ]
by Sixtease (Friar) on Dec 17, 2007 at 00:47 UTC

Do you think that this should be filed as a bug? I mean the different behavior of v5.8.8 built for different platforms, not the confusion about Infinity and inf. This is in my opinion not a matter of atof because the problem arises after you manage to get the actual infinity. Array indexed by minus infinity shouldn't yield the first element and if so, then on all platforms, I would think. If you agree that it should be filed, then I humbly ask your guidance on how and where to do so.
use strict; use warnings; print "Just Another Perl Hacker\n";
 [reply] 
Re: $array[ 'Infinity' ]
by explorer (Chaplain) on Dec 16, 2007 at 23:12 UTC

infinity is recognized as a number from perl 5.6.1.
Updated:Sorry for the changes, blokhead.
 [reply] 

$ perl le 'print 0+(Infinity)'
inf
$ perl le 'print 0+("Infinity")'
inf
$ perl v
This is perl, v5.8.8 built for i486linuxgnuthreadmulti
I'm not sure I ever considered using infinity as an array offset. Nor did I guess that 0+"Infinity" would actually be infinity. It is cute that both do reasonable things.
 [reply] [d/l] [select] 

Is Perl suppose to support Infinity as a number? If so, it has two bugs: it doesn't work, and it's not in the docs. It's not in the 5.10.0 docs either.
It's not recognized by the parser:
>perl e "use Devel::Peek; $x="Infinity"; Dump($x); $x=Infinity; Dump(
+$x)"
SV = PV(0x22612c) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x182cb54 "Infinity"\0
CUR = 8
LEN = 12
SV = PV(0x22612c) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x182cb54 "Infinity"\0
CUR = 8
LEN = 12
>perl e "use Devel::Peek; $x="Infinity"; Dump($x); $x=Infinity; Dum
+p($x)"
SV = PV(0x226150) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1835404 "Infinity"\0
CUR = 9
LEN = 12
SV = PV(0x226150) at 0x226000
REFCNT = 1
FLAGS = (POK,pPOK)
PV = 0x1835404 "Infinity"\0
CUR = 9
LEN = 12
I also get different output from the commands you issued.
>perl le "print 0+(Infinity)"
0
>perl le "print 0+('Infinity')"
0
>perl v
This is perl, v5.8.8 built for MSWin32x86multithread
(with 25 registered patches, see perl V for more detail)
Copyright 19872006, Larry Wall
Binary build 817 [257965] provided by ActiveState http://www.ActiveSta
+te.com
Built Mar 20 2006 17:54:25
...
Has this been discussed on P5P?
 [reply] [d/l] [select] 



