Other Get shifted bits from Bit.ShiftLeft (overflow)

OliverA

Expert
Licensed User
Longtime User
Maybe this? I don't know if this classifies as "elegant" though:
B4X:
    'For byte values. See notes to adapt for short values.
    'When left shifting
    Dim a As Byte = 255
    Dim bits2shift As Int = 5
    'Create a bitmask used to determine what bits are shifted out to the left
    'For Short, you'll have to use 16 instead of 8 and 0xffff instead of 0xff
    Dim shiftLeftMask As Int = Bit.And(Bit.Not(Power(2, 8-bits2shift)-1), 0xff)
    'Extract bits that would be removed using the mask and some shifting. Use 16 for Short
    Dim bitsRemovedLeftShift As Byte = Bit.UnsignedShiftRight(Bit.And(a, shiftLeftMask), 8 - bits2shift)
    
    'When right shifting
    Dim shiftRightMask As Int = Power(2, bits2shift) - 1
    'For shorts, use 0xffff
    Dim bitsRemovedRightShift As Byte = Bit.And(Bit.And(a, 0xff), shiftRightMask)

    Log(bitsRemovedLeftShift)
    Log(bitsRemovedRightShift)
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
(Using Power is not very elegant when you work with bits.)

I'm not 100% sure that I understood the question.

B4X:
Sub AppStart (Args() As String)
    Dim input As Int = Bit.ParseInt("11010101", 2) 'same as writing input = 213
    Dim output As Int = GetOverflowBits(input, 3)
    Log(Bit.ToBinaryString(output))
End Sub

Sub GetOverflowBits (N As Int, Shift As Int) As Int
    Return Bit.UnsignedShiftRight(Bit.And(0xff, N), 8 - Shift)
End Sub

The output is 110
 
Upvote 0

emexes

