Circular rotate: Issue with rotate left - java

In below code, where and what exactly I am doing wrong? I am getting unexpected values when rotating data back to left. What is the fix for this?
public class RotateExample {
public static byte rotateRight(byte bits, int shift) {
return (byte)((bits >>> shift) | (bits << (8 - shift)));
}
public static byte rotateLeft(byte bits, int shift) {
return (byte)((bits << shift) | (bits >>> (8 - shift)));
}
public static void main(String[] args) {
//test 1 failed
byte a = (byte)1;
byte b = rotateRight(a,1);
byte c = rotateLeft(b,1);
System.out.println(a+" "+b+" "+c);
//test 2 passed
a = (byte)1;
b = rotateRight(a,2);
c = rotateLeft(b,2);
System.out.println(a+" "+b+" "+c);
//test 3 failed
a = (byte)2;
b = rotateRight(a,2);
c = rotateLeft(b,2);
System.out.println(a+" "+b+" "+c);
//test 4 passed
a = (byte)2;
b = rotateRight(a,3);
c = rotateLeft(b,3);
System.out.println(a+" "+b+" "+c);
}
}

The following works.
public static byte rotateRight(byte bits, int shift)
{
return (byte)(((bits & 0xff) >>> shift) | ((bits & 0xff) << (8 - shift)));
}
public static byte rotateLeft(byte bits, int shift)
{
return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (8 - shift)));
}
Refer to this question. Behaviour of unsigned right shift applied to byte variable
This happens because the bytes are converted to signed int before the shift operations takes place.

The current answer didn't work for me, and I realized it's because the righthand side of the operator should be shifting by the size of an Integer (32) rather than 8. This is because the byte is promoted to an Integer prior to any shifting operations taking place on it. Here is my solution:
/**
* Performs a circular bitwise rotation on a byte, rotating right by shift positions.
*
* #param bits the byte to rotate
* #param shift the number of positions to rotate by
* #return the rotated byte
*/
private static byte rotateRight(byte bits, int shift) {
return (byte) (((bits & 0xff) >>> shift) | ((bits & 0xff) << (Integer.SIZE - shift)));
}
/**
* Performs a circular bitwise rotation on a byte, rotating left by shift positions.
*
* #param bits the byte to rotate
* #param shift the number of positions to rotate by
* #return the rotated byte
*/
private static byte rotateLeft(byte bits, int shift)
{
return (byte)(((bits & 0xff) << shift) | ((bits & 0xff) >>> (Integer.SIZE - shift)));
}
It's an old thread, but hopefully someone can find this answer useful!

Related

Shift byte value into int

I am attempting to store a single byte value into a position within an int, however, I am having trouble figuring out how this would be done.
I have shifted the byte that i want to store in the int to the correct value, but I am at a loss as to how i then combine this with the value.
public static int ibyteToInt(int b, int pos, int val)
{
return ((b & 0xff) << (8 * pos)) ??;
}
The simplest solution would be to unpack the 3 other bytes from the int and then recombine the 4 bytes into an int but of course this would not be very performant.
public static int bytesToInt(byte a, byte b, byte c, byte d)
{
return ((a & 0xff) << 0) | ((b & 0xff) << 8) | ((c & 0xff) << 16) | ((d & 0xff) << 24);
}
An other simple solution is clearing out the target byte, then OR-ing in the new value:
int replaceByte(int value, byte b, int pos)
{
return (value & ~(0xFF << (pos * 8))) | ((b & 0xFF) << (pos * 8));
}
This is very similar to how to do the same thing in C#, but Java requires & 0xFF to prevent sign-extension of the byte. If the "byte" is a value between 0 and 255 and passed in as an int, that step is not required.

Java byte Array to signed Int

