& behaves differently - Page 2

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View

Re: & behaves differently

fritz-bayer@web.de said the following on 05/03/2006 12:33:
Quoted text here. Click to load it

Why would you be concerned about behaviour in out-of-range input  
conditions, as they're technically meaningless, and wouldn't be  
relied-upon except in the most bizarre situations?  What's more, if you  
did make your Perl function consistent with PHP behaviour, it would then  
be inconsistent with the rest of Perl's behaviour.

Anyway, I don't think the PHP behaviour Tim describes is consistent.  
For instance, try this in PHP:

    $a = 5543039444;
    $b = $a * 10000000000;

    echo $a . " => " . intval($a) . "\n";
    echo $b . " => " . intval($b) . "\n";

PHP is clearly not just converting the floats to fully-represented  
integers and retaining only the 32 LSBs.


Re: & behaves differently

Oli Filth wrote:
Quoted text here. Click to load it

Well, I guess the program I'm porting relies on this strange behaviour.
That's for sure. I did not write it. I'm just trying to port it. Could
it be that php ocde above will convert those numbers to unsigned ints
so that no overflow takes place?!

Re: & behaves differently

Quoted text here. Click to load it

Actually, you're seeing an artifact of the design of the x86 FPU here. With
any fewer zeros, your code will print a number.

I looked up the PHP code; it is doing a simple C cast to unsigned long, and
writing the equivalent C program gets the same result:

int main(void)
    double a = 5543039444;
    double b = a * 10000000000;
    printf( "%f %d\n", b, (unsigned long)b);
    return 0;

55430394439999996000.000000 0


The reason is that the mantissa in your example requires more than 64 bits,
which means it can no longer be represented exactly in an 80-bit FPU
register.  In that case, the "fist" instruction raises an exception and
returns the "most negative integer".  For an unsigned long, that is 0.
- Tim Roberts, timr@probo.com
  Providenza & Boekelheide, Inc.

Re: & behaves differently

Quoted text here. Click to load it

Now that you've actually posted your code, it's possible to (finally)  
understand something about the problem you're having.

