This is what I see in java, and it puzzles me.
Long.toHexString(0xFFFFFFFF) returns ffffffffffffffff
Similarly, 0xFFFFFFFF and Long.parseLong("FFFFFFFF", 16) are unequal.
As others have said, 0xFFFFFFFF evaluates to the int value -1, which is promoted to a long.
To get the result you were expecting, qualify the constant with the L suffix to indicate it should be treated as a long, i.e. Long.toHexString(0xFFFFFFFFL).
This:
Long.toHexString(0xFFFFFFFF)
is equivalent to:
Long.toHexString(-1)
which is equivalent to:
Long.toHexString(0xFFFFFFFFFFFFFFFFL)
Basically, the problem is that you're specifying a negative int value, which is then being converted to the equivalent negative long value, which consists of "all Fs". If you really want 8 Fs, you should use:
Long.toHexString(0xFFFFFFFFL)
Of course, Long in java is 64-bits long! 0xFFFFFFFF means -1 as an int, when written in 64 bits, it's ffffffffffffffff.
However, if the number were unsigned, the string would also be ffffffff [but there's no unsigned in java].
0xFFFFFFFF is an int literal. When using ints (32 bit in Java) 0xFFFFFFFF equals -1. What your code does:
the compiler parses 0xFFFFFFFF as an int with value -1
the java runtime calls Long.toHexString(-1) (the -1 get "casted" automatically to a long which is expected here)
And when using longs (64 bit in Java) -1 is 0xffffffffffffffff.
long literals are post-fixed by an L. So your expected behaviour is written in Java as:
Long.toHexString(0xFFFFFFFFL)
and Long.toHexString(0xFFFFFFFFL) is "ffffffff"
Related
Problem
I wanted to perform bit operation with Java and was expecting the same behavior that happens with C or C++. However it is not working as intended.
In C or C++
printf("%d", 0 > 0xFFFFFFFF);
this would return 0 (which is false)
However in Java
System.out.println(0 > 0xFFFFFFFF);
returns true
What I understand
I know how 2's complement works. The below is that I am guessing what is happening internally with those two languages.
C++ or C just translates 0xFFFFFFFF to 0xFFFFFFFF itself, so value 0 is smaller than 0xFFFFFFFF thus resulting false.
Java translates 0xFFFFFFFF with 2's complement as -1, so value 0 is bigger than -1 thus resulting true.
Question
Is there any possible way that Java can work just like C++ or C did? I would like Java's hex values to be recognized as hex values instead of converting them into signed int values?
In Java the literal 0xFFFFFFFF represents the int whose value is -1. In Java int is a signed type.
In C / C++ 0xFFFFFFFF will typically be either a long or an unsigned long. In the former case, it represents -1. In the latter case it represents 2^32 - 1 ... a very large positive integer.
Is there any possible way that Java can work just like C++ or C did?
No.
I would like Java's hex values to be recognized as hex values instead of converting them into signed int values?
Well the problem is that Java int is signed. And you can't change that.
However, there are methods in the Integer class that will treat an int value as if it was unsigned; e.g. Integer.compareUnsigned, divideUnsigned and parseUnsignedInt. See the javadocs for more details.
Here is some code I have been looking at:
public static long getUnsignedInt(ByteBuffer buff) {
return (long) (buff.getInt() & 0xffffffffL);
}
Is there any reason to do buff.getInt() & 0xffffffffL (0xffffffffL has 32 bits of 1's in the 32 least significant bits)? It looks to me like the result will always be buff.getInt().
In short, it's because the method needs to convert a signed int (which all Java ints are) to an unsigned quantity.
If you were to just do (long) buff.getInt(), and buff.getInt() returned -1, you'd end up with -1. And that's a signed quantity -- not what the method is supposed to return.
So what the method does is forces buff.getInt() to become unsigned by ANDing the int bits with 0x00000000FFFFFFFF. This effectively "reinterprets" the bits of the signed int as an unsigned int (really a signed long, but as only the lower 32 bits are ever going to be set, it works as an unsigned int), producing the desired result.
For example, (working with bytes for brevity).
Say buff.getInt() is really buff.getByte(), and returns -1 == 0xFF
Try to cast that to an int, you'll end up with 0xFFFFFFFF -- still -1, due to the magic of sign extension.
However, mask that with 0xFF, and you'll end up with 0x000000FF == 255 -- the desired value.
I believe the explicit cast is unnecessary (it isn't on my machine), but I could be missing something...
Edit: Turns out the cast actually is unnecessary. From JLS section 5.6.2:
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise,if either operand is of type float, the other is converted to float.
Otherwise, if either operand is of type long, the other is converted to long.
Otherwise, both operands are converted to type int.
If buff.getInt() is a negative number, it will still be a negative number when casting it to a long. But it'll be sign extended.
So, if you want to preserve the bit pattern, e.g. to try to interpret the values as unsigned values, &0xffffffffL will mask off those bits.
e.g. if buff.getInt() returns -2147483648, the returned int will have a bit pattern of 0x80000000. Cast to long, that'll still be -2147483648 , but with a bit pattern of 0xffffffff80000000. 0xffffffff80000000 & 0xFFFFFFFF preserves the original bit pattern of 0x80000000
Integers in Java (int and long) are signed, two's complement numbers. That means the high digit is 0 if the number is positive (or 0), and -1 if it's negative.
To convert from an int to a long, Java uses sign extension. This means that the numbers it "fills in" to the left depend on that leftmost digit. To illustrate with going from 4-bit to 8-bit numbers:
1 = 0001 -> 0000 0001
-1 = 1111 -> 1111 1111
So if you want to interpret 1111 as a signed number (ie, 15), you can't just convert it from 4 bits to 8: you'd get 1111 1111, which is -1. What you want is 0000 1111, which is 15.
To do this, you need to do a bitwise AND on the number to mask out the high bits which have been filled in, and turn those into 0's.
Consider the following code:
System.out.println(1 + 0xFFFFFFFFL);
System.out.println(1L + 0xFFFFFFFF);
The first line prints the expected value, 4294967296. But the second line prints a 0. I checked the type of both expressions (by passing them to methods) and both are recognized as long by the JVM. The Lava 7 language specification states that with binary operations, "if either operand is of type long, the other is converted to long." It seems that's what is happening, but I have two questions:
If both operands end up being longs, why are the higher-order bits chopped off in the first expression?
Why should the order matter?
0xFFFFFFFF is equal to -1. When you add 1 + -1 you get 0.
The order matters because 0xFFFFFFFFL != (long) 0xFFFFFFFF
Just like (double) 0.1F != 0.1
By default, in java all numeric constants are int.
In the second example, because java uses the two's-complement binary representation, the expression 0xFFFFFFFF is -1 as an int, which when widened to a long stays as -1, so you've coded 1 + -1, giving zero.
Is there a way to declare an unsigned int in Java?
Or the question may be framed as this as well:
What is the Java equivalent of unsigned?
Just to tell you the context I was looking at Java's implementation of String.hashcode(). I wanted to test the possibility of collision if the integer were 32 unsigned int.
Java does not have a datatype for unsigned integers.
You can define a long instead of an int if you need to store large values.
You can also use a signed integer as if it were unsigned. The benefit of two's complement representation is that most operations (such as addition, subtraction, multiplication, and left shift) are identical on a binary level for signed and unsigned integers. A few operations (division, right shift, comparison, and casting), however, are different. As of Java SE 8, new methods in the Integer class allow you to fully use the int data type to perform unsigned arithmetic:
In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 2^32-1. Use the Integer class to use int data type as an unsigned integer. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.
Note that int variables are still signed when declared but unsigned arithmetic is now possible by using those methods in the Integer class.
Whether a value in an int is signed or unsigned depends on how the bits are interpreted - Java interprets bits as a signed value (it doesn't have unsigned primitives).
If you have an int that you want to interpret as an unsigned value (e.g. you read an int from a DataInputStream that you know should be interpreted as an unsigned value) then you can do the following trick.
int fourBytesIJustRead = someObject.getInt();
long unsignedValue = fourBytesIJustRead & 0xffffffffL;
Note, that it is important that the hex literal is a long literal, not an int literal - hence the 'L' at the end.
We needed unsigned numbers to model MySQL's unsigned TINYINT, SMALLINT, INT, BIGINT in jOOQ, which is why we have created jOOU, a minimalistic library offering wrapper types for unsigned integer numbers in Java. Example:
import static org.joou.Unsigned.*;
// and then...
UByte b = ubyte(1);
UShort s = ushort(1);
UInteger i = uint(1);
ULong l = ulong(1);
All of these types extend java.lang.Number and can be converted into higher-order primitive types and BigInteger. Hope this helps.
(Disclaimer: I work for the company behind these libraries)
For unsigned numbers you can use these classes from Guava library:
UnsignedInteger
UnsignedLong
They support various operations:
plus
minus
times
mod
dividedBy
The thing that seems missing at the moment are byte shift operators. If you need those you can use BigInteger from Java.
Perhaps this is what you meant?
long getUnsigned(int signed) {
return signed >= 0 ? signed : 2 * (long) Integer.MAX_VALUE + 2 + signed;
}
getUnsigned(0) → 0
getUnsigned(1) → 1
getUnsigned(Integer.MAX_VALUE) → 2147483647
getUnsigned(Integer.MIN_VALUE) → 2147483648
getUnsigned(Integer.MIN_VALUE + 1) → 2147483649
Use char for 16 bit unsigned integers.
There are good answers here, but I don’t see any demonstrations of bitwise operations. Like Visser (the currently accepted answer) says, Java signs integers by default (Java 8 has unsigned integers, but I have never used them). Without further ado, let‘s do it...
RFC 868 Example
What happens if you need to write an unsigned integer to IO? Practical example is when you want to output the time according to RFC 868. This requires a 32-bit, big-endian, unsigned integer that encodes the number of seconds since 12:00 A.M. January 1, 1900. How would you encode this?
Make your own unsigned 32-bit integer like this:
Declare a byte array of 4 bytes (32 bits)
Byte my32BitUnsignedInteger[] = new Byte[4] // represents the time (s)
This initializes the array, see Are byte arrays initialised to zero in Java?. Now you have to fill each byte in the array with information in the big-endian order (or little-endian if you want to wreck havoc). Assuming you have a long containing the time (long integers are 64 bits long in Java) called secondsSince1900 (Which only utilizes the first 32 bits worth, and you‘ve handled the fact that Date references 12:00 A.M. January 1, 1970), then you can use the logical AND to extract bits from it and shift those bits into positions (digits) that will not be ignored when coersed into a Byte, and in big-endian order.
my32BitUnsignedInteger[0] = (byte) ((secondsSince1900 & 0x00000000FF000000L) >> 24); // first byte of array contains highest significant bits, then shift these extracted FF bits to first two positions in preparation for coersion to Byte (which only adopts the first 8 bits)
my32BitUnsignedInteger[1] = (byte) ((secondsSince1900 & 0x0000000000FF0000L) >> 16);
my32BitUnsignedInteger[2] = (byte) ((secondsSince1900 & 0x000000000000FF00L) >> 8);
my32BitUnsignedInteger[3] = (byte) ((secondsSince1900 & 0x00000000000000FFL); // no shift needed
Our my32BitUnsignedInteger is now equivalent to an unsigned 32-bit, big-endian integer that adheres to the RCF 868 standard. Yes, the long datatype is signed, but we ignored that fact, because we assumed that the secondsSince1900 only used the lower 32 bits). Because of coersing the long into a byte, all bits higher than 2^7 (first two digits in hex) will be ignored.
Source referenced: Java Network Programming, 4th Edition.
It seems that you can handle the signing problem by doing a "logical AND" on the values before you use them:
Example (Value of byte[] header[0] is 0x86 ):
System.out.println("Integer "+(int)header[0]+" = "+((int)header[0]&0xff));
Result:
Integer -122 = 134
Just made this piece of code, wich converts "this.altura" from negative to positive number. Hope this helps someone in need
if(this.altura < 0){
String aux = Integer.toString(this.altura);
char aux2[] = aux.toCharArray();
aux = "";
for(int con = 1; con < aux2.length; con++){
aux += aux2[con];
}
this.altura = Integer.parseInt(aux);
System.out.println("New Value: " + this.altura);
}
You can use the Math.abs(number) function. It returns a positive number.
I want to obtain the least 32 bits from a number of type long, so I perform bitwise operation "&" on the number with bits mask 0xFFFFFFFF, but the result is not correct, it still contains the other bits.
for example:
long a = 0x1234567890ab;
long b = (a & 0xffffffff);
I expect the value of b to be 0x567890ab
but in practice, it is still 0x1234567890ab
Try this:
long a = 0x1234567890ab;
long b = (a & 0xffffffffL);
0xffffffff is a literal of type int, for performing & with long it's promoted to type long by sign extension, therefore it turns into 0xffffffffffffffff. To avoid sign extension you need to write it as a literal of type long: 0xffffffffL.
Does using 0xffffffffL make any difference?
I think what happens is that 0xffffffff gets upcasted to a long, and since both int and long are signed it tries to keep the same sign.
So, since 0xffffffff is -1 as an int, it gets converted to -1 as a long, or 0xffffffffffffffff
try doing a bitwise AND with a long value with some leading zeroes instead of a 32 bit value. right now you're basically doing nothing to the number.