Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Recently, one of my co-workers noticed some problems hashing on references in our 64-bit HPUX-11 environment with perl 5.6.1. A bit of probing left me, the resident perl gnome, quite concerned. I see the problem also on an IA64/Linux build of perl 5.6.1, but not on a 64-bit Solaris build. This may be an instance of RTFM, but I have not seen it addressed in any FAQs, so I may be readingthe wrong FAQs. Or my eyes may have crossed and missed it.

The problem occurs in large integers, where the lower 8 bits get rounded if the upper 8 are in use. Here's a simple test script that illustrates the problem.

#!/path/to/perl my $X = \$X; printf STDOUT "Starting with VAR %lx and REF %lx \n", $X, \$X; if ($X == \$X) { printf STDOUT "uh oh, they are deemed equal\n"; } else { printf STDOUT "ah, good, they are observed to differ\n"; } # end

Here's a slightly more informative version of the same:

#!/path/to/perl my $X = \$X; my $Y = \$Y; if ( \$X == \$Y ) { printf STDOUT "disturbing declaration of equality! \n"; printf STDOUT "Refs: %s \t %s \n", \$X, \$Y; printf STDOUT "Vals: %lx \t %lx \n", $X, $Y; printf STDOUT "SOps: sum %lx \t dif %lx \n", $X + $Y, $X - $Y; printf STDOUT "incs: %lx \t +512=%lx \t +1024=%lx \n", $X, $X ++ 512, $X + 1024; } else { printf STDOUT "all is quiet and peaceful, \n"; printf STDOUT "%lx and %lx are recognized to differ by %lx \n" +, \$X, \$Y, \$X - \$Y; } # end

Results on the Solaris 5.8 machine:

all is quiet and peaceful, 100231cc0 and 100231ce0 are recognized to differ by ffffffffffffffe0

Results on the HPUX 11 machine:

disturbing declaration of equality! Refs: SCALAR(0x800000010002a9b0) SCALAR(0x800000010002a9d0) Vals: 800000010002a9f0 800000010002aa30 SOps: sum 200055000 dif 0 incs: 800000010002a9f0 +512=800000010002a800 +1024=800000010002b00 +0

What seems to be happening in the second case is values like
800000010002a9f0 and 800000010002aa30
are getting rounded to
800000010002a800 and 800000010002a800
and treated as equal, among other unsettling traits.

So, has anyone else encountered this? Is there a quick and happy fix? Is libc.sl hopelessly mangled? Can't we all just...get along?

Replies are listed 'Best First'.
Re: 64-to-56-bit truncation?
by Abigail-II (Bishop) on May 30, 2002 at 11:22 UTC
    Well, the first question one should ask is, "Has your Perl been build with 64 bit integer support?".

    If the answer is yes, you should have 64 bit precision on your integers. If the answer is no, you can expect about 56 bits of precision on your integers. You may wonder, "why not 32"? That is, if your integers would overflow, perl automatically start using a double instead. And that will give you about 56 bits of precision.

    You can find out whether your Perl support 64 bit integers by doing a 'perl -V'. The 64bitness of the hardware is neither sufficient, nor a requirement.

    Abigail

Re: 64-to-56-bit truncation?
by Zaxo (Archbishop) on May 30, 2002 at 03:46 UTC

    What do you expect to happen when rounding numbers? If two close ones round to the same number, they will compare equal. It appears from your data that Solaris does not place user code so high in virtual address space as HP-UX and Linux. The Solaris addresses are zero in the high byte, the others are not.

    I must admit that I don't understand why you are messing with circular self-reference in $X and $Y. That gives a surreal feel to your code. It set me back quite a while before I figured out that it was there for metaphysical reasons ;-)

    I remain unsettled but I suppose that's good for the soul.

    After Compline,
    Zaxo

Re: 64-to-56-bit truncation?
by Elian (Parson) on May 30, 2002 at 15:24 UTC
    If you've built with 64-bit integers but haven't built with long doubles (or your platform doesn't have long doubles) this will often happen. For almost everything perl does mathematically, it tends to promote integers to floating point numbers. If, unfortunately, the floating point number type your perl is using has fewer bits of precision than the integer you're using, you'll see lower bits go away.

    use integer; will solve this to some extent, as it stops promotion while its in scope, but the only solution is to build perl with 64 bit integers and larger than 64 bit doubles.