First, I have to point out that whoever wrote this code did so under the  
assumption that $a would be a 32-bit integer and $b would be in the range 0  
to 31.  The constant 80000000 is equivalent to the comment "This function  
assumes $a is a 32-bit integer" (but see my note below).  And if that's the  
case, then $b is in the range 0 to 31 (otherwise the behaviour is  

Moreover, the author assumes that on the machine executing this code ">>"  
might do sign bit propogation, but might not, and it might do sign bit  
extension, or might not.  Again, this is clear from the structure of the  
code ("$a |= 0x40000000" deals with sign bit propogation, "$a &= (~$z)"  
deals with sign bit extension).

But there are still puzzles in this code.  The expression "hexdec(80000000)"  
yields a floating point value in PHP (in modern PHP's--in older ones it's  
undefined).  As others have already pointed out, floating point has no  
business being used in a function like this!  This function was not written  
to use floating point.  The person who wrote it clearly assumed it was going  
to handle 32-bit integers.

The entire function would make PERFECT sense if the opening line were "$z =  
0x80000000"...is there any possibility that somebody changed it?

I cannot see where "overflow" comes into this function at all.  Nothing in  
it overflows.

Of course, PHP being PHP, you can pass whatever you want for $a and $b and  
the function will doubtless deliver some result, probably without issuing  
any error message.  This is one of the nice things, and one of the not nice  
things, about PHP.  But if your goal is to reproduce that out-of-bounds  
behaviour on some other machine, good luck.  Actually, bad luck, because it  
won't happen.

I don't know how PHP actually executes right shift (>>).  But if it uses the  
underlying hardware, which it might well do, be aware that when you  
"overshift" (shift by the word width or more, so 32 or more, in this case),  
most Intel chips do the shift modulo the word width, and most Motorola chips  
use the value you supplied.  So the expression $a >> 32 will typically give  
you $a on an Intel chip, and 0 on a Motorola chip.  Which is why you see  
people warning you (and pay attention to their warning) that shifting by the  
word width or more is UNDEFINED.  Attempting to port such code is going to  
bring you nothing but grief.

You need to take a deep breath, step back from this function, and examine  
the code that calls it.  Someplace the original author's assumptions are  
being violated.


Re: & behaves differently

Thanks Dana and thanks to rest of the people who responded.

I have debug both scripts an figured out that the program breaks, when
it's processing the values

a=5496229061, b=13

The php script returns 146638 and the perl script 524287. So also the
operation $a = ($a >> $b) yields different values in php and perl.

Or could it be, that php is smart enough to create a unsigned integer,
wheras perl does not and therefore an overflow occurs? Anyway here you
have the possibiliy of an overflow depending on how $a is handled.

Do you think >> differs in perl and php or is it an overflow problem?

Re: & behaves differently

My e-mail address doesn't have a 2 in it.
Quoted text here. Click to load it

Please remember that this function is ONLY VALID when fed a $a that fits  
within a 32-bit signed integer.  As has been pointed out, 5,496,229,061  
doesn't fit within a 32-bit signed int (limit is 2,147,483,647).  Nor does  
it fit within an unsigned 32-bit int (limit is 4,294,967,295).  It isn't a  
question of whether PHP is using signed or unsigned arithmetic.  It is  
surely being stored as a float of some sort (which will vary from one  
computer to another).

Therefore, you simply cannot pass it to this function and expect predictable  
results.  Your results will depend upon the nitty-gritty details of the  
language, the computer you're on, the version of the software you're  
using...in short, you cannot pass this function 5496229061 and ask  
meaningful questions about the results.  It's not an overflow problem.  It  
does not depend on how >> works.  It has to do with how numbers are  
represented in memory.

If you have software that is feeding 5496229061 to this function, then you  
have a HUGE problem.  Evidently the software depends upon the specific value  
that this function HAPPENS TO RETURN when run on a CERTAIN HARDWARE PLATFORM  
on a PARTICULAR VERSION OF PHP.  Aside from the issue of porting it to perl,  
I am certain that this software will break (in unpredictable ways) simply by  
the passage of time, because if you try to run it on a different computer,  
it will likely break.  If you upgrade PHP, it will likely break.  And so on  
and so forth.  This is a time bomb that will sooner or later detonate.

You cannot easily fix this problem by messing around with this function.  
Your software is breaking the rules, and you are suffering the consequences.

You could study the floating point representation of 5,496,229,061 and see  
if the results you are getting can be predicted from that (this should be  
possible, since computers are not whimsical).  You would need to look at the  
PHP code that implements >> and see what it does with a floating point (this  
is where open source is *really* handy).  And you could try to force perl to  
do its arithmetic the same way.  And you could meticulously document the  
resulting code.  It should be possible to do.  It's what I would do if this  
were my problem to solve and I wasn't able to fix the real problem, which is  
that some idiot wrote code that is passing bogus values to this function.


Re: & behaves differently

Hi Dana,

the complete code of the php, which I`m supposed to port to perl can be
found at http://www.googlecommunity.com/scripts/google-pagerank.php

It actually computes the pagerank of a website. Most of the script is
calculating a checksum, which is needed to calculate the pagerank.

It's really strange the code, but my job is just to port it, but it's
not so easy as you can see?

Re: & behaves differently

fritz-bayer@web.de said the following on 05/03/2006 21:06:
Quoted text here. Click to load it

Basically, PHP doesn't do unsigned arithmetic.  This algorithm probably  
originated in C or something similar, where you can specify unsigned  
data types and everything will work fine.  The implementation this guy  
created relies on the current conversions occurring in PHP; on a 64-bit  
platform this would probably fail.


It's talking about VBScript, but the problem he describes is identical.


Re: & behaves differently

I found a perl version: http://www.everyscript.de/PRank.htm

Re: & behaves differently

Quoted text here. Click to load it

This should handle an arbitrary number of bits for $a, allowing $b to be  
greater than the number of machine word bits.

// Assuming 32-bit (1 sign) integer length.
function fillWithZeroes($a, $b)
    // In PHP you could use is_float($a), but I don't know
    // the equivalent Perl function.
    if ($a > 0x7FFFFFFF)
        // It is some FP number, must emulate shift with division.
        $d = exp(2, $b);
        $a = round($a / $d);
        // Return int if possible.
        if ($a <= 0x7FFFFFFF)
            $a = (int)$a;
        $a >>= $b;
    return $a;

This yelds correct results as long as FP numbers have enugh precision. This  
is obviously NOT a safe assumption; yet if FP numbers have 53 + 1  
significand bits (64-bits IEEE FP), this fillWithZeroes should be able to  
handle numbers from 0 to 2^54 - 1.


"Experience is a hard teacher: she gives the test first, the lesson
  afterwards." - Vernon Sanders law  

Re: & behaves differently

ColdShine wrote:
Quoted text here. Click to load it

Hi Coldhine, thanks for the workaround. I had to slightly change the
code, since perl does not have a rounding function and have now:

 sub zeroFill2()
    my ($a, $b) = @_;
    # In PHP you could use is_float($a), but I don't know
    # the equivalent Perl function.
    if ($a > 0x7FFFFFFF)
        # It is some FP number, must emulate shift with division.
        $d = 2 ** $b;
        $a = round($a / $d);

        # Return int if possible.
        if ($a <= 0x7FFFFFFF)
        return int($a);
        $a = ($a >> $b);
    return $a;


sub round()
   my ($number) = @_;
   return int($number + .5 * ($number <=> 0));

Problem still remains so. This function returns 679118 instead of the
needed 154830. What should I change, so that it will return the right

Site Timeline