Why does toHexString have variable length? - java

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

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

Internal conversion of integer to char whose size is smaller

In the following program , I am assigning a integer data type to a char data type.
public static void main(String args[]) {
char ch =65;
System.out.println(ch);
}
I know the fact that int occupies 32 bits and char occupies 16 bits . With that knowledge , I was expecting the compiler throw an error of some message "Attempt to convert a data of higher size to a lower size ".
Why is the compiler not complaining and internally converting and printing the output as 'A' (I understand the fact that it is the ASCII equivalent of 65, my question is only related to the size of data types) ?
The compiler does in fact validate the range. That is working because int 65 is within the expected range.
The following won't compile:
char c = (int)Character.MAX_VALUE + 1
char c = 65536
And this will, just like your assignment:
char c = 65535 //Within range
When the value is not a constant at compile time, though, there's need for cast:
private static void charRange(int i) {
char c = (char) i;
System.out.println(" --> " + (int) c);
}
charRange(65);
charRange(Character.MAX_VALUE + 20);
And the check doesn't happen (making room for overflow)
--> 65
--> 19
There is an exception to Java's general rule about converting an int to a char. If the int is a compile time constant expression (e.g. a literal) AND the int value of the expression is within the required range (0 to 65535), then it is legal to assign the int expression to a char.
Intuitively, for a compile-time constant expression, the compiler knows if the expression value can be assigned without loss of information.
This is covered by JLS 5.2 ... in the paragraph that starts "In addition, if the expression is a constant expression ..."
Programing languages like Java or C# come with a set of integer primitive types. Each type has a well-defined range in the form of [min value, max value]. This values are stored in a fixed sequence of bits from most significant bit to the least one.
For example, let the decimal number 123456 be represented for the next 32 bit sequence
0000000000000011110001001000000
When you attempt to convert a 32-bit number type to a 16-bit one, the compiler copies the 16 least significant bits (or the last 16 bits) then 123456 number is wrapped to
1110001001000000
And if you convert this binary number to decimal it is 57920. As you realize, the 32-bit number cant fit into a 16-bit sequence, and the original sequence was arbitrarily wrapped. This is known as integer overflow, and also happens when you add or multiply 2 number which result is out of bounds of the integer type range.
As programmer, you should be aware of overflow, and react to this to avoid a program failure. You also should read further details about signed integer representation.

Converting negative integer to hex value using pre-defined methods

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.

Java quickly access array item

I'm doing a calculation that returns a long decimal, for example 4611686018427387904. I need to first convert it to hex and then chack an array of size (16) depending on the bits set.
So the above number gets converted to 0x40000000000000000L, this corresponds to the first index in the array. If the number is 0x0004000000000000L it corresponds to the 3rd index in the array.
My questions are:
Is there a quick way to convert a decimal to hex?
Is there a quick way to access an array depending on the bits set of the value (instead of using loops)?
If the number is in the long range, use Long.highestOneBit(). Alternatively, BigInteger has a bitLength() method.
First, a guess: you have a long that you are viewing as 16 4-bit numbers. You want to use each 4-bit number as an index into a 16-element array.
I think the fastest way to do this is going to be with a mask and some bit-shifting. Both are fast operations. If you mask out of the bottom, you don't have to shift the result after you mask.
There are 16 4-bit groupings in a long, so:
long l = 1234;
int[] results = new int[16];
for (int i=15; i>=0; i--)
{
int index = (int)l & 0xF;
results[i] = index;
l = l >> 4;
}
This gets your 16 indices from the right (lower-order) bits of your long, and you say the left (higher-order) bits are the first indices. So this gets them all in reverse order and stores them accordingly. Adjust for shorts or whatever you need, and this will be fast.
Warning: I have not run this code. I mean it as a kind of java pseudo-code.
IN CASE YOU ARE NOT FAMILIAR WITH THE '&' OPERATOR: it gives you back the ones and zeros in the positions which have 1s in them, so & with 0xF will tell you whatever the lower-order 4 bits are.
Remember internally all primitives in Java is stored as binary. The fact that it prints a decimal number when you pass it to System.out.println() is a view on that binary value. So converting a decimal to hex if it's stored in a primitive (double, float, long, integer, short, byte) is already done. If you want to convert that value to a hex string for display purposes you can Integer.toHexString( int ).
Java has an upper limit on array sizes which is an integer so 2^31 slots. Anything over that and you'll have to use two or more structures and combine them. I suppose that's sorta what you are doing. But, if you are doing that maybe use a long, and Long.highestOneBit() could be a first index into an array of arrays where each slow is an array of potentially 2^31 slots. Of course that isn't a particularly efficient structure for memory usage. But that would give you a view that is potentially the size of a long. You probably don't have enough memory for that, but who knows.

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.

Categories

Resources