Converting two bytes into 16 bit signed number - java

I got two bytes:
byte[0] is 0000 0000
byte[1] is 1000 0000
I would like to put them together and make one float value of them. So the result should be 128 is decimal and 0000 0000 1000 0000 in binary. Not negative because of the leading zero.
My solution so far is this approach:
float f = (bytes[0] << 8 | bytes[1]);
But this will result in a value of minus 128 for value f. It's because of the 2s complement i guess. Therefore byte[1] will be interpreted as negative. How can I just see the leading bit of byte[0] as the bit for negative/positive?

Try this:
short int16 = (short)(((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF));
You need to use parenthesis because of operation precedence.
once you have your 16 bit integer, you can assign it to your float:
float f = int16;
yes, you could have done it in one step, but I wanted to go step by step.

Since you are performing some widening conversions, you have to stop the propagation of leading 1 bits due to the internal usage of two's complement:
byte[] bytes = {0, -128}; // bytes[0] = 0000 0000, bytes[1] = 1000 0000
short s = (short) (((bytes[0] & 0xFF) << 8) | (bytes[1] & 0xFF));
System.out.println(s); // prints 128
Also, float is for floating point numbers, since you want a 16 bit decimal number I changed the target datatype to short.

Related

Unsigned Right Shift operator works as the normal right-shift operator, why?

When I use the Unsigned Right Shift (Logical Shift) operator in java, I get the same result as the normal right-shift operator would give.
my code is:
byte b1 = -99; // 01100011
byte result = (byte) (b1 >>> 6);
String str = String.format("%8s", Integer.toBinaryString(result & 0xFF)).replace(' ', '0');
System.out.println("result: " + result);
The preceding code produces the same output which is -13 with both of >> and >>> operators, what is the reason behind that and how to resolve it?
First of all, byte is a signed type in Java, and bit shifting (whether normal or with sign extension) is done in int, so before performing the shift, the value of b1 is implicitly cast back to int (which preserves sign). (As an aside, the value -99 is not 01100011, it is 1001 1101 in byte and 1111 1111 1111 1111 1111 1111 1001 1101 in int).
With b >> 6 (or -99 >> 6), the value is -2 (1111 1111 1111 1111 1111 1111 1111 1110), with b >>> 6 (or -99 >>> 6) the value in int is 67108862 (0000 0011 1111 1111 1111 1111 1111 1110). However, when you then cast to byte, this last value becomes -2 as well (1111 1110).
What you need to do is make sure you get the unsigned value of the byte as the integer value before shifting:
byte result = (byte) ((b1 & 0xFF) >>> 6);
Which results in 2.

How does cast in java work? [duplicate]

int i =132;
byte b =(byte)i; System.out.println(b);
Mindboggling. Why is the output -124?
In Java, an int is 32 bits. A byte is 8 bits .
Most primitive types in Java are signed, and byte, short, int, and long are encoded in two's complement. (The char type is unsigned, and the concept of a sign is not applicable to boolean.)
In this number scheme the most significant bit specifies the sign of the number. If more bits are needed, the most significant bit ("MSB") is simply copied to the new MSB.
So if you have byte 255: 11111111
and you want to represent it as an int (32 bits) you simply copy the 1 to the left 24 times.
Now, one way to read a negative two's complement number is to start with the least significant bit, move left until you find the first 1, then invert every bit afterwards. The resulting number is the positive version of that number
For example: 11111111 goes to 00000001 = -1. This is what Java will display as the value.
What you probably want to do is know the unsigned value of the byte.
You can accomplish this with a bitmask that deletes everything but the least significant 8 bits. (0xff)
So:
byte signedByte = -1;
int unsignedByte = signedByte & (0xff);
System.out.println("Signed: " + signedByte + " Unsigned: " + unsignedByte);
Would print out: "Signed: -1 Unsigned: 255"
What's actually happening here?
We are using bitwise AND to mask all of the extraneous sign bits (the 1's to the left of the least significant 8 bits.)
When an int is converted into a byte, Java chops-off the left-most 24 bits
1111111111111111111111111010101
&
0000000000000000000000001111111
=
0000000000000000000000001010101
Since the 32nd bit is now the sign bit instead of the 8th bit (and we set the sign bit to 0 which is positive), the original 8 bits from the byte are read by Java as a positive value.
132 in digits (base 10) is 1000_0100 in bits (base 2) and Java stores int in 32 bits:
0000_0000_0000_0000_0000_0000_1000_0100
Algorithm for int-to-byte is left-truncate; Algorithm for System.out.println is two's-complement (Two's-complement is if leftmost bit is 1, interpret as negative one's-complement (invert bits) minus-one.); Thus System.out.println(int-to-byte( )) is:
interpret-as( if-leftmost-bit-is-1[ negative(invert-bits(minus-one(] left-truncate(0000_0000_0000_0000_0000_0000_1000_0100) [)))] )
=interpret-as( if-leftmost-bit-is-1[ negative(invert-bits(minus-one(] 1000_0100 [)))] )
=interpret-as(negative(invert-bits(minus-one(1000_0100))))
=interpret-as(negative(invert-bits(1000_0011)))
=interpret-as(negative(0111_1100))
=interpret-as(negative(124))
=interpret-as(-124)
=-124 Tada!!!
byte in Java is signed, so it has a range -2^7 to 2^7-1 - ie, -128 to 127.
Since 132 is above 127, you end up wrapping around to 132-256=-124. That is, essentially 256 (2^8) is added or subtracted until it falls into range.
For more information, you may want to read up on two's complement.
132 is outside the range of a byte which is -128 to 127 (Byte.MIN_VALUE to Byte.MAX_VALUE)
Instead the top bit of the 8-bit value is treated as the signed which indicates it is negative in this case. So the number is 132 - 256 = -124.
here is a very mechanical method without the distracting theories:
Convert the number into binary representation (use a calculator ok?)
Only copy the rightmost 8 bits (LSB) and discard the rest.
From the result of step#2, if the leftmost bit is 0, then use a calculator to convert the number to decimal. This is your answer.
Else (if the leftmost bit is 1) your answer is negative. Leave all rightmost zeros and the first non-zero bit unchanged. And reversed the rest, that is, replace 1's by 0's and 0's by 1's. Then use a calculator to convert to decimal and append a negative sign to indicate the value is negative.
This more practical method is in accordance to the much theoretical answers above. So, those still reading those Java books saying to use modulo, this is definitely wrong since the 4 steps I outlined above is definitely not a modulo operation.
Two's complement Equation:
In Java, byte (N=8) and int (N=32) are represented by the 2s-complement shown above.
From the equation, a7 is negative for byte but positive for int.
coef: a7 a6 a5 a4 a3 a2 a1 a0
Binary: 1 0 0 0 0 1 0 0
----------------------------------------------
int: 128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 = 132
byte: -128 + 0 + 0 + 0 + 0 + 4 + 0 + 0 = -124
often in books you will find the explanation of casting from int to byte as being performed by modulus division. this is not strictly correct as shown below
what actually happens is the 24 most significant bits from the binary value of the int number are discarded leaving confusion if the remaining leftmost bit is set which designates the number as negative
public class castingsample{
public static void main(String args[]){
int i;
byte y;
i = 1024;
for(i = 1024; i > 0; i-- ){
y = (byte)i;
System.out.print(i + " mod 128 = " + i%128 + " also ");
System.out.println(i + " cast to byte " + " = " + y);
}
}
}
A quick algorithm that simulates the way that it work is the following:
public int toByte(int number) {
int tmp = number & 0xff
return (tmp & 0x80) == 0 ? tmp : tmp - 256;
}
How this work ? Look to daixtr answer. A implementation of exact algorithm discribed in his answer is the following:
public static int toByte(int number) {
int tmp = number & 0xff;
if ((tmp & 0x80) == 0x80) {
int bit = 1;
int mask = 0;
for(;;) {
mask |= bit;
if ((tmp & bit) == 0) {
bit <<=1;
continue;
}
int left = tmp & (~mask);
int right = tmp & mask;
left = ~left;
left &= (~mask);
tmp = left | right;
tmp = -(tmp & 0xff);
break;
}
}
return tmp;
}
If you want to understand this mathematically, like how this works
so basically numbers b/w -128 to 127 will be written same as their decimal value, above that its (your number - 256).
eg. 132, the answer will be
132 - 256 = - 124
i.e.
256 + your answer in the number
256 + (-124) is 132
Another Example
double a = 295.04;
int b = 300;
byte c = (byte) a;
byte d = (byte) b; System.out.println(c + " " + d);
the Output will be 39 44
(295 - 256) (300 - 256)
NOTE: it won't consider numbers after the decimal.
Conceptually, repeated subtractions of 256 are made to your number, until it is in the range -128 to +127. So in your case, you start with 132, then end up with -124 in one step.
Computationally, this corresponds to extracting the 8 least significant bits from your original number. (And note that the most significant bit of these 8 becomes the sign bit.)
Note that in other languages this behaviour is not defined (e.g. C and C++).
In java int takes 4 bytes=4x8=32 bits
byte = 8 bits range=-128 to 127
converting 'int' into 'byte' is like fitting big object into small box
if sign in -ve takes 2's complement
example 1: let number be 130
step 1:130 interms of bits =1000 0010
step 2:condider 1st 7 bits and 8th bit is sign(1=-ve and =+ve)
step 3:convert 1st 7 bits to 2's compliment
000 0010
-------------
111 1101
add 1
-------------
111 1110 =126
step 4:8th bit is "1" hence the sign is -ve
step 5:byte of 130=-126
Example2: let number be 500
step 1:500 interms of bits 0001 1111 0100
step 2:consider 1st 7 bits =111 0100
step 3: the remained bits are '11' gives -ve sign
step 4: take 2's compliment
111 0100
-------------
000 1011
add 1
-------------
000 1100 =12
step 5:byte of 500=-12
example 3: number=300
300=1 0010 1100
1st 7 bits =010 1100
remaining bit is '0' sign =+ve need not take 2's compliment for +ve sign
hence 010 1100 =44
byte(300) =44
N is input number
case 1: 0<=N<=127 answer=N;
case 2: 128<=N<=256 answer=N-256
case 3: N>256
temp1=N/256;
temp2=N-temp*256;
if temp2<=127 then answer=temp2;
else if temp2>=128 then answer=temp2-256;
case 4: negative number input
do same procedure.just change the sign of the solution

BigDecimal Class in Java - Reason behind Constant values

I am working out with Java Puzzlers second puzzle.
public class Change {
public static void main(String args[]) {
System.out.println(2.00 - 1.10);
}
}
You will think the answer is 0.9. But it is not. If you workout this you will get 0.8999999. The solution given is
System.out.println(new BigDecimal("2.00").subtract(new BigDecimal("1.10")));
Now it will print 0.9. I understood why it prints 0.89999. But while
I am curiously debugging BigDecimal class, I found there are many constant values substituted in most of the places. I'll list all those below and interested to know the reason behind it.
BigDecimal.java line number 394,
while (len > 10 && Character.digit(c, 10) == 0) {
offset++;
c = in[offset];
len--;
}
Here Character.digit(c,10).
public static int digit(char ch, int radix) {
return digit((int)ch, radix);
}
Here 10 is passed as radix.
Q1. Why 10 is passed there.??
BigDecimal.java line number 732
int sign = ((valBits >> 63)==0 ? 1 : -1);
int exponent = (int) ((valBits >> 52) & 0x7ffL);
long significand = (exponent==0 ? (valBits & ((1L<<52) - 1)) << 1
: (valBits & ((1L<<52) - 1)) | (1L<<52));
exponent -= 1075;
Q2. If you look into the code in depth, you can understand what the valBits is, and I am unable to understand why rightshift is used some where?
Q3. Here also you can see there as many constants like 63, 52 are used. Why?
Q4. I can understand that the hexadecimal 0x7ffL used here will increase the speed of execution. Again why BitWise & operator is used there with the hexadecimal constant.
I hope my question is clear. Sincerely your patience is appreciated.
Q1: Of course, the radix is the base of the computation. You're are using a digit in base 10 ;)
Q4: 7ff in binary: 0111 1111 1111
If you read the explanation of the bit shift operators, Java "Bit Shifting" Tutorial? you will see that >> 63 discard the 63 first bits and keep the last one. The last bit is the sign bit (for signed types). If it is 1 then the integer is negative, hence the int sign there.
Also, you can refer to https://en.wikipedia.org/wiki/Floating_point for the definition of the floating point. The 52 is to distinguish between exponent and significand.
Q4: Of course, for the exponent, you don't want to use the 'sign' bit in it, since it's not a part of the exponent, hence the mask with 7ff. The Bitwise & 0x7ff just do that; it will only put a 0 on the first bit, and leave the other to the same state. (see the truth table of the 'AND' operator https://en.wikipedia.org/wiki/Truth_table)
Edit:
Q4 complementary: If the exponent is for example 12, then the first bit will be something like:
0000 0000 1100 ... (positive value) (ex: 1x10^12)
1000 0000 1100 ... (negative value) (ex: -1x10^12)
But: 1000 0000 1100 is 2060 decimal.
if you apply the 'mask':
1000 0000 1100 & 0111 1111 1111 -> 0000 0000 1100 (12 decimal)
AND
0000 0000 1100 & 0111 1111 1111 -> 0000 0000 1100 (12 decimal)
That's what the 0x7ff is for.

Bit shifting and bit mask - sample code

I've come across some code which has the bit masks 0xff and 0xff00 or in 16 bit binary form 00000000 11111111 and 11111111 00000000.
/**
* Function to check if the given string is in GZIP Format.
*
* #param inString String to check.
* #return True if GZIP Compressed otherwise false.
*/
public static boolean isStringCompressed(String inString)
{
try
{
byte[] bytes = inString.getBytes("ISO-8859-1");
int gzipHeader = ((int) bytes[0] & 0xff)
| ((bytes[1] << 8) & 0xff00);
return GZIPInputStream.GZIP_MAGIC == gzipHeader;
} catch (Exception e)
{
return false;
}
}
I'm trying to work out what the purpose of using these bit masks in this context (against a byte array). I can't see what difference it would make?
In the context of a GZip compressed string as this method seems to be written for the GZip magic number is 35615, 8B1F in Hex and 10001011 00011111 in binary.
Am I correct in thinking this swaps the bytes? So for example say my input string were \u001f\u008b
bytes[0] & 0xff00
bytes[0] = 1f = 00011111
& ff = 11111111
--------
= 00011111
bytes[1] << 8
bytes[1] = 8b = 10001011
<< 8 = 10001011 00000000
((bytes[1] << 8) & 0xff00)
= 10001011 00000000 & 0xff00
= 10001011 00000000
11111111 00000000 &
-------------------
10001011 00000000
So
00000000 00011111
10001011 00000000 |
-----------------
10001011 00011111 = 8B1F
To me it doesn't seem like the & is doing anything to the original byte in both cases bytes[0] & 0xff and (bytes[1] << 8) & 0xff00). What am I missing?
int gzipHeader = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
The type byte is Java is signed. If you cast a byte to an int, its sign will be extended. The & 0xff is to mask out the 1 bits that you get from sign extension, effectively treating the byte as if it is unsigned.
Likewise for 0xff00, except that the byte is first shifted 8 bits to the left.
So, what this does is:
take the first byte, bytes[0], cast it to int and mask out the sign-extended bits (treating the byte as if it is unsigned)
take the second byte, cast it to int, shift it left by 8 bits, and mask out the sign-extended bits
combine the values with |
Note that the shift left effectively swaps the bytes.
Apparently the purpose is to read the first word of bytes and store them in gzipHeader by suitable masking and shifting. More precisely, the first part masks out exactly the first byte while the second part masks out the second byte, already shifted by 8 bits. The | combines both bit masks to an int.
The resulting value is compared against the defined value GZIPInputStream.GZIP_MAGIC to determine if the first two bytes are the defined beginning of data compressed with gzip.
This is a trick to overcome big-endian/little-endian issues. It is forcing the interpretation of the first two bytes as little-endian, i.e. [0] contains the low byte and [1] contains the high byte.
byte is a signed type. If you convert 0xff as a byte to int you get -1. If you actually want to get 255, mask after the conversion.

Anding with 0xff, clarification needed

In the following snippet consider replacing line 8 with commented equivalent
1. private static String ipToText(byte[] ip) {
2. StringBuffer result = new StringBuffer();
3.
4. for (int i = 0; i < ip.length; i++) {
5. if (i > 0)
6. result.append(".");
7.
8. result.append(ip[i]); // compare with result.append(0xff & ip[i]);
9. }
10.
11. return result.toString();
12. }
.equals() test confirms that adding 0xff does not change anything. Is there a reason for this mask to be applied?
byte in Java is a number between −128 and 127 (signed, like every integer in Java (except for char if you want to count it)). By anding with 0xff you're forcing it to be a positive int between 0 and 255.
It works because Java will perform a widening conversion to int, using sign extension, so instead of a negative byte you will have a negative int. Masking with 0xff will leave only the lower 8 bits, thus making the number positive again (and what you initially intended).
You probably didn't notice the difference because you tested with a byte[] with only values smaller than 128.
Small example:
public class A {
public static void main(String[] args) {
int[] ip = new int[] {192, 168, 101, 23};
byte[] ipb = new byte[4];
for (int i =0; i < 4; i++) {
ipb[i] = (byte)ip[i];
}
for (int i =0; i < 4; i++) {
System.out.println("Byte: " + ipb[i] + ", And: " + (0xff & ipb[i]));
}
}
}
This prints
Byte: -64, And: 192
Byte: -88, And: 168
Byte: 101, And: 101
Byte: 23, And: 23
showing the difference between what's in the byte, what went into the byte when it still was an int and what the result of the & operation is.
As you're already working with an array of bytes here, and you're doing a bitwise operation, you can ignore how Java treats all bytes as signed. After all, you're working on the bit level now, and there is no such thing as "signed" or "unsigned" values on the level of bits.
Masking an 8-bit value (a byte) with all 1's is just a waste of cycles, as nothing will ever be masked off. A bitewise AND will return a bit true if both bits being compared are true, thus if the mask contains all 1's, then you're guaranteed that all bits of the masked value will remain unchanged after the AND operation.
Consider the following examples:
Mask off the upper nibble:
0110 1010
AND 0000 1111 (0x0F)
= 0000 1010
Mask off the lower nibble:
0110 1010
AND 1111 0000 (0xF0)
= 0110 0000
Mask off... Eh, nothing:
0110 1010
AND 1111 1111 (0xFF)
= 0110 1010
Of course, if you were working with a full blown int here, you'd get the result at the others have said: You'd "force" the int to be the equivalent of an unsigned byte.
In this example, I don't see how it would make any difference. You are anding the 0xff with a byte. A byte by definition has 8 bits, and the add masks off the last 8 bits. So you're taking the last 8 of 8, that's not going to do anything.
Anding with 0xff would make sense if the thing you were anding with it was bigger than a byte, a short or an int or whatever.
This should only make a difference if there are negative bytes. & 0xff is typically used to interpret a byte as unsigned.

Categories

Resources