Altering specific bits of a 32-bit integer in Java - java

Background: I have a 32-bit integer with a binary representation like so:
1111 1111 0000 0000 0000 0000 1111 1111
Note: This is the binary representation of the ARGB value of Color.BLUE. I'm using this for illustration purposes, but it is relevant to a situation I am attempting to solve.
The Problem: I am attempting to alter the high order bits so that its binary representation looks like this:
1000 0000 0000 0000 0000 0000 1111 1111
Or more simply, the first eight high order bits should be changed like so:
1111 1111 -> 1000 0000
Current Solution Attempt: Thus far, I've been successful by masking out the first eight high order bits, and then "adding" the desired value using bitwise "or", like so:
int colourBlue = Color.BLUE.getRGB(); // equal to binary value at top of question
int desiredAlpha = (0x80 << 24); // equal to 1000 0000 0000 0000 0000 0000 0000 0000
// Mask out the eight high order bits, and add in the desired alpha value
int alteredAlphaValue = (colourBlue & 0x00FFFFFF) | desiredAlpha;
While this does presently work, admittedly it has been some time since my computer architecture classes, and I have not had a lot of experience yet working with bitwise operators and lower level bit manipulation.
My question: Is my solution the correct way to accomplish this task? If it is in some way improper (or just plain "dumb"), what is a better (or correct) way to achieve the goal of altering specific bits?

Transcoded from C# to Java (untested):
public static int setBits(int orig, int newBits, int startBit, int length)
{
int mask = Mask(startBit, length);
return (orig & ~mask) | (bits << startBit & mask);
}
public int Mask(int startBit, int length)
{
if (length ==32)
return Integer.MAX_VALUE;
else
return (1 << (1 << length) - 1) << startbit;
}
Or, if you prefer, you can just specify the mask directly, and avoid the bit-shifting:
public static int setBits(int orig, int newBits, int mask)
{
return (orig & ~mask) | (bits & mask);
}
Of course, if you're being handed the RGB value as a 32 bit number, you could always convert it to a byte array and vice versa, which makes the manipulations much easier.

Related

Java: byte[] bit shift operation into short

I have a byte array of size 4096. I fill field 0 with 0xA2 and field 1 with 0xF0.
My goal is to shift field 0 by 8 bits to the left, then do an OR-operation with field 1 and store it into a short variable.
The result on paper should be:
1010 0010 (0xA2)
>>shift left by 8 bits
1010 0010 0000 (0xA20)
>>OR-operation with field 1
1010 0010 0000 (0xA20)(field 0)
1111 0000 (0xF0)(field 1)
----------------------
1010 1111 0010 (0xAF2)
There was already a similar post but it only helped a little.
Even though I'm casting it seems to cut off the shifted bits.
Here's the code.
public static void main(String[] args) {
byte[] myMem = new byte[4096];
myMem[0] = (byte)0xA2;
myMem[1] = (byte)0xF0;
short test = (short)(myMem[0] << 8 | myMem[1]);
}
Debugger shows following values:
myMem[0] = -94 (which is correctly 0xA2)
myMem[1] = -16 (which is correctly 0xF0)
test = -16 (which is wrong, 0x00A2. Should be -23824 or 0xA2F0).
Somewhere I made a logical mistake I suppose, I can't find it though.
use
short test = (short)((myMem[0] << 8) | ((myMem[1])& 0xff));

How to get a 14 bit, two's complement value into an Integer or Short and maintain the sign in Java