Expert
Licensed User
Return Bit.UnsignedShiftRight(Bit.And(0xff, N), 8 - Shift)
Great for Bytes. I think Oliver's adjustment works for both sets of code. Not sure why Ints don't rate a mention (but I think Bit.And wouldn't be necessary then anyway).
'For byte values. See notes to adapt for short values.
'For Short, you'll have to use 16 instead of 8 and 0xffff instead of 0xff
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
I'm not 100% sure that I understood the question

Exactly what I meant. Base32 encoding packs 5 bits to a single block. So it's quite easy to shift 5 bits to the left to get a block. Of course we could get the binary value as a string and get 5 chars ("bits") out of it.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Using Power is not very elegant when you work with bits.
Believe it or, I realized that as soon as I went to bed. That’s what I get when I work on too many things at the same time. Usually at night I get the “that was dumb” realization
Not sure why Ints don't rate a mention
Because of the sign issue with Java. I was too lazy to test Int’s. Byte’s and Short’s sign issue can be handled by converting them to Int’s.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Ok, one more try. As @Erel pointed out in his solution, when determining overflow bits for a left shift, all one has to do is a right shift. As to determine the overflow of a right shift, a mask is created and ANDed to the original value (and no, I'm not using Power this time around). And Ints work, but it is imperative that for the right shifting the Bit.UnsignedShiftRight method is used. For Bytes and Shorts, this is optional (one could just stick with UnsignedShiftRight, but in the examples below I use Bit.ShiftRight for Bytes and Shorts).

Notes:
1) Bit.ParseInt cannot handle 32 1/0 combos for generating an Int. The max number allowed to use is 31, otherwise a NumberFormat exception is thrown (in my example, the error was: "java.lang.NumberFormatException: For input string: "11010111110101111101011111010111"
2) For those curious about the 0xFF masking for Bytes and 0xFFFF masking for shorts, that is necessary since in B4X, no unsigned versions exist for Bytes and Shorts. Neither does for Ints, but at that point, no such additional masking is necessary

B4X:
    Dim inputByte As Byte = Bit.ParseInt("11010111", 2)
    Dim inputShort As Short = Bit.ParseInt("1101011111010111", 2)
    Dim inputInt As Int = Bit.ParseInt("11010111110101111101011111010111", 2)
    'NOTE: The above bomb's out. Looks like we cannot set the complete 32 bits of an Int
    Dim inputInt As Int = 0xD7D7D7D7
    
    Log(inputByte)
    Log(inputShort)
    Log(inputInt)
    
    Dim byteShiftAmount As Int = 5
    Dim shortShiftAmount As Int = 13
    Dim intShiftAmount As Int = 29
    
    'Determine overflow bits from a left shift. Just do a right shift!
    Log("Left shifting:")
    Log("Byte:")
    Dim overFlowByte As Byte =    Bit.ShiftRight(Bit.And(inputByte, 0xFF), 8 - byteShiftAmount)
    Log($"overflow for ${inputByte} shifted ${byteShiftAmount} to the left = ${overFlowByte}"$)
    Log($"overflow for ${Bit.ToBinaryString(Bit.And(inputByte, 0xFF))} shifted ${byteShiftAmount} to the left = ${Bit.ToBinaryString(Bit.And(overFlowByte, 0xFF))}"$)
    Log("Short:")
    Dim overFlowShort As Short = Bit.ShiftRight(Bit.And(inputShort, 0xFFFF), 16 - shortShiftAmount)
    Log($"overflow for ${inputShort} shifted ${shortShiftAmount} to the left = ${overFlowShort}"$)
    Log($"overflow for ${Bit.ToBinaryString(Bit.And(inputShort, 0xFFFF))} shifted ${shortShiftAmount} to the left = ${Bit.ToBinaryString(Bit.And(overFlowShort, 0xFFFF))}"$)
    Log("Int:")
    Dim overFlowInt As Int = Bit.UnsignedShiftRight(inputInt, 32 - intShiftAmount)
    Log($"overflow for ${inputInt} shifted ${intShiftAmount} to the left = ${overFlowInt}"$)
    Log($"overflow for ${Bit.ToBinaryString(inputInt)} shifted ${intShiftAmount} to the left = ${Bit.ToBinaryString(overFlowInt)}"$)
    
    'Determine overflow from a right shift. Do it by creating a mask ((1 << shiftAmount) - 1) and ANDing it with the original value
    Log("Right shifting:")
    Log("Byte:")
    overFlowByte =    Bit.And(Bit.And(inputByte, 0xFF), Bit.ShiftLeft(1, byteShiftAmount) - 1)
    Log($"overflow for ${inputByte} shifted ${byteShiftAmount} to the right = ${overFlowByte}"$)
    Log($"overflow for ${Bit.ToBinaryString(Bit.And(inputByte, 0xFF))} shifted ${byteShiftAmount} to the right = ${Bit.ToBinaryString(Bit.And(overFlowByte, 0xFF))}"$)
    Log("Short:")
    overFlowShort = Bit.And(Bit.And(inputShort, 0xFFFF), Bit.ShiftLeft(1, shortShiftAmount) - 1)
    Log($"overflow for Short ${inputShort} shifted ${shortShiftAmount} to the right = ${overFlowShort}"$)
    Log($"overflow for Short ${Bit.ToBinaryString(Bit.And(inputShort, 0xFFFF))} shifted ${shortShiftAmount} to the right = ${Bit.ToBinaryString(Bit.And(overFlowShort, 0xFFFF))}"$)
    Log("Int:")
    Dim overFlowInt As Int = Bit.And(inputInt, Bit.ShiftLeft(1, intShiftAmount) - 1)
    Log($"overflow for Int ${inputInt} shifted ${intShiftAmount} to the right = ${overFlowInt}"$)
    Log($"overflow for Int ${Bit.ToBinaryString(inputInt)} shifted ${shortShiftAmount} to the right = ${Bit.ToBinaryString(overFlowInt)}"$)vvv
 
Upvote 0
Top