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.
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.
Hi Leigh,
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/
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.
Hi Leigh,
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/
Hi Leigh,
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.
Hi Leigh,
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/
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.
Hi,
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/
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.
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/
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
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 - bigintOr 64th to for complete madness?
4611686018427387904 // 1 << 62 - int
-9223372036854775808 // 1 << 63 - int
18446744073709551616 // 1 << 64 - bigint
The specific code can be found here:
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/
Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.
because
$ sapi/cli/php -r '$x = 1 << 63; debug_zval_dump($x);'
bigint(9223372036854775808) refcount(2)
Why would it be promoted?! The high bit is the 63rd bit. It fits within a long.
because
$ 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/
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.
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.