I have a 14 bit, two's complement value being sent to my java application form a bluetooth device in the form of a byte array.
I am unable to change the format of the data sent from the bluetooth device.
How do I get this value into an Integer or Short and maintain the sign?
A few things I have tried are
Short x = ByteBuffer.wrap(value).getShort();
Integer x = (short)(value[3] & 0xff) | (short)((value[2] << 8) & 0xff00);
The problem I think I encounter with the above code is when I receive a negative number, for example
-8192 (in two's complement 10 0000 0000 0000)
Because the receiving data type is 16 bits it expects the bit that negates the value to be 16 along but seen as what it actually receives is
0010 0000 0000 0000
It considers this 8192 and not -8192.
Simply extract the number from the byte array, ignoring signedness and excess bits completely:
byte[] data = ...
int rawNum = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
Now left shift the raw value by (type size - number of valid bits) then right shift using the signed shift operator
int realNum = (rawNum << (32 - 14)) >> (32 - 14);
This will first move the sign bit into the sign bit of the type storing the value (here: int) by shifting left, then when right shifting the sign bit is replicated shift-distance times (as defined by the shift operator).
I've generated a small example that uses integers, It should be easy to put the short you've retrieved in the integer. I've shown an example using your value variable just to be sure.
/**
* Expects the value to contain a 2-complement number stored in the
* least significant bits.
* The contents of the most significant bits is ignored.
* #param value the value to convert
* #param bitSize the size of the 2 complement number in the value
* #return the converted value
*/
public static int fromTwoComplement(int value, int bitSize) {
int shift = Integer.SIZE - bitSize;
// shift sign into position
int result = value << shift;
// Java right shift uses sign extension, but only works on integers or longs
result = result >> shift;
return result;
}
public static void main(String[] args) {
System.out.println(fromTwoComplement(0b00_00_0000_0000_0001, 14));
System.out.println(fromTwoComplement(0b00_01_1111_1111_1111, 14));
System.out.println(fromTwoComplement(0b00_10_0000_0000_0000, 14));
System.out.println(fromTwoComplement(0b00_11_1111_1111_1111, 14));
// largest negative
byte[] value = new byte[] { 0b0010_0000, 0b0000_0000 };
System.out.println(fromTwoComplement((int) ByteBuffer.wrap(value).getShort(), 14));
}
You should extend the most significant bit to the left.
Offhand: short y = (short)((x & 0b10000000000000 ) > 0 ? ( x | 0b1100000000000000 ) : x);
That is, if the most significant bit (for a 14 bit number) is 1, then the result of the & is going to be non-zero. If so, add the two additional ones to the left with an or. Otherwise leave as is.
public static void main(String[] args)
{
System.out.println((short) 0x1FFF);
// 0001 1111 1111 1111 - maximum positive value
System.out.println((short) 0x3FFF);
// 0011 1111 1111 1111 - minimum negative value
System.out.println((short) 0xF);
// 0000 0000 0000 1111 - positive 15
System.out.println((short) 0x3FF1);
// 0011 1111 1111 0001 - negative 15
System.out.println(convert14bit((short) 0x3FFF)); // returns -1
System.out.println(convert14bit((short) 0x3FF1)); // returns -15
}
public static final short convert14bit(short value)
{
if ((value & 0x2000) > 0)
{
// negative number
return (short) (value | 0xE000);
}
else
{
return value;
}
}

Java left shift and fill with Zeros

I want to do left shifting but filling with zero, just like
int number = 20 >>> 10 = ( 0000 0000 0000 0000 0000 0000 0001 0100 )
int number = 20 >>> 32‎ = ( 0000 0000 0000 0000 0000 0000 0000 0000 )
I want to do the same with left shift, since there is no operator <<< for leftshift
int number = 20 << 32 = 0000 0000 0000 0000 0000 0000 0001 0100 ;
I want to fill it with zeros just like >>> operator. So how I can do this?
The << left shift operator will bring in zeros just as you want to.
The reason why there are 2 right shift operators (>> and >>>) is because in 2's complement form negative numbers have a bit value of 1 in the left-most bit position. The right shift operator >> will add the sign bit (1 in case of negative numbers, and 0 in case of positive numbers or zero) on the left side while the other (>>>) will always add zeros.
Both right shift operators have their use.
The language specification states that if bit shifting operators are applied on int since it is 32-bit long, only the 5 lowest bit is used to determine how many times to shift the number.
So if you shift by 32 which is 100000 in binary, it is equivalent to shift by 0 which means not to shift! And if you want to shift a 64-bit long, the 6 lowest bit is used only to tell how many times to shift.
You need to use long type and only make use of lowest 32 bits.
Use and operator to accomplish that.
long intMask = 0x00000000FFFFFFFFL;
long x = 0x00000000FFFFFFFFL;
x = x<<32;
int xi = (int)(x & intMask);
System.out.println("xi=" + xi); //Result will be 0
See question : Declaring an unsigned int in Java

Changing a bit within a byte in java

So I understand how to change an individual bit within a byte, what I am not sure is why my particular code is not working.
public static void setBit(byte[] input, int position, int value) {
int byteLocation = position / 8;
int bitLocation = position % 8;
byte tempByte = input[byteLocation];
if (value == 0)
tempByte = (byte) (tempByte & ~(1 << bitLocation));
else
tempByte = (byte) (tempByte | (1 << bitLocation));
input[byteLocation] = tempByte;
}
Now I have been testing it with the string "Testing1" which is 64bits long, then attempting to set the bits and display the value. It works a treat up to 46 bits, then on the 47th bit if I attempt to set it to 1 it borks up, works fine with 0 however.
Can't see the error in my ways, here's how I am testing it
String test = "Testing1";
byte[] bytes = test.getBytes();
for (int i = 0; i < bytes.length; i++)
System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");
setBit(bytes, 44, 1);
System.out.println();
for (int i = 0; i < bytes.length; i++)
System.out.print(String.format("%8s", Integer.toBinaryString(bytes[i])).replace(' ', '0') + "[" + i + "] ");
The following is the output when I attempt to change the 47th bit to a 1
01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 01101110[5] 01100111[6] 00110001[7]
01010100[0] 01100101[1] 01110011[2] 01110100[3] 01101001[4] 11111111111111111111111111101110[5] 01100111[6] 00110001[7]
Change formatting as
Integer.toBinaryString(0xFF & bytes[i])
byte needs to be masked off because it is sign-extended, not zero-extended, to 32-bit int
The problem is you are setting the sign bit in the byte in question. So, that byte now has a negative value. You call Integer.toBinaryString(), which takes an int as it's argument, not a byte. The byte get promoted to an int, and it correctly evaluates the value of:
11101110
to it's equivalent integer:
11111111111111111111111111101110
I made your method smaller using ^ (xor)
public static void setBit(byte[] input, int position, int value) {
int byteLocation = position / 8;
int bitLocation = position % 8;
input[byteLocation] = (byte) (input[byteLocation] ^ (byte) (1 << bitLocation));
}
I haven't looked at it in too much detail but I think the problem with the one bite is that it's being extended to an int (Since it's signed, the 1 extends to a negative int).
Just take the last 8 characters of the string and it will work fine.
Ive recently had to do something like this.
I managed to achieve it through (a lot of use of the whiteboard but..) shifting the original bits right by the position of the LSB I wanted to replace and making all bits inclusive of the MSB I wanted to replace, 1's.
I then AND'ed the bits I want in place of the bits I want to replace, shifted left the same number I shifted right, OR'ing the result with the original and AND'ed by an XOR'ed mask of the replacement. (Take a breath, I'll try to explain)
Let's say I have the bytes:
1111 1010 0001 1001
and I want to replace the nibble 1010 with 0001 to produce:
1111 0001 0001 1001.
The operation I went through to achieve this is:
1) Shift right by 8 to produce:
0000 0000 1111 1010
2) OR a mask of 0xf (1111) to produce:
0000 0000 1111 1111
3) AND the replacement of 0001 with 0000 0000 1111 1111 to produce:
0000 0000 0000 0001
4) Shift left by 8 to produce:
0000 0001 0000 0000
5) Shift the mask by the LSB position and XOR with full bytes
1111 1111 1111 1111
0000 1111 0000 0000
==================
1111 0000 1111 1111
6) AND the XOR'ed, shifted mask with the original to produce:
1111 0000 0001 1001
1111 0000 1111 1111
==================
1111 0000 0001 1001
7) OR that result of the above with the replacement:
1111 0000 0001 1001
0000 0001 0000 0000
==================
1111 0001 0001 1001 << end result
==================
In java, this results in the function:
public long overwriteBits(long overwrite, long with, long shift, long mask)
{
return ((((overwrite >> shift) | mask) & with) << shift) | (overwrite & (~0 ^ (mask << shift)));
}
Where "overwrite" is the original data, "with" are the bits you want in place of the bits in position "shift" and mask is a a series of positive bits with the same length of the replacement.
To do the above I'd call (in sudo):
overwriteBits(1111101000011001, 0001, 8, 1111)
I want to mention that the above will work for replacing bits in any primitive, no need for byte arrays. e.g. Replacing 11 bits, as below:
1101001010101101 1111 0101 101 001101
with 1010 1010 101
overwriteBits(1101001010101101 1111 0101 101 001101, 1010 1010 101, 6, 11111111111)
1101001010101101 1111 0101 101 001101
1101001010101101 1010 1010 101 001101
overwriteBits(1789785421l, 1365l, 6, 0x7FF)