I'm trying to convert a signed int variable to a 3 byte array and backwards.
In the the function getColorint, I'm converting the int value to the byte array. That works fine!
public byte [] getColorByte(int color1){
byte[] color = new byte[3];
color[2] = (byte) (color1 & 0xFF);
color[1] = (byte) ((color1 >> 8) & 0xFF);
color[0] = (byte) ((color1 >> 16) & 0xFF);
return color;
}
But if I try to convert the byte array back to the Integer with the getColorint function:
public int getColorint(byte [] color){
int answer = color [2];
answer += color [1] << 8;
answer += color [0] << 16;
return answer;
}
it only works for positive integer values.
Here is a screenshot during the debug:
My input int value is -16673281 but my output int value is 38143.
Can anyone help me?
Thanks :)
The Color class defines methods for creating and converting color ints. Colors are represented as packed ints, made up of 4 bytes: alpha, red, green, blue.
You should use it.
The problem here is that byte is signed. When you do int answer = color[2] with color[2] == -1, then answer will be also -1, i.e. 0xffffffff, whereas you want it to be 255 (0xff). You can use Guava 's UnsignedBytes as a remedy, or simply take color[i] & 0xff which casts it to int.
As is Color represents in 4 bytes, you should store also an alpha channel.
From Int :
public byte [] getColorByte(int color1){
byte[] color = new byte[4];
for (int i = 0; i < 4; i++) {
color [i] = (byte)(color1 >>> (i * 8));
}
return color;
}
To Int :
public int getColorInt(byte [] color){
int res = ((color[0] & 0xff) << 24) | ((color[1] & 0xff) << 16) |
((color[2] & 0xff) << 8) | (color[3] & 0xff);
return res;
}

Java: custom to byte conversions

