Logical shift

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Logical shift

D Burgess-3
Forgive me if this has been previously noted:
The 5.3 manual says
>  All bitwise operations convert its operands to integers (see §3.4.3), operate on all bits of those integers, and result in an integer.
> Both right and left shifts fill the vacant bits with zeros.

In other words an "unsigned" shift or logical shift. No sign extension.

Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio
> string.format("0x%016x",(1<<63)>>8)
0x0080000000000000

Bash
# printf '0x%016x\n' $(( (1<<63)>>8 ))
0xff80000000000000

PHP
printf '0x%016x\n' $(( (1<<63)>>8 ))
0xff80000000000000

Perl
# perl -e 'printf "0x%016x\n",(1<<63)>>8'
0x0080000000000000

SQLite 3.29.0
sqlite> select printf('0x%016x',(1<<63)>>8);
0xff80000000000000

*I wish this was highlighted in the manual.*

What was the reasoning in choosing logical shift for >> rather than arithmetic?
It seems strange given that >> only operates on lua_integer and
lua_integer is by default a signed entity.
also note:
> string.format("%d , %d",(1<<63),(1<<63)//256)
-9223372036854775808 , -36028797018963968
> string.format("%d , %d",(1<<63),(1<<63)//(2^8))
-9223372036854775808 , -36028797018963968
> string.format("%d , %d",(1<<63),(1<<63)>>8)
-9223372036854775808 , 36028797018963968

Reply | Threaded
Open this post in threaded view
|

Re: Logical shift

Sean Conner
It was thus said that the Great D Burgess once stated:

> Forgive me if this has been previously noted:
> The 5.3 manual says
> >  All bitwise operations convert its operands to integers (see §3.4.3), operate on all bits of those integers, and result in an integer.
> > Both right and left shifts fill the vacant bits with zeros.
>
> In other words an "unsigned" shift or logical shift. No sign extension.
>
> Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio
> > string.format("0x%016x",(1<<63)>>8)
> 0x0080000000000000
>
> Bash
> # printf '0x%016x\n' $(( (1<<63)>>8 ))
> 0xff80000000000000
>
> PHP
> printf '0x%016x\n' $(( (1<<63)>>8 ))
> 0xff80000000000000
>
> Perl
> # perl -e 'printf "0x%016x\n",(1<<63)>>8'
> 0x0080000000000000
>
> SQLite 3.29.0
> sqlite> select printf('0x%016x',(1<<63)>>8);
> 0xff80000000000000
>
> *I wish this was highlighted in the manual.*
>
> What was the reasoning in choosing logical shift for >> rather than arithmetic?

  From the C89 standard (ISO/IEC 9899:1990), section 6.3.7 (emphasis added):

        The result of El >> E2 is El right-shifted E2 bit positions. If El
        has an unsigned type or if El has a signed type and a nonnegative
        value, the value of the result is the integral part of the quotient
        of El divided by the quantity, 2 raised to the power E2. If El has a
        signed type and a negative value, the resulting value is
        implementation-defined.
        ^^^^^^^^^^^^^^^^^^^^^^

  From that, I would assume that the only way to ensure consistent values
across all C compilers is to only do unsigned shifts.

  -spc


Reply | Threaded
Open this post in threaded view
|

Re: Logical shift

Jonathan Goble
On Sun, Oct 13, 2019 at 9:59 PM Sean Conner <[hidden email]> wrote:

>
> It was thus said that the Great D Burgess once stated:
> > Forgive me if this has been previously noted:
> > The 5.3 manual says
> > >  All bitwise operations convert its operands to integers (see §3.4.3), operate on all bits of those integers, and result in an integer.
> > > Both right and left shifts fill the vacant bits with zeros.
> >
> > In other words an "unsigned" shift or logical shift. No sign extension.
> >
> > Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio
> > > string.format("0x%016x",(1<<63)>>8)
> > 0x0080000000000000
> >
> > Bash
> > # printf '0x%016x\n' $(( (1<<63)>>8 ))
> > 0xff80000000000000
> >
> > PHP
> > printf '0x%016x\n' $(( (1<<63)>>8 ))
> > 0xff80000000000000
> >
> > Perl
> > # perl -e 'printf "0x%016x\n",(1<<63)>>8'
> > 0x0080000000000000
> >
> > SQLite 3.29.0
> > sqlite> select printf('0x%016x',(1<<63)>>8);
> > 0xff80000000000000
> >
> > *I wish this was highlighted in the manual.*
> >
> > What was the reasoning in choosing logical shift for >> rather than arithmetic?
>
>   From the C89 standard (ISO/IEC 9899:1990), section 6.3.7 (emphasis added):
>
>         The result of El >> E2 is El right-shifted E2 bit positions. If El
>         has an unsigned type or if El has a signed type and a nonnegative
>         value, the value of the result is the integral part of the quotient
>         of El divided by the quantity, 2 raised to the power E2. If El has a
>         signed type and a negative value, the resulting value is
>         implementation-defined.
>         ^^^^^^^^^^^^^^^^^^^^^^
>
>   From that, I would assume that the only way to ensure consistent values
> across all C compilers is to only do unsigned shifts.

The Lua VM implements shifts here:
https://github.com/lua/lua/blob/master/lvm.c#L673-L687

It took me a moment to understand that, but after looking at the intop
macro in lvm.h (https://github.com/lua/lua/blob/master/lvm.h#L61), it
casts the operands to unsigned before performing the operation
(https://github.com/lua/lua/blob/master/llimits.h#L129-L141).

I think it might be useful to offer both types of right shift. Perhaps
the arithmetic shift can be offered as the >>> operator?

Reply | Threaded
Open this post in threaded view
|

Re: Logical shift

D Burgess-4
> Perhaps the arithmetic shift can be offered as the >>> operator?
Excellent suggestion.

Reply | Threaded
Open this post in threaded view
|

Re: Logical shift

Egor Skriptunoff-2
On Mon, Oct 14, 2019 at 5:51 AM D Burgess wrote:
> Perhaps the arithmetic shift can be offered as the >>> operator?
Excellent suggestion.


(x >>> k) == (x >> k) - ((x & math.mininteger) >> (k-1))