Writing a function: short GetBits(short data, int p, int n)

I am writing a function short getBits(short data, int p, int n)
I have tried:
public static short getBits(short data, int p, int n) {
short bitmask = (short) ((~0 << (16 -n)) >>> p);
short returnVal = (short) ((bitmask & data) >>> (16 - n));
return returnVal;
}
This works for getBits( (short) 0x7000, 0, 4) but if I were to replace the 7 with an 8 I get a negative value.
There are a few things to remember about java data types, to make this thing work.
I'm assuming you're using int variables because of the absence of explicit casts in your expression. If you're using an int type for your variables: data start_pos, and length; you should be using 32 instead of 16, since int's are 32-bit values.
Also if you're going to use integer primitive types like int, short or byte, remember that these primitive types are two's complement that are sign-extended, meaning that if you do a right shift on negative numbers like ~0 (evaluates to -1), ones will be appended on the higher order bit (sign bit) instead of zeroes.
For instance:
1111 1111 1111 1111 1111 1111 1111 1000
>>1
1111 1111 1111 1111 1111 1111 1111 1100
Now going back to your problem. The general idea is to be able to do a:
data & mask
Now, generating the mask is a bit tricky on signed data types. It would make sense to generate the mask using:
(~0 << (32 - length) >> (32 - length - start_pos))
But this won't work of course because of the sign extension.
I would suggest that instead of using right-shift >>, use rotate operator >>> that way instead of ones being appended on the higher order bit, the rotate operator will append the lower order bit.
For instance:
1111 1111 1111 1111 1111 1111 1111 1000
>>>1
0111 1111 1111 1111 1111 1111 1111 1100
so...
mask = (~0 << 32-length >>> 32-length-start_pos)
And your final answer would look something like:
(data & (~0 << 32-length >>> 32-length-start_pos)) >>> start_pos
The outermost rotate operation moves your masked data to the lower order bits.
Not sure why you need to use short. Here is a solution using long.
public static long getBits(long data, int p, int n) {
assert p >= 0 && p < 64;
assert n >= 0 && n < 64;
return (data >> p) & ((1 << n) - 1);
}

Categories