I am working with some low capacity module and I need to compress the data as much as possible. The data will look like this:
DeviceEvent:
1 byte:
2 bits for status (00 each time)
6 bits for rgb color (3 x 2 bits)
2 bytes: number of minutes from now to a certain datetime
I need to create a constructor (preferably 2 constructors) for conversion from/to:
Event:
byte[] color (rgb, colors will get simplified to only 64 available)
some datetime (but I will get the integer for difference in minutes and it will be small enough to fit in two bits)
So basically I need:
byte[3] color <-> 1 byte status and color
int minutes <-> byte[2]
minutes
I will be thankful for any help
I'm not very sure what is your problem, probably this will help:
final byte red = 1; // 01 binary
final byte green = 2; // 10 binary
final byte blue = 3; // 11 binary
final byte finalColor = (byte) ((red & 0x3) << 4) | ((green & 0x3) << 2) | (blue & 0x3);
System.out.println(finalColor);// finalColor is 011011 = 27 decimal
final int minutes = 0x1234; // first byte is 0x12, second byte is 0x34
final byte[] bytes = {(byte) (((minutes) >>> 8) & 0xff), (byte) (minutes & 0xff)};
System.out.println(bytes[0]); // 0x12 = 18 decimal
System.out.println(bytes[1]); // 0x34 = 52 decimal
I am not sure what the second problem is. So I made these two functions that might help you:
public static int convertToInt(int a, int b, int c, int d) {
a = Math.min(a, 255);
b = Math.min(b, 255);
c = Math.min(c, 255);
d = Math.min(d, 255);
return ((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF);
}
public static int[] extractComponents(int data) {
int a = (data >> 24) & 0xFF;
int b = (data >> 16) & 0xFF;
int c = (data >> 8) & 0xFF;
int d = data & 0xFF;
return new int[] {a, b, c, d};
}
The convertToInt function takes four numbers(that are less than 255) and puts them all in one int.
The extractComponents function does the opposite.
This is an example:
int data = 0xC8E0601B;
int[] dataA = extractComponents(data);
for(int i = 0 ; i < dataA.length; i++) System.out.printf("%x\n", dataA[i]);
System.out.printf("%x\n", convertToInt(dataA[0], dataA[1], dataA[2], dataA[3]));

Converting Byte[4] to float - Integer[4] array works but byte[4] does not

This is probably a basic question for out more experienced programmers out there. I'm a bit of a noob and can't work this one out. I'm trying to unpack a binary file and the doco is not too clear on how floats are stored. I have found a routine that does this, but it will only work if I pass an integer array of the bytes. The correct answer is -1865.0. I need to be able to pass the byte array and get the correct answer. How do I need to change the code to make float4byte return -1865.0. Thanks in advance.
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class HelloWorld {
public static void main(String[] args) {
byte[] bytes = {(byte) 0xC3,(byte) 0X74,(byte) 0X90,(byte) 0X00 };
int[] ints = {(int) 0xC3,(int) 0X74,(int) 0X90,(int) 0X00 };
// This give the wrong answer
float f = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getFloat();
System.out.println("VAL ByteBuffer BI: " + f);
// This give the wrong answer
f = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getFloat();
System.out.println("VAL ByteBuffer LI: " + f);
//This gives the RIGHT answer
f = float4int (ints[0], ints[1], ints[2], ints[3]);
System.out.println("VAL Integer : " + f);
// This gives the wrong answer
f = float4byte (bytes[0], bytes[1], bytes[2], bytes[3]);
System.out.println("VAL Bytes : " + f);
}
private static float float4int(int a, int b, int c, int d)
{
int sgn, mant, exp;
System.out.println ("IN Int: "+String.format("%02X ", a)+
String.format("%02X ", b)+String.format("%02X ", c)+String.format("%02X ", d));
mant = b << 16 | c << 8 | d;
if (mant == 0) return 0.0f;
sgn = -(((a & 128) >> 6) - 1);
exp = (a & 127) - 64;
return (float) (sgn * Math.pow(16.0, exp - 6) * mant);
}
private static float float4byte(byte a, byte b, byte c, byte d)
{
int sgn, mant, exp;
System.out.println ("IN Byte : "+String.format("%02X ", a)+
String.format("%02X ", b)+String.format("%02X ", c)+String.format("%02X ", d));
mant = b << 16 | c << 8 | d;
if (mant == 0) return 0.0f;
sgn = -(((a & 128) >> 6) - 1);
exp = (a & 127) - 64;
return (float) (sgn * Math.pow(16.0, exp - 6) * mant);
}
}
The reason why your solution with ByteBuffer doesn't work: the bytes do not match the (Java) internal representation of the float value.
The Java representation is
System.out.println(Integer.toHexString(Float.floatToIntBits(-1865.0f)));
which gives c4e92000
bytes are signed in Java. When calculating the mantissa mant, the bytes are implicitly converted from bytes to ints - with the sign "extended", i.e. (byte)0x90 (decimal -112) gets converted 0xFFFFFF90 (32 bits int). However what you want is just the original bytes' 8 bits (0x00000090).
In order to compensate for the effect of sign extension, it suffices to change one line:
mant = (b & 0xFF) << 16 | (c & 0xFF) << 8 | (d & 0xFF)
Here, in (c & 0xFF), the 1-bits caused by sign extension are stripped after (implicit) conversion to int.
Edit:
The repacking of floats could be done via the IEEE 754 representation which can be obtained by Float.floatToIntBits (which avoids using slow logarithms). Some complexity in the code is caused by the change of base from 2 to 16:
private static byte[] byte4float(float f) {
assert !Float.isNaN(f);
// see also JavaDoc of Float.intBitsToFloat(int)
int bits = Float.floatToIntBits(f);
int s = (bits >> 31) == 0 ? 1 : -1;
int e = (bits >> 23) & 0xFF;
int m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits& 0x7FFFFF) | 0x800000;
int exp = (e - 150) / 4 + 6;
int mant;
int mantissaShift = (e - 150) % 4; // compensate for base 16
if (mantissaShift >= 0) mant = m << mantissaShift;
else { mant = m << (mantissaShift + 4); exp--; }
if (mant > 0xFFFFFFF) { mant >>= 4; exp++; } // loose of precision
byte a = (byte) ((1 - s) << 6 | (exp + 64));
return new byte[]{ a, (byte) (mant >> 16), (byte) (mant >> 8), (byte) mant };
}
The code does not take into account any rules that may exist for the packaging, e.g. for representing zero or normalization of the mantissa. But it might serve as a starting point.
Thanks to #halfbit and a bit of testing and minor changes, this routine appears convert IEEE 754 float into IBM float.
public static byte[] byte4float(float f) {
assert !Float.isNaN(f);
// see also JavaDoc of Float.intBitsToFloat(int)
int bits = Float.floatToIntBits(f);
int s = (bits >> 31) == 0 ? 1 : -1;
int e = (bits >> 23) & 0xFF;
int m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits& 0x7FFFFF) | 0x800000;
int exp = (e - 150) / 4 + 6;
int mant;
int mantissaShift = (e - 150) % 4; // compensate for base 16
if (mantissaShift >= 0) mant = m >> mantissaShift;
else mant = m >> (Math.abs(mantissaShift));
if (mant > 0xFFFFFFF) { mant >>= 4; exp++; } // loose of precision */
byte a = (byte) ((1 - s) << 6 | (exp + 64));
return new byte[]{ a, (byte) (mant >> 16), (byte) (mant >> 8), (byte) mant };
}
I think this is right and appears to be working.

Java IEEE 754 float to IBM float byte[4] conversion

I'm dealing with a packed binary data file that I am trying to decode, modify and recode. I need to be able to repack float values in the same way that they were unpacked. The float value in this sample code is -1865.0. What do I need to do in byte4float so that the four bytes returned are the same as I started, ie (C3 74 90 00 ).
public class HelloWorld {
public static void main(String[] args) {
byte[] bytes = {(byte) 0xC3,(byte) 0X74,(byte) 0X90,(byte) 0X00 };
byte newbytes[] = new byte[4];
float f;
f = float4byte (bytes[0], bytes[1], bytes[2], bytes[3]);
System.out.println("VAL Bytes : " + f);
// Now see if we can reverse it
// NOT Working
newbytes = byte4float(f);
System.out.println ("TO Bytes: "+String.format("%02X ", newbytes[0])+
String.format("%02X ", newbytes[1])+String.format("%02X ", newbytes[2])+String.format("%02X ", newbytes[3]));
}
/**
* Convert four bytes into a float value. Byte parameters
*
* #param a highest byte
* #param b higher byte
* #param c lower byte
* #param d lowest byte
*
* #return float value
*/
private static float float4byte(byte a, byte b, byte c, byte d)
{
int sgn, mant, exp;
System.out.println ("IN Byte : "+String.format("%02X ", a)+
String.format("%02X ", b)+String.format("%02X ", c)+String.format("%02X ", d));
mant = ( b &0xFF) << 16 | (c & 0xFF ) << 8 | ( d & 0xFF);
if (mant == 0) return 0.0f;
sgn = -(((a & 128) >> 6) - 1);
exp = (a & 127) - 64;
return (float) (sgn * Math.pow(16.0, exp - 6) * mant);
}
/**
* Convert float value into a four bytes.
*
* #param f float value to convert
*
* #return byte[0] highest byte, byte[1] higher byte, byte[2] lower byte, byte[3] lowest byte
*/
private static byte[] byte4float(float f)
{
byte newbytes[] = new byte[4];
int bits = Float.floatToIntBits(f);
newbytes[0] = (byte)(bits & 0xff);
newbytes[1] = (byte)((bits >> 8) & 0xff);
newbytes[2] = (byte)((bits >> 16) & 0xff);
newbytes[3] = (byte)((bits >> 24) & 0xff);
return newbytes;
}
}
The fact that your mantisse is 24 bit and exponent is 7 bits indicates that you are dealing with IBM style single precision floating points. I had some trouble figuring out why float4byte does sgn * Math.pow(16.0, exp - 6) * mant, when I realized that simply is the same as sgn * Math.pow(16, exp) * (mant / Math.pow(2, 24), which is exactly the way IBM floats work.
What you are encoding are common IEEE-754 single precision floating points. The mis-match is causing the trouble.
On the IBM floating point architecture wikipedia article you can find an example of how to encode a floating point number to IBM float bytes.
Thanks to #halfbit input, and some minor changes, this routine will convert IEEE 754 float to IBM float.
public static byte[] byte4float(float f) {
assert !Float.isNaN(f);
// see also JavaDoc of Float.intBitsToFloat(int)
int bits = Float.floatToIntBits(f);
int s = (bits >> 31) == 0 ? 1 : -1;
int e = (bits >> 23) & 0xFF;
int m = (e == 0) ? (bits & 0x7FFFFF) << 1 : (bits& 0x7FFFFF) | 0x800000;
int exp = (e - 150) / 4 + 6;
int mant;
int mantissaShift = (e - 150) % 4; // compensate for base 16
if (mantissaShift >= 0) mant = m >> mantissaShift;
else mant = m >> (Math.abs(mantissaShift));
if (mant > 0xFFFFFFF) { mant >>= 4; exp++; } // loose of precision */
byte a = (byte) ((1 - s) << 6 | (exp + 64));
return new byte[]{ a, (byte) (mant >> 16), (byte) (mant >> 8), (byte) mant };
}
I think this is right and appears to be working.

Categories

Resources