FAQ
Hi list,

How do we feel about a zero-fill right shift operator?

PHPs current right shift operator preserves signage, but this is not
always desirable.

I propose the same syntax as JavaScript for this: >>>

php -r 'var_dump(-256 >> 8);'
int(-1)

php -r 'var_dump(-256 >>> 8);'
int(16777215)

This will introduce a T_SHRZF token and corresponding opcode. Targeting PHP 7.

Search Discussions

  • Leigh at Feb 3, 2015 at 1:24 pm
    This will introduce a T_SHRZF token and corresponding opcode. Targeting PHP 7.
    That should have been T_SRZF, and I suppose I would also have to add
    ">>>=" (T_SRZF_EQUAL) which looks nasty, but should be included for
    completeness.
  • Andrea Faulds at Feb 3, 2015 at 1:25 pm
    Hi Leigh,
    On 3 Feb 2015, at 13:20, Leigh wrote:

    Hi list,

    How do we feel about a zero-fill right shift operator?

    PHPs current right shift operator preserves signage, but this is not
    always desirable.

    I propose the same syntax as JavaScript for this: >>>

    php -r 'var_dump(-256 >> 8);'
    int(-1)

    php -r 'var_dump(-256 >>> 8);'
    int(16777215)

    This will introduce a T_SHRZF token and corresponding opcode. Targeting PHP 7.
    Hmm, how would this interact with bigints? Does it rely on fixed-width integers, as it appears to? :/

    I think it’s a very obscure use case, too. Might be better to add a function in this case, like we did for intdiv().

    Thoughts?

    --
    Andrea Faulds
    http://ajf.me/
  • Leigh at Feb 3, 2015 at 1:51 pm

    On 3 February 2015 at 13:25, Andrea Faulds wrote:
    Hmm, how would this interact with bigints? Does it rely on fixed-width integers, as it appears to? :/
    No idea. Personally I'm opposed to the bigints implementation because
    of the implicit type auto-promotion.
  • Andrea Faulds at Feb 3, 2015 at 1:54 pm
    Hi Leigh,
    On 3 Feb 2015, at 13:51, Leigh wrote:
    On 3 February 2015 at 13:25, Andrea Faulds wrote:
    Hmm, how would this interact with bigints? Does it rely on fixed-width integers, as it appears to? :/
    No idea. Personally I'm opposed to the bigints implementation because
    of the implicit type auto-promotion.
    Huh? There’s no type promotion from a userland perspective, it’s entirely an implementation detail. Yes, some integers may be IS_LONG and others may be IS_BIGINT internally, but that’s only for Zend Engine 3 (might change in future), the boundary point varies by platform, and crucially, you can’t distinguish them from userland.

    --
    Andrea Faulds
    http://ajf.me/
  • Leigh at Feb 3, 2015 at 2:15 pm

    On 3 February 2015 at 13:54, Andrea Faulds wrote:
    Hi Leigh,
    On 3 Feb 2015, at 13:51, Leigh wrote:
    No idea. Personally I'm opposed to the bigints implementation because
    of the implicit type auto-promotion.
    Huh? There’s no type promotion from a userland perspective, it’s entirely an implementation detail. Yes, some integers may be IS_LONG and others may be IS_BIGINT internally, but that’s only for Zend Engine 3 (might change in future), the boundary point varies by platform, and crucially, you can’t distinguish them from userland.
    Aside from the breaks to some binary ops and once you hit the
    promotion breakpoint working with that integer is a lot slower. Lets
    not derail this thread into a discussion about why I dislike bigints.
  • Andrea Faulds at Feb 3, 2015 at 2:36 pm

    On 3 Feb 2015, at 14:15, Leigh wrote:
    On 3 February 2015 at 13:54, Andrea Faulds wrote:
    Hi Leigh,
    On 3 Feb 2015, at 13:51, Leigh wrote:
    No idea. Personally I'm opposed to the bigints implementation because
    of the implicit type auto-promotion.
    Huh? There’s no type promotion from a userland perspective, it’s entirely an implementation detail. Yes, some integers may be IS_LONG and others may be IS_BIGINT internally, but that’s only for Zend Engine 3 (might change in future), the boundary point varies by platform, and crucially, you can’t distinguish them from userland.
    Aside from the breaks to some binary ops
    I don’t know where you got that idea. The binary ops are consistent - they aren’t constrained by register size like in previous PHP versions, but they’re still completely consistent.
    and once you hit the
    promotion breakpoint working with that integer is a lot slower.
    It’s slower, yes, but that hardly matters. If people care so much about performance, why use PHP?
    --
    Andrea Faulds
    http://ajf.me/
  • Leigh at Feb 3, 2015 at 2:43 pm

    On 3 February 2015 at 14:36, Andrea Faulds wrote:
    I don’t know where you got that idea. The binary ops are consistent - they aren’t constrained by register size like in previous PHP versions, but they’re still completely consistent.
    php -r 'var_dump(1 << 65);'
    int(2)

    Rotate left gets broken.
    It’s slower, yes, but that hardly matters. If people care so much about performance, why use PHP?
    If people didn't care about performance, we wouldn't have phpng, or
    any of the other work people have done to make the engine faster.

    Sometimes you have to make the most of what you have available.
  • Andrea Faulds at Feb 3, 2015 at 2:49 pm
    Hi,
    On 3 Feb 2015, at 14:43, Leigh wrote:
    On 3 February 2015 at 14:36, Andrea Faulds wrote:
    I don’t know where you got that idea. The binary ops are consistent - they aren’t constrained by register size like in previous PHP versions, but they’re still completely consistent.
    php -r 'var_dump(1 << 65);'
    int(2)

    Rotate left gets broken.
    It’s not “broken”, the behaviour is just different to account for it now being an arbitrary-precision type. If you want to “rotate left”, bitmasking does exist.
    It’s slower, yes, but that hardly matters. If people care so much about performance, why use PHP?
    If people didn't care about performance, we wouldn't have phpng, or
    any of the other work people have done to make the engine faster.

    Sometimes you have to make the most of what you have available.
    OK, performance is not unimportant. But in most cases, arbitrary-precision integers are not going to be a bottleneck for your web app.

    Also, the bigint changes only affect you if you’re dealing with large integers anyway. If you want to preserve the horrid float promotion behaviour, you can do so explicitly. But I think in most cases, it’s better to trade off performance for lack of data loss.

    --
    Andrea Faulds
    http://ajf.me/
  • Leigh at Feb 3, 2015 at 2:59 pm

    On 3 February 2015 at 14:49, Andrea Faulds wrote:
    It’s not “broken”, the behaviour is just different to account for it now being an arbitrary-precision type.
    That's pretty much the definition of a BC issue.
    Also, the bigint changes only affect you if you’re dealing with large integers anyway. If you want to preserve the horrid float promotion behaviour, you can do so explicitly. But I think in most cases, it’s better to trade off performance for lack of data loss.
    It's not anything to do with float promotion or data loss. If I'm
    working with a 64-bit bitmask that gets promoted to bigint when I set
    the high bit, it's a performance regression from then on. Not
    everything written in PHP is a web app.
  • Andrea Faulds at Feb 3, 2015 at 3:02 pm

    On 3 Feb 2015, at 14:59, Leigh wrote:
    On 3 February 2015 at 14:49, Andrea Faulds wrote:
    It’s not “broken”, the behaviour is just different to account for it now being an arbitrary-precision type.
    That's pretty much the definition of a BC issue.
    Sure, it’s a BC break if you’re relying on the undefined behaviour of your platform. Which a lot of people unfortunately were doing.

    Actually, this specific case was already broken in PHP 7 after the Integer Semantics RFC passed, which made our bitwise shifts more consistent across platforms.
    Also, the bigint changes only affect you if you’re dealing with large integers anyway. If you want to preserve the horrid float promotion behaviour, you can do so explicitly. But I think in most cases, it’s better to trade off performance for lack of data loss.
    It's not anything to do with float promotion or data loss. If I'm
    working with a 64-bit bitmask that gets promoted to bigint when I set
    the high bit
    Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.

    --
    Andrea Faulds
    http://ajf.me/
  • Leigh at Feb 3, 2015 at 3:12 pm

    On 3 February 2015 at 15:02, Andrea Faulds wrote:
    Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.
    I'm assuming your bigint implementation would want to respect signage.

    When does it promote? 63rd to preserve signage?

    4611686018427387904 // 1 << 62 - int
    9223372036854775808 // 1 << 63 - bigint
    18446744073709551616 // 1 << 64 - bigint

    Or 64th to for complete madness?

    4611686018427387904 // 1 << 62 - int
    -9223372036854775808 // 1 << 63 - int
    18446744073709551616 // 1 << 64 - bigint
  • Andrea Faulds at Feb 3, 2015 at 4:09 pm

    On 3 Feb 2015, at 15:12, Leigh wrote:
    On 3 February 2015 at 15:02, Andrea Faulds wrote:
    Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.
    I'm assuming your bigint implementation would want to respect signage.

    When does it promote? 63rd to preserve signage?

    4611686018427387904 // 1 << 62 - int
    9223372036854775808 // 1 << 63 - bigint
    18446744073709551616 // 1 << 64 - bigint

    Or 64th to for complete madness?

    4611686018427387904 // 1 << 62 - int
    -9223372036854775808 // 1 << 63 - int
    18446744073709551616 // 1 << 64 - bigint
    The specific code can be found here:

    https://github.com/TazeTSchnitzel/php-src/blob/b91a80879ca3ba269bd239d9c820003c83d0dbc1/Zend/zend_operators.c#L2265

    The algorithm is fairly simple: if the number of bits in the long plus the number of bits to shift is greater than the number of bits in a zend_long, then it promotes.

    Thus:

    $ sapi/cli/php -r '$x = 1 << 62; debug_zval_dump($x);'
    long(4611686018427387904)
    $ sapi/cli/php -r '$x = 1 << 63; debug_zval_dump($x);'
    bigint(9223372036854775808) refcount(2)
    $ sapi/cli/php -r '$x = 1 << 64; debug_zval_dump($x);'
    bigint(18446744073709551616) refcount(2)

    I tried some negative numbers, but I’ve noticed that any left shift on a negative integer promotes - that’s probably because clz is including the high bit... that should probably be fixed, mostly likely by doing clz on its absolute value in that case and factoring in the high bit.
    --
    Andrea Faulds
    http://ajf.me/
  • Leigh at Feb 3, 2015 at 4:22 pm
    On 3 February 2015 at 15:02, Andrea Faulds wrote:
    Why would it be promoted?! The high bit is the 63rd bit. It fits within a long. because
    On 3 February 2015 at 16:08, Andrea Faulds wrote:

    $ sapi/cli/php -r '$x = 1 << 63; debug_zval_dump($x);'
    bigint(9223372036854775808) refcount(2)
  • Andrea Faulds at Feb 3, 2015 at 4:26 pm

    On 3 Feb 2015, at 16:22, Leigh wrote:
    On 3 February 2015 at 15:02, Andrea Faulds wrote:

    Why would it be promoted?! The high bit is the 63rd bit. It fits within a long. because
    On 3 February 2015 at 16:08, Andrea Faulds wrote:

    $ sapi/cli/php -r '$x = 1 << 63; debug_zval_dump($x);'
    bigint(9223372036854775808) refcount(2)
    Yeah, I see your point now, although I’d question *why* you need to mess with the high bit.

    You can still do ^ -1 or something as usual, though.
    --
    Andrea Faulds
    http://ajf.me/
  • Ben at Feb 3, 2015 at 1:28 pm
    is called a logical right shift (in contrast to the arithmetic right shift >>). This would be a good addition.
    $op1 >>> $op2 is equivalent to ($op1 >> $op2) & (PHP_INT_MAX >> $op2 - 1)

    ========== Original ==========
    From: Leigh <leight@gmail.com>
    To: internals@lists.php.net
    Date: Tue, 03 Feb 2015 14:24:07 +0100
    Subject: [PHP-DEV] Re: Zero-fill right shift.


    This will introduce a T_SHRZF token and corresponding opcode. Targeting PHP 7.
    That should have been T_SRZF, and I suppose I would also have to add
    ">>>=" (T_SRZF_EQUAL) which looks nasty, but should be included for
    completeness.
  • Dmitry Stogov at Feb 4, 2015 at 12:45 pm
    I'm not sure if this is often necessary, but sometimes it may be nice to
    have.

    Actually, this is "logical right shift" operation (>> is "arithmetic right
    shift").
    LSHR is a well recognizable name, used in assemblers.
    Use T_LSHR instead of T_SHRZF.

    Thanks. Dmitry.

    On Tue, Feb 3, 2015 at 4:20 PM, Leigh wrote:

    Hi list,

    How do we feel about a zero-fill right shift operator?

    PHPs current right shift operator preserves signage, but this is not
    always desirable.

    I propose the same syntax as JavaScript for this: >>>

    php -r 'var_dump(-256 >> 8);'
    int(-1)

    php -r 'var_dump(-256 >>> 8);'
    int(16777215)

    This will introduce a T_SHRZF token and corresponding opcode. Targeting
    PHP 7.

    --
    PHP Internals - PHP Runtime Development Mailing List
    To unsubscribe, visit: http://www.php.net/unsub.php

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-internals @
categoriesphp
postedFeb 3, '15 at 1:20p
activeFeb 4, '15 at 12:45p
posts17
users4
websitephp.net

People

Translate

site design / logo © 2022 Grokbase