I was trying to store byte value in a variable and trying to perform some logic based upon this calculation.
byte mByteValue = -129; // Holding byte value
Problem is I am always getting value 127, due to which my logic fails everytime.
Any specific reason behind this, why its behaving strange in my case?
A byte in java is a signed 8-bit value. 8 bits gives you 256 possible values, but since a byte is signed and can represent positive and negative values, those 256 values must be roughly split in half across the possible positive and negative values. So you can't store negative values past -128; in particular don't expect to be able to store -256.
What you're actually observing when your byte has the value 127 is known as overflow (see this wiki article)
If you need to manipulate values outside this range, as in your example code, or e.g. an unsigned byte, at some point you'll need to make use of a wider integer type, like short.
The standard libraries provide these limits as Byte.MIN_VALUE and Byte.MAX_VALUE (docs here and here).
The range of byte is from -128 to 127. You can not store any value beyond these range.
This is because byte is 8 bits. So the maximum positive number stored at byte is -
2^7 -1 = 127. // since the first bit is sing bit; 0 for positive
And minimum negative number stored at byte is-
2^7 = -128 //since the first bit is sign bit; 1 for negative.
And if you use unsigned byte the it would be 255.
To correctly convert a byte to an int use mByteValue & 0xFF. You can read more about the Two's complement here: https://en.wikipedia.org/wiki/Two%27s_complement.
Related
I am working on a file reader and came into a problem when trying to read a short. In short (punintended), java is converting a two bytes I'm using to make the short into an int to do bitwise operations and is converting it in a way to keep the same value. I need to convert the byte into an int in a way that would preserve its value so the bits stayed the same.
example of what's happening:
byte number = -1; //-1
int otherNumber = 1;
number | otherNumber; // -1
example of what I want:
byte number = -1; //-1
int otherNumber = 1;
number | otherNumber; // 129
This can be done pretty easily with some bit magic.
I'm sure you're aware that a short is 16 bits (2 bytes) and an int is 32 bits (4 bytes). So, between an integer and a short, there is a two-byte difference. Now, for positive numbers, copying the value of a short to an int is effectively copying the binary data, however, as you've pointed out, this is not the case for negative numbers.
Now let's look at how negative numbers are represented in binary. It's a bit confusing, so I'll try to keep it simple. Modern systems use what's called the two's compliment to store negative numbers. Basically all this means is that the very first bit in the set of bytes representing the number determines whether or not it's negative. For mathematical purposes, the rest of the bits are also inverted and offset 1 bit to the right (since you can't have negative 0). For example, 2 as a short would be represented as 0000 0000 0000 0010, while -2 would be represented as 1111 1111 1111 1110. Now, since the bytes are inverted in a negative number, this means that -2 in int form is the same but with 2 more bytes (16 bits) at the beginning that are all set to 1.
So, in order to combat this, all we need to do is change the extra 1s to 0s. This can be done by simply using the bitwise and operator. This operator goes through each bit and checks if the bits at each position in each operand are a 1 or a 0. If they're both 1, the bit is flipped to a 0. If not, nothing happens.
Now, with this knowledge, all we need to do is create another integer where the first two bytes are all 1. This is fairly simple to do using hexidecimal literals. Since they are an integer by default, we simply need to use this to get four bytes of 1s. With a single byte, if you were to set every bit to 1, the max value you can get is 255. 255 in hex is 0xFF, so 2 bytes would be 0xFFFF. Pretty simple, now you just need to apply it.
Here is an example that does exactly that:
short a = -2;
int b = a & 0xFFFF;
You could also use Short.toUnsignedInt(), but where's the fun in that? 😉
I've searched and read many previous answers concerning this difference but I still don't get somethings, for example with this line of code :
System.out.println(Integer.parseUnsignedInt("11111111111111111111111111111111", 2));
I read that Unsigned can hold a larger positive value, and no negative value. Unsigned uses the leading bit as a part of the value, while the signed version uses the left-most-bit to identify if the number is positive or negative. signed integers can hold both positive and negative numbers. A Unisgned can go larger than MAX_VALUE, so why is that sysout gives -1 which is negative. And for this line code :
System.out.println(Integer.parseInt("11111111111111111111111111111111", 2));
Why does this line gives an error(32 times 1) ? Isn't a signed int suppose to treat the first 1 as a minus, and the other 31 1's as the positive value ? (so it should give - MAX_VALUE)
Java does not have unsigned integer types. When you call parseUnsignedInt, it does not return an unsigned integer, because there is no such thing in java.
Instead, parseUnsignedInt parses the input as an unsigned 32-bit value, and then returns the signed 32-bit value with the same bits.
If you provide it with a number that has the leading bit set in its unsigned representation, it will therefore return a negative number, because all the signed numbers with that bit set are negative.
Why does this line gives an error(32 times 1) ? Isn't a signed int
suppose to treat the first 1 as a minus, and the other 31 1's as the
positive value ? (so it should give - MAX_VALUE)
It throws a NumberFormatException for exactly the same reason that
Integer.parseInt("2147483648", 10)
does. The string does not represent a number that can be represented as an int when interpreted according to the specified radix. That int uses 32 bits to represent values is only peripherally related. If you want to parse a negative value with Integer.parseInt() then the string should contain a leading minus sign:
Integer.parseInt("-1111111111111111111111111111111", 2)
or even
Integer.parseInt("-10000000000000000000000000000000", 2) // note: 32 digits
The method is not mapping bits directly to an int representation. It is interpreting the string as a textual representation of a number.
A Unsigned can go larger than MAX_VALUE, so why is that sysout gives
-1 which is negative.
Integer holds a 32-bit value. The result of parseUnsignedInt(32 one-bits, 2) is a value with all bits set. What that "means" is in the eye of the beholder. Most of Java considers integer values to be signed. The formatter used by println, for example, regards the value as signed, and the result is -1.
All you really have 'inside' the Integer is a 32-bit value. parseUnsignedInt() handles its input argument specially, but then it has to store the result in a standard Integer. There is nothing to say that the bits are supposed to be 'unsigned'. If you want to treat the value as unsigned, you can't use anything that treats it as signed, since Java really does not have an unsigned-integer type.
Isn't a signed int suppose to treat the first 1 as a minus, and the
other 31 1's as the positive value ? (so it should give - MAX_VALUE)
See other answer for this part.
The representation I think you were expecting, where the high bit indicates the sign and the rest of the bits indicates the (positive) value, is called "sign and magnitude" representation. I am unaware of any current computer that uses sign-and-magnitude for its integers (may have happened in the very early days, 1950s or so, when people were getting to grips with this stuff).
System.out.println(Byte.toString( (byte)(1 << 7) ));//print "-128"
System.out.println(Byte.parseByte("80", 16));//run time exception java.lang.NumberFormatException: Value out of range. Value:"80" Radix:16
Why does the first succeed while the second fails? One might expect that they produce the same output.
Hexadecimal 0x80 is 128 in decimal. Bytes can only hold values from -128 to 127, inclusive. So, when you try to parse a value of 128, it fails because that value can't be represented as a byte.
If you want to parse a negative value, you need to include a negative sign:
System.out.println(Byte.parseByte("-80", 16)); /* Prints -128 */
When performing a narrowing conversion, for example, from int to byte as in this example, information about the overall magnitude of a value can be lost. Casting an int value to byte simply discards all but the lowest 8 bits, so casting int 128 to byte yields -128.
The first operator is a binary shift. -128 represents 0b10000000 in binary code. The 1 shifted seven times to the left.
In the second statement, the radix you're using is for hex numbers as you can see in Tutorialspoint's example. If you change your statement to System.out.println(Byte.parseByte("80", 10));, you won't get the exception.
Hope this explanations was of help.
I can store numbers ranging from -127 to 127 but other than that it is impossible and the compiler give warning. The binary value of 127 is 01111111, and 130 is 10000010 still the same size (8 bits) and what I think is I can store 130 in Byte but it is not possible. How did that happen?
Java does not have unsigned types, each numeric type in Java is signed (except char but it is not meant for representing numbers but unicode characters).
Let's take a look at byte. It is one byte which is 8 bits. If it would be unsigned, yes, its range would be 0..255.
But if it is signed, it takes 1 bit of information to store the sign (2 possible values: + or -), which leaves us 7 bits to store the numeric (absolute) value. Range of 7 bit information is 0..127.
Note that the representation of signed integer numbers use the 2's complement number format in most languages, Java included.
Note: The range of Java's byte type is actually -128..127. The range -127..127 only contains 255 numbers (not 256 which is the number of all combinations of 8 bits).
In Java, a byte is a signed data type. You are thinking about unsigned bytes, in which case it is possible to store the value 130 in 8 bits. But with a signed data type, that also allows negative numbers, the first bit is necessary to indicate a negative number.
There are two ways to store negative numbers, (one's complement and two's complement) but the most popular one is two's complement. The benefit of it is that for two's complement, most arithmetic operations do not need to take the sign of the number into account; they can work regardless of the sign.
The first bit indicates the sign of the number: When the first bit is 1, then the number is negative. When the first bit is 0, then the number is positive. So you basically only have 7 bits available to store the magnitude of the number. (Using a small trick, this magnitude is shifted by 1 for negative numbers - otherwise, there would be two different bit patterns for "zero", namely 00000000 and 10000000).
When you want to store a number like 130, whose binary representation is 10000010, then it will be interpreted as a negative number, due to the first bit being 1.
Also see http://en.wikipedia.org/wiki/Two%27s_complement , where the trick of how the magnitude is shifted is explained in more detail.
can anyone tell me why this explicit conversion gives different results, even if size of short/char is both 16bits?
package jh;
public class Main {
public static void main(String[] args) {
byte b = (byte)255;
System.out.println("Size of short: " + Short.SIZE);
System.out.println("Size of char: " + Character.SIZE);
System.out.println((int)((short)b));
System.out.println((int)((char)b));
}
}
Output:
Size of short: 16
Size of char: 16
-1
65535
From Java datatypes doc
byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive). The byte data type can be useful for saving memory in large arrays, where the memory savings actually matters. They can also be used in place of int where their limits help to clarify your code; the fact that a variable's range is limited can serve as a form of documentation.
short: The short data type is a 16-bit signed two's complement integer. It has a minimum value of -32,768 and a maximum value of 32,767 (inclusive). As with byte, the same guidelines apply: you can use a short to save memory in large arrays, in situations where the memory savings actually matters.
char: The char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive).
So in short (pardon the pun), bitwise they are the same. But char represents a different numeric value for the same bit pattern as short.
This is also accompanied by the sign extension feature: (byte) 255 is going to mean a byte value, with all bits set (0b11111111), which is -1, in twos complement. When converting upwards, Java does a sign extension operation, so if the sign bit is 0, all the higher bits will be 0 too, but when the sign bit is 1, all higher bits will be 1 too. This now means that -1 will mean -1 in all signed, integer datatypes (0b1111111111111111 for short in this example). But not char - which when has all bits set, equals the positive maximum value - 65535.
byte is signed and only holds values -128..127. When you assign 255 it wraps around and becomes -1.
(short)b is -1.
char however is the only unsigned type in Java, it has values 0..65535, so (char)-1 wraps around again and becomes 65535.
byte b = (byte)255; this assigns the value -1 to b since byte is signed. When you cast -1 to short you get -1. When you cast -1 to char you get 65535 since the range of char lies between 0 and 65535