Difference between revisions of "Right Shift"

From Second Life Wiki
Jump to navigation Jump to search
m (<lsl> tag to <source>)
 
(19 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{LSL Header}}{{RightToc}}
{{LSL Header}}{{RightToc}}


== Bitwise vs. Arithmetic ==
== Unsigned vs. Arithmetic ==


There are two types of Right Shifts, that can be performed on an integer. They are: Bitwise and Arithmetic. LSL currently only supports Arithmetic. The difference between the two modes is how it fills the bits revealed. In bitwise mode, the revealed bits are always zero; in Arithmetic mode, it duplicates the old top bit to all the new bits. If you take the expression <code>int >> count</code> where ''int'' is arithmetically shifted right ''count'' bits, then this is the same mathematically as doing <code>int / (2 <sup>count</sup>)</code> or in LSL <code>int / llPow(2.0, count)</code>.
There are two types of Right Shifts, that can be performed on an integer. They are: Unsigned and Arithmetic. LSL currently only supports Arithmetic. The difference between the two modes is how it fills the bits revealed. With the unsigned mode, the revealed bits are always zero; in Arithmetic mode, it duplicates the old top bit to all the new bits. If you take the expression <code>value >> count</code> where ''value'' is arithmetically shifted right ''count'' bits, then this is the same mathematically as doing <code>value / (2<sup>count</sup>)</code> or in LSL <code>value / [[llPow]](2.0, count)</code> (but will result in data loss in LSL).


== How to do Bitwise Right Shifts in LSL ==
== How to do Unsigned Right Shifts in LSL ==


Since LSL does not have a bitwise right shift operator you have to do it yourself. There are two methods for doing this, each with it's advantages and disadvantages.
Since LSL does not have a unsigned right shift operator you have to do it yourself. There are two methods for doing this, each with it's advantages and disadvantages.
 
There is a feature suggestion to add an unsigned right shift operator to LSL: {{JIRA|SVC-1171}}


=== Method 1 ===
=== Method 1 ===
<lsl>(value >> count) & ~((~value) >> count);</lsl>
This method is good when count is dynamic (not known at compile time) but is twice as complicated as Method 2.
This method is good when count is dynamic.
<source lang="lsl2">((value & 0x7fFFffFF) >> count) - ((value & 0x80000000) >> count);</source>
It works because all the bits that need to be turned on will be turned on both sides of the AND but on only one side will the arithmetic right shift cause the sign bit to be extended. The result of the and is a value that is always a bitwise right shift.
This works by shifting body and sign bits separately and then recombining them. Since the sign bit is extended as a negative number, we just need to make it positive. Since the left and right values have no bits in common (due to the masking), we can use | or + and they will do the same thing. To simplify the code we merge the negation and combine into a single operation.


=== Method 2 ===
=== Method 2 ===
<lsl>(value >> count) & mask;</lsl>
This method can only be used when count is a constant value. It works by using a constant mask to remove the extended sign bits.
This method can only be used when count is a constant value. You use a constant mask to remove the extended sign bits. Example: <code>(value >> 5) & 0x07FFFFFF</code> As you can see the top five bits have been turned off in the mask value, if you have trouble seeing that, you can just use the lookup table below.
<source lang="lsl2">(value >> count) & mask;</source>
'''Example:''' <code>(value >> 5) & 0x07FFFFFF</code><br>
As you can see the top five bits have been turned off in the mask value, if you have trouble seeing that, you can just use the lookup table below.


{|
{|
Line 25: Line 29:
! Shift
! Shift
! Mask
! Mask
|-
! Mask - Bit View
|- align="right"
| 0
| 0
| {{LSL Hex|0xFFFFFFFF|}}
| {{LSL Hex|0xFFFFFFFF|}}
|-
| 11111111 11111111<br/>11111111 11111111
|- align="right"
| 1
| 1
| {{LSL Hex|0x7FFFFFFF|}}
| {{LSL Hex|0x7FFFFFFF|}}
|-
| 01111111 11111111<br/>11111111 11111111
|- align="right"
| 2
| 2
| {{LSL Hex|0x3FFFFFFF|}}
| {{LSL Hex|0x3FFFFFFF|}}
|-
| 00111111 11111111<br/>11111111 11111111
|- align="right"
| 3
| 3
| {{LSL Hex|0x1FFFFFFF|}}
| {{LSL Hex|0x1FFFFFFF|}}
|-
| 00011111 11111111<br/>11111111 11111111
|- align="right"
| 4
| 4
| {{LSL Hex|0x0FFFFFFF|}}
| {{LSL Hex|0x0FFFFFFF|}}
|-
| 00001111 11111111<br/>11111111 11111111
|- align="right"
| 5
| 5
| {{LSL Hex|0x07FFFFFF|}}
| {{LSL Hex|0x07FFFFFF|}}
|-
| 00000111 11111111<br/>11111111 11111111
|- align="right"
| 6
| 6
| {{LSL Hex|0x03FFFFFF|}}
| {{LSL Hex|0x03FFFFFF|}}
|-
| 00000011 11111111<br/>11111111 11111111
|- align="right"
| 7
| 7
| {{LSL Hex|0x01FFFFFF|}}
| {{LSL Hex|0x01FFFFFF|}}
|-
| 00000001 11111111<br/>11111111 11111111
|}
|
{|{{Prettytable}}
|-{{Hl2}}
! Shift
! Mask
! Mask - Bit View
|- align="right"
| 8
| 8
| {{LSL Hex|0x00FFFFFF|}}
| {{LSL Hex|0x00FFFFFF|}}
|-
| 00000000 11111111<br/>11111111 11111111
|- align="right"
| 9
| 9
| {{LSL Hex|0x007FFFFF|}}
| {{LSL Hex|0x007FFFFF|}}
|-
| 00000000 01111111<br/>11111111 11111111
|- align="right"
| 10
| 10
| {{LSL Hex|0x003FFFFF|}}
| {{LSL Hex|0x003FFFFF|}}
|}
| 00000000 00111111<br/>11111111 11111111
|
|- align="right"
{|{{Prettytable}}
|-{{Hl2}}
! Shift
! Mask
|-
| 11
| 11
| {{LSL Hex|0x001FFFFF|}}
| {{LSL Hex|0x001FFFFF|}}
|-
| 00000000 00011111<br/>11111111 11111111
|- align="right"
| 12
| 12
| {{LSL Hex|0x000FFFFF|}}
| {{LSL Hex|0x000FFFFF|}}
|-
| 00000000 00001111<br/>11111111 11111111
|- align="right"
| 13
| 13
| {{LSL Hex|0x0007FFFF|}}
| {{LSL Hex|0x0007FFFF|}}
|-
| 00000000 00000111<br/>11111111 11111111
|- align="right"
| 14
| 14
| {{LSL Hex|0x0003FFFF|}}
| {{LSL Hex|0x0003FFFF|}}
|-
| 00000000 00000011<br/>11111111 11111111
|- align="right"
| 15
| 15
| {{LSL Hex|0x0001FFFF|}}
| {{LSL Hex|0x0001FFFF|}}
|-
| 00000000 00000001<br/>11111111 11111111
|}
|
{|{{Prettytable}}
|-{{Hl2}}
! Shift
! Mask
! Mask - Bit View
|- align="right"
| 16
| 16
| {{LSL Hex|0x0000FFFF|}}
| {{LSL Hex|0x0000FFFF|}}
|-
| 11111111 11111111
|- align="right"
| 17
| 17
| {{LSL Hex|0x00007FFF|}}
| {{LSL Hex|0x00007FFF|}}
|-
| 01111111 11111111
|- align="right"
| 18
| 18
| {{LSL Hex|0x00003FFF|}}
| {{LSL Hex|0x00003FFF|}}
|-
| 00111111 11111111
|- align="right"
| 19
| 19
| {{LSL Hex|0x00001FFF|}}
| {{LSL Hex|0x00001FFF|}}
|-
| 00011111 11111111
|- align="right"
| 20
| 20
| {{LSL Hex|0x00000FFF|}}
| {{LSL Hex|0x00000FFF|}}
|-
| 00001111 11111111
|- align="right"
| 21
| 21
| {{LSL Hex|0x000007FF|}}
| {{LSL Hex|0x000007FF|}}
|}
| 00000111 11111111
|
|- align="right"
{|{{Prettytable}}
|-{{Hl2}}
! Shift
! Mask
|-
| 22
| 22
| {{LSL Hex|0x000003FF|}}
| {{LSL Hex|0x000003FF|}}
|-
| 00000011 11111111
|- align="right"
| 23
| 23
| {{LSL Hex|0x000001FF|}}
| {{LSL Hex|0x000001FF|}}
|-
| 00000001 11111111
|- align="right"
| 24
| 24
| {{LSL Hex|0x000000FF|}}
| {{LSL Hex|0x000000FF|}}
|-
| 00000000 11111111
|- align="right"
| 25
| 25
| {{LSL Hex|0x0000007F|}}
| {{LSL Hex|0x0000007F|}}
|-
| 00000000 01111111
|- align="right"
| 26
| 26
| {{LSL Hex|0x0000003F|}}
| {{LSL Hex|0x0000003F|}}
|-
| 00000000 00111111
|- align="right"
| 27
| 27
| {{LSL Hex|0x0000001F|}}
| {{LSL Hex|0x0000001F|}}
|-
| 00000000 00011111
|- align="right"
| 28
| 28
| {{LSL Hex|0x0000000F|}}
| {{LSL Hex|0x0000000F|}}
|-
| 00000000 00001111
|- align="right"
| 29
| 29
| {{LSL Hex|0x00000007|}}
| {{LSL Hex|0x00000007|}}
|-
| 00000000 00000111
|- align="right"
| 30
| 30
| {{LSL Hex|0x00000003|}}
| {{LSL Hex|0x00000003|}}
|-
| 00000000 00000011
|- align="right"
| 31
| 31
| {{LSL Hex|0x00000001|}}
| {{LSL Hex|0x00000001|}}
|-
| 00000000 00000001
|- align="right"
| 32
| 32
| {{LSL Hex|0x00000000|}}
| {{LSL Hex|0x00000000|}}
| 00000000 00000000
|}
|}
|}
|}


== Example Bitwise Right Shift Function ==
== Example Unsigned Right Shift Function ==


Here's a function to pass a signed 32 bit integer along with a value indicating how far to shift the bits. This method is primarily needed to shift bits for negative integers, as the regular bit shift operators work just fine for positive values.
Here's a function that encapsulates the first method. It allows for a signed 32 bit integer along with a value indicating how far to shift the bits to be executed as an unsigned right shift.


<lsl>// the lsl right shift is an arithmetic right shift,
<source lang="lsl2">// the lsl right shift is an arithmetic right shift,
// this means it more closely resembles dividing by a
// this means it more closely resembles dividing by a
// positive power of two then a bitwise right shift.
// positive power of two then a unsigned right shift.
// To perform a bitwise right shift you need to be smart
// To perform a unsigned right shift you need to be clever
integer rightShift(integer value, integer count)
integer rightShift(integer value, integer count)
{
{
     return (value >> count) & ~((~value) >> count);
     return ((value & 0x7fFFffFF) >> count) - ((value & 0x80000000) >> count);
}</lsl>
    //This works by shifting body and sign bits separately and then
    //recombining them. Since the sign bit is extended as a negative
    //number, we just need to make it positive. Since the left and
    //right values have no bits in common (due to the masking), we
    //can use | or + and they will do the same thing. To simplify the
    //code we merge the negation and combine into a single operation.
}
 
// Jonhboy Resident
integer rightShiftJonhboy(integer value, integer count) {
    if(count & 31)
        return ~(0x80000000 >> (count - 1)) & (value >> count);
    return value;
    //This works by conditionally applying a calculated mask after
    //shifting. The disadvantage of this method is that it is hard
    //to inline due to the condition, not to mention the cost of forking.
}
</source>
'''Example Usage:'''
'''Example Usage:'''
<lsl>default
<source lang="lsl2">default
{
{
     state_entry()
     state_entry()
     {
     {
         // output should be 268435449
         // output should be 268435449
         llSay(DEBUG_CHANNEL, (string)rightShift(-99, 4));
         llSay(DEBUG_CHANNEL, (string)rightShift(-99, 4)); // output: 268435449
 
        llSay(DEBUG_CHANNEL, (string)rightShiftJonhboy(-99, 4));  // output: 268435449
         // before: 1111 1111 1111 1111 1111 1111 1001 1101
         // before: 1111 1111 1111 1111 1111 1111 1001 1101
         // after:  0000 1111 1111 1111 1111 1111 1111 1001
         // after:  0000 1111 1111 1111 1111 1111 1111 1001
     }
     }
}</lsl>
}</source>


{{LSLC|Examples|Right Shift}}
{{LSLC|Examples|Right Shift}}
[[Category: LSL Encryption]]
[[Category: LSL Encryption]]

Latest revision as of 16:46, 24 January 2015

Unsigned vs. Arithmetic

There are two types of Right Shifts, that can be performed on an integer. They are: Unsigned and Arithmetic. LSL currently only supports Arithmetic. The difference between the two modes is how it fills the bits revealed. With the unsigned mode, the revealed bits are always zero; in Arithmetic mode, it duplicates the old top bit to all the new bits. If you take the expression value >> count where value is arithmetically shifted right count bits, then this is the same mathematically as doing value / (2count) or in LSL value / llPow(2.0, count) (but will result in data loss in LSL).

How to do Unsigned Right Shifts in LSL

Since LSL does not have a unsigned right shift operator you have to do it yourself. There are two methods for doing this, each with it's advantages and disadvantages.

There is a feature suggestion to add an unsigned right shift operator to LSL: SVC-1171

Method 1

This method is good when count is dynamic (not known at compile time) but is twice as complicated as Method 2.

((value & 0x7fFFffFF) >> count) - ((value & 0x80000000) >> count);

This works by shifting body and sign bits separately and then recombining them. Since the sign bit is extended as a negative number, we just need to make it positive. Since the left and right values have no bits in common (due to the masking), we can use | or + and they will do the same thing. To simplify the code we merge the negation and combine into a single operation.

Method 2

This method can only be used when count is a constant value. It works by using a constant mask to remove the extended sign bits.

(value >> count) & mask;

Example: (value >> 5) & 0x07FFFFFF
As you can see the top five bits have been turned off in the mask value, if you have trouble seeing that, you can just use the lookup table below.

Mask Lookup Table
Shift Mask Mask - Bit View
0 0xFFFFFFFF 11111111 11111111
11111111 11111111
1 0x7FFFFFFF 01111111 11111111
11111111 11111111
2 0x3FFFFFFF 00111111 11111111
11111111 11111111
3 0x1FFFFFFF 00011111 11111111
11111111 11111111
4 0x0FFFFFFF 00001111 11111111
11111111 11111111
5 0x07FFFFFF 00000111 11111111
11111111 11111111
6 0x03FFFFFF 00000011 11111111
11111111 11111111
7 0x01FFFFFF 00000001 11111111
11111111 11111111
Shift Mask Mask - Bit View
8 0x00FFFFFF 00000000 11111111
11111111 11111111
9 0x007FFFFF 00000000 01111111
11111111 11111111
10 0x003FFFFF 00000000 00111111
11111111 11111111
11 0x001FFFFF 00000000 00011111
11111111 11111111
12 0x000FFFFF 00000000 00001111
11111111 11111111
13 0x0007FFFF 00000000 00000111
11111111 11111111
14 0x0003FFFF 00000000 00000011
11111111 11111111
15 0x0001FFFF 00000000 00000001
11111111 11111111
Shift Mask Mask - Bit View
16 0x0000FFFF 11111111 11111111
17 0x00007FFF 01111111 11111111
18 0x00003FFF 00111111 11111111
19 0x00001FFF 00011111 11111111
20 0x00000FFF 00001111 11111111
21 0x000007FF 00000111 11111111
22 0x000003FF 00000011 11111111
23 0x000001FF 00000001 11111111
24 0x000000FF 00000000 11111111
25 0x0000007F 00000000 01111111
26 0x0000003F 00000000 00111111
27 0x0000001F 00000000 00011111
28 0x0000000F 00000000 00001111
29 0x00000007 00000000 00000111
30 0x00000003 00000000 00000011
31 0x00000001 00000000 00000001
32 0x00000000 00000000 00000000

Example Unsigned Right Shift Function

Here's a function that encapsulates the first method. It allows for a signed 32 bit integer along with a value indicating how far to shift the bits to be executed as an unsigned right shift.

// the lsl right shift is an arithmetic right shift,
// this means it more closely resembles dividing by a
// positive power of two then a unsigned right shift.
// To perform a unsigned right shift you need to be clever
integer rightShift(integer value, integer count)
{
    return ((value & 0x7fFFffFF) >> count) - ((value & 0x80000000) >> count);
    //This works by shifting body and sign bits separately and then
    //recombining them. Since the sign bit is extended as a negative
    //number, we just need to make it positive. Since the left and
    //right values have no bits in common (due to the masking), we
    //can use | or + and they will do the same thing. To simplify the
    //code we merge the negation and combine into a single operation.
}

// Jonhboy Resident
integer rightShiftJonhboy(integer value, integer count) {
    if(count & 31)
        return ~(0x80000000 >> (count - 1)) & (value >> count);
    return value;
    //This works by conditionally applying a calculated mask after
    //shifting. The disadvantage of this method is that it is hard 
    //to inline due to the condition, not to mention the cost of forking.
}

Example Usage:

default
{
    state_entry()
    {
        // output should be 268435449
        llSay(DEBUG_CHANNEL, (string)rightShift(-99, 4)); // output: 268435449
        llSay(DEBUG_CHANNEL, (string)rightShiftJonhboy(-99, 4));  // output: 268435449
        // before: 1111 1111 1111 1111 1111 1111 1001 1101
        // after:  0000 1111 1111 1111 1111 1111 1111 1001
    }
}