PHP bug (or my bad code)?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Bob Purdon

    #1

    PHP bug (or my bad code)?

    Consider this code:

    <?
    $mask_n = (pow(2,32) - (pow(2,32-24)-1));
    printf("%x\n", $mask_n);
    ?>

    On PHP 4.1.2 it prints:

    ffffff00

    On PHP 4.3.10 is prints:

    ffffff01


    Both versions of PHP are the standard Debian packaged versions (4.1.2
    from Woody, 4.3.10 from Sarge)

    tecra# php -v
    PHP 4.3.10-9 (cli) (built: Mar 6 2005 17:45:14)
    Copyright (c) 1997-2004 The PHP Group
    Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies

    admin# php -v
    4.1.2

    Results are (predictably) the same under both the CLI version and under
    the Apache module.


    Is this a bug in PHP, or is there something broken in my code?
  • Hans van Kranenburg

    #2
    Re: PHP bug (or my bad code)?

    Bob Purdon wrote:[color=blue]
    > Consider this code:
    >
    > <?
    > $mask_n = (pow(2,32) - (pow(2,32-24)-1));
    > printf("%x\n", $mask_n);
    > ?>
    >
    > On PHP 4.1.2 it prints:
    > ffffff00
    >
    > On PHP 4.3.10 is prints:
    > ffffff01
    >
    > Both versions of PHP are the standard Debian packaged versions (4.1.2
    > from Woody, 4.3.10 from Sarge)[/color]

    Some other code:

    <pre>
    <?
    $mask_n = (pow(2,32) - (pow(2,32-24)-1));
    var_dump($mask_ n);
    printf("%x\n", $mask_n);

    $mask_n2 = 4294967041;
    var_dump($mask_ n2);
    printf("%x\n", $mask_n2);

    echo "so... what's the difference ... " . ($mask_n - $mask_n2);

    ?>
    </pre>

    On woody 4.1.2:

    float(429496704 1)
    ffffff00
    float(429496704 1)
    ffffff01
    so... what's the difference ... -3.3378601074219 E-06

    On sarge 4.3.10:

    float(429496704 1)
    ffffff01
    float(429496704 1)
    ffffff01
    so... what's the difference ... 0

    What's going on?!

    Hans van Kranenburg

    --
    "He who asks a question is a fool for five minutes;
    he who does not ask a question remains a fool forever"

    Comment

    • Dana Cartwright

      #3
      Re: PHP bug (or my bad code)?

      "Hans van Kranenburg" <f00b4r@xs4all. nl> wrote in message
      news:4246a1d3$0 $143$e4fe514c@n ews.xs4all.nl.. .[color=blue]
      > Bob Purdon wrote:[color=green]
      >> Consider this code:
      >>
      >> <?
      >> $mask_n = (pow(2,32) - (pow(2,32-24)-1));
      >> printf("%x\n", $mask_n);
      >> ?>
      >>
      >> On PHP 4.1.2 it prints:
      >> ffffff00
      >>
      >> On PHP 4.3.10 is prints:
      >> ffffff01
      >>
      >> Both versions of PHP are the standard Debian packaged versions (4.1.2
      >> from Woody, 4.3.10 from Sarge)[/color]
      >
      > Some other code:
      >
      > <pre>
      > <?
      > $mask_n = (pow(2,32) - (pow(2,32-24)-1));
      > var_dump($mask_ n);
      > printf("%x\n", $mask_n);
      >
      > $mask_n2 = 4294967041;
      > var_dump($mask_ n2);
      > printf("%x\n", $mask_n2);
      >
      > echo "so... what's the difference ... " . ($mask_n - $mask_n2);
      >
      > ?>
      > </pre>
      >
      > On woody 4.1.2:
      >
      > float(429496704 1)
      > ffffff00
      > float(429496704 1)
      > ffffff01
      > so... what's the difference ... -3.3378601074219 E-06
      >
      > On sarge 4.3.10:
      >
      > float(429496704 1)
      > ffffff01
      > float(429496704 1)
      > ffffff01
      > so... what's the difference ... 0
      >
      > What's going on?!
      >
      > Hans van Kranenburg[/color]

      I imagine the relevant statement from the manual is:

      "If possible, this function will return an integer"

      Your expression would be OK if indeed it were calculated in integers. But
      since 2 raised to the power 32 cannot be represented in 32 bits (it misses
      by 1), you're thrown into the realm of floating point, and in that world,
      you can't assume all bits will be as you think they will be, only that the
      numeric values will be sufficiently close to the exact result. And in
      floating point, the *order* in which you do arithmetic matters, quite a lot.

      As to your code, the most straight-forward way to create bit masks (which is
      what I'm thinking you are trying to do) is like this:

      $mask = 0xFFFFFFFF << (32 - 8)

      which will reliably give you:

      0xFFFFFF00

      Further, if this were my software, I'd simply write:

      $mask = 0xFFFFFF00;

      because that says, as clearly as can be said, "I want a 32-bit mask with the
      high 24 bits set and the low 8 bits clear".

      If I had a variable that specified the number of low zero bits I needed, I'd
      write:

      $mask = 0xFFFFFFFF << (32 - $low_zero_bits) ;

      because that says, as clearly as can be said, "I want a mask that's 32 bits
      wide and is everywhere 1's except for the $low_zero_bits which are zero".

      Finally, if you want this to work cross-platform, you should define a
      constant that's the number of bits in an integer, and work from that,
      remembering to never shift by more than that many bits, since Intel
      disagrees with most of the rest of the world as to the meaning of
      over-shifting (shifting more than 32 on a 32-bit machine, for example).


      Comment

      • Bob Purdon

        #4
        Re: PHP bug (or my bad code)?

        > As to your code, the most straight-forward way to create bit masks (which is[color=blue]
        > what I'm thinking you are trying to do) is like this:
        >
        > $mask = 0xFFFFFFFF << (32 - 8)[/color]

        Yeah, indeed a much better way.
        [color=blue]
        > Further, if this were my software, I'd simply write:
        >
        > $mask = 0xFFFFFF00;[/color]

        Agree, except the mask varies, so:
        [color=blue]
        > $mask = 0xFFFFFFFF << (32 - $low_zero_bits) ;[/color]

        Is the way it needs to go...

        Seems I've been cracking this nut the hard way and overlooking the
        obvious :-)

        Thanks all.

        Comment

        Working...