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.
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).
I am a beginner in Java, and have just started learning this language.
I am learning and experimenting with examples from Herbert Schildt's book to test my understanding.
My objective is to convert negative integer to hex using in-built java methods, and then back to integer (or long). However, there are two issues that I am facing:
Issue #1: as I understand from the thread hex string to decimal conversion, Java Integer parseInt error and Converting Hexadecimal String to Decimal Integer that the converted value fffffff1 is too big to fit into Integer, so I have used Long. However, when fffffff1 is converted back to Long, I don't get -15. I get garbage value = 4294967281.
Moreover, when I type-cast the result from Long to Integer, it works well. I am not sure why Long result would show garbage value and then magically I would get the right value by just typecasting the number to integer-type. I am sure I am missing something crucial here.
Issue#2: If I don't use radix (or even change it from 16 to 4) in the method Long.parseLong(), I get an exception.
Here's my code:
public class HexByte {
public static void main(String[] args) {
byte b = (byte) 0xf1;
System.out.println("Integer value is:"+Integer.valueOf(b)); //you would get -15
int i = -15;
System.out.println("Hexadecimal value is:"+Integer.toHexString(i));
//Let's try to convert to hex and then back to integer:
System.out.println("Integer of Hexadecimal of -15 is:"+(int)Long.parseLong(Integer.toHexString(i),16 ));
//type-cast to integer works well, but not sure why
System.out.println("Integer of Hexadecimal of -15 is:"+Long.parseLong(Integer.toHexString(i),16));
//This surprisingly throws garbage value
System.out.println("Integer of Hexadecimal of -15 is:"+Long.parseLong(Integer.toHexString(i)));
//doesn't work - throws an exception
}
}
Can someone please help me? I didn't want to open duplicate threads for above issues so I have included them herewith.
Issue 1:
Negative numbers are represented using Two's Complement, which you can read more about here: wikipedia link
Basically, the left-most bit is used to determine the sign of the integer (whether it's positive or negative). A 0 means the number is positive, and a 1 means it's negative.
fffffff1 doesn't go all the way to the left, so the left-most bit when you convert that to long is a 0, which means the number is positive. When you cast it to an integer, the left bits are just dropped, and you end up somewhere in the middle of the 1s such that your leftmost digit is now a 1, so that the result is negative.
An example, with much shorter lengths for demonstration's sake:
4-bit number: 0111 -> this is positive since it starts with a 0
2-bit number using the last 2 bits of the 4-bit number: 11 -> this is negative since it starts with a 1.
Longs are like the 4-bit number in this example, and ints are like the 2-bit number. Longs have 64 bits and ints have 32 bits.
Issue 2:
If you don't specify a radix, Long.parseLong assumes base 10. You're giving it "fffffff1", and it doesn't recognize "f" as a digit in base 10 and thus throws an exception. When you specify the radix 16 then it knows "f" = 15 so there aren't any problems.
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.
This code
byte b = Byte.parseByte("10000000", 2);
throws an exception in Java. This should be -128 or 255.
Byte has 8 bit. Why can't I parse a 8 bit string?
The reason is down to the range of a byte in Java. Bytes are signed, so you can have anything from -128 ("-10000000") through to 127 ("1111111"), but no values outside that range.
The MAX_VALUE of a byte in java (or in C#) is 127 where as 10000000 return 128 which cannot be stored in a byte variable
What you can do treat the value as signed this way.
byte b = (byte) Integer.parseInt("10000000", 2);
Strictly, you passed not eight bits to parse method, but string representation of usual number with radix 2. And it may contain a sign character. Particularly, byte b = Byte.parseByte("-10000000", 2) works nice and gives -128.
That's not an 8-bit string, it's an 8-character string, and it's not being read the way you think it is...
From the MSDN documentation (here), you'll see that byte.Parse accepts strings in the integer format. So, you're trying to parse 10 million, not -1. The exception you're getting gives this away: you should see an OverflowException.
byte.parse("255") gives the effect you expect (byte is unsigned; using -128 also gives an overflow).