Converting negative integer to hex value using pre-defined methods - java

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.

Related

DIfference between signed and unsigned practically

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).

Why does toHexString have variable length?

Why is it that toHexString prints different strings in what appears to be very specific circumstances? Printing a number below 0x80000000 works just fine. Adding 1 to that value and printing it works fine. But assigning that value directly does not print the same thing, instead I have to add an L to the end.
My guess is that it has to do with the fact that numeric literals are of type int by default, but I don't know this happens at 0x80000000 and not when crossing over 0xffffffff for instance.
long a = 0x7FFFFFFF;
System.out.println(java.lang.Long.toHexString(a)); // prints 7fffffff
a++;
System.out.println(java.lang.Long.toHexString(a)); // prints 80000000
long b = 0x80000000;
System.out.println(java.lang.Long.toHexString(b)); // prints ffffffff80000000
b=0x80000000L;
system.out.println(java.lang.Long.toHexString(b)); // prints 80000000
P.S. Why doesn't oracle or tutorialspoint say anything about how methods are implemented? Where can I find the implementation of the standard libraries?
That has nothing to do with the toHexString method, it's all about int vs long in Java, and binary representation of signed integers.
When you write
long b = 0x7FFFFFFF;
and
long b = 0x80000000;
the literal number on the right is interpreted as an int (32 bits). Now, in the second case that value overflows the (signed) integer positive range, its binary represantion has a 1 in the leftmost position, and hence the number is understood as negative (-2147483648). Afterwards, in the assignment, it's promoted to a (negative) long, so the extra 32 bits are filled with ones. That's why you see those "extra" FFF...
If you don't know about the binary representation of signed integers in Java, read here

Why does Byte.parseByte("80", 16) fail?

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.

Java 7 binary literals clarification

As you know, the binary literal is a new feature that is introduced in Java 7:
int x = 0b1011;
System.out.println(x); // prints 11 as expected
But, when I tried to get the maximum number from the literal binary I got -1!!!
int x = 0b11111111111111111111111111111111;
System.out.println(x); // prints -1 !!!
Further Details:
System.out.println(Integer.MAX_VALUE);
System.out.println(0b1111111111111111111111111111111); // 31 bits
/* Both print 2147483647 */
/************************************************************************************/
System.out.println(Integer.MIN_VALUE);
System.out.println(0b10000000000000000000000000000000); // 32 bits (increment by 1)
/* Both print -2147483648 */
/************************************************************************************/
// And if you keep increasing the binary literal, its actual value
// will be decreased until you reach the maximum binary literal and
// its actual value will be -1.
System.out.println(0b11111111111111111111111111111111); // 32 bits
/* Prints -1 */
As you can see, the actual value of the literal binary (while the increment) jumps over from the maximum value of int to the minimum one and then keep decreasing till it reaches -1 which is the maximum value of the literal binary.
Is this a bug? or does it have something to do with signed/unsigned numbers?
You're using a signed integer. Bit 32 (the "first" one from the left) is the sign bit. It being 1 means it is a negative number, and 0 means positive. Two's complement is then performed to give the value of -1. Read about that here:
http://tfinley.net/notes/cps104/twoscomp.html
This is not a bug at all: since int is unsigned, all bits to 1 does mean -1.
The leftmost bit of a signed integer, in two's complement, is the sign bit. What you see is therefore expected.
Indeed this is a signed int so is 0xffff == 0b11111111111111111111111111111111 == -1.
This is not a positive number.
See also Wikipedia Two's complement.
Java uses 32 bit signed integers, and the max/min & overflow results you are seeing are valid.
For more information see: http://en.wikipedia.org/wiki/Integer_(computer_science)
Java's int uses 2's complement signed integers. This means the leftmost bit indicates a negative number. So
int x = 0b11111111111111111111111111111111;
// ^--- this bit
indicates the number is negative. The fact that all of the other bits are also 1 means that the number is (decimal) -1. See the link for details.

Why is Java offended by my use of Long.parseLong(String s, int radix) with this long binary number?

I have the following code:
Why does Java think that this is not a valid long.
#Test
public void testOffendingBinaryString() {
String offendingString = "1000000000000000000010101000000000000000000000000000000000000000";
assertEquals(64, offendingString.length());
Long.parseLong(offendingString, 2);
}
Because it's out of range for the valid value of a long. The string:
"-111111111111111111101011000000000000000000000000000000000000000"
should work just fine. You cannot specify a negative number directly in 2s complement binary notation. And if you're trying to specify a positive number, that number is too big to fit into a Java long, which is a signed 64-bit value expressed in 2s complement (which means it's basically 63 bits + a sign bit (it's a little more complicated than that, read the page on 2s complement)).
The long is stored in 2's compliment, but the parse method expects straight binary. So, the max number of digits in the String can be 63.
When using regular binary, there is no sign bit. You can pass it a String with length 63 and precede it with a - if you want a negative long.
This is a bug in Java, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4215269, they fixed it in 1.8
Java long type:
8 bytes signed (two's complement).
Ranges from -9,223,372,036,854,775,808
to +9,223,372,036,854,775,807.
The size of the string is too long, check this question
Internally numbers are represented using the Two's complement. That means there are only 63 bits, for the number and one bit to represent positive or negative numbers. Since Long.parseLong() is not ment to parse numbers in Two's complement your String is a positive number with 64 bits, that exceeds the maximum positive value for a long.

Categories

Resources