Help with bit shifting

Disclaimer: I am quite new to working with the bit32 library and bit shifting in general. Bear with me as I attempt to explain what I did.

I’m experimenting with the bit32 library and made a few observations about how it works in comparison to JavaScript’s shift operators.

Lua

Code

print(bit32.rshift(0, 0))
print(bit32.rshift(0, 1))
print(bit32.rshift(1, 0))
print(bit32.rshift(1, 1))
print("________________________")
print(bit32.rshift(0, 0))
print(bit32.rshift(0, -1))
print(bit32.rshift(-1, 0))
print(bit32.rshift(-1, -1))

Output
image

JavaScript


  1. It appears the bit32 library uses the no-sign shift operator (>>> instead of >>). How could I use the >> equivalent in Luau?
  2. In the final example, Lua returns 4294967294 for bit32.rshift(-1, -1) but JS returns 1 for the same equation. Why (JS overflow?)?
1 Like

It looks like lua fills vacant bits with 0 regardless, whereas JavaScript will fill vacant bits with the sign bit (something to do with two’s complement, I’m not very sure)

1 Like

I think the best solution for this is to use bit32.replace(shiftedNum, -1, 31, 31 - shiftAmount) when num < 0.

2 Likes

So for this example:

-- Lua
bit32.rshift(-1, 0) -- 4294967295

-- JS
-1 >> 0 -- -1
-1 >>> 0 -- 4294967295

Using

bit32.replace(bit32.rshift(-1, 0), -1, 31, 31 - -1)

and

bit32.replace(bit32.rshift(-1, 0), -1, 31, 31 - 0)

yield a “trying to access non-existent bits” error.

1 Like

Maybe I read the documentation wrong, perhaps you need to use a loop instead, but the base premise is to replace bits with a different bit so that a negative number is bit-shifted with 1s instead of 0s

1 Like

turns out lua just decides that the integer becomes unsigned or something, but this code snippet seems to do the trick:

local function rshiftsigned(num: number, shiftAmount: number)
    local shiftedNum = bit32.rshift(num, shiftAmount)

    if num < 0 then
        return shiftedNum - 2 ^ 32
    else
        return shiftedNum
    end
end
2 Likes

The bit32 library’s functions are only compatible with signed 32 bit integers.
https://www.lua.org/manual/5.2/manual.html#6.7

Unless otherwise stated, all functions accept numeric arguments in the range (-251,+251)

1 Like

You can do that with ro-typescript for question 1. For 2 it shows that the bit32 library will absolute your input causes your binary thing looks like this 10000000 and when you right shift it in lua you get essentially a really high number (2^32-1). For javascript, it’s probably cause it uses left shift if the input is negative cause it makes no sense to shift bits by a negative number. right shift and left shift actually just execute a couple bitmasks and AND operations

2 Likes

To make this work as a left shift, would all you need to do is change bit32.rshift to bit32.lshift?

you should just try it and see

2 Likes
local function alshift(x: number, disp: number): number
    local y = bit32.lshift(x, disp)
    
    if y >= 2 ^ 31 then
        return y - 2 ^ 32
    end
    
    return y
end

local function arshift(x: number, disp: number): number
    local y = bit32.rshift(x, disp)
    
    if y >= 2 ^ 15 then
        return y - 2 ^ 16
    end
    
    return y
end
1 Like