behavioral change during multicasting [duplicate] - java

This question already has answers here:
what is logic behind this java code
(3 answers)
Closed 7 years ago.
Following is a simple statement
System.out.println((int)(char)(byte)-1);
when I run it I get output as 65535. I dont know the reason for
it.
During execution (byte)-1 return -1,hence (int)(char)(byte)-1 is equivalent to (int)(char)-1. when I print (char)-1 it prints ? only in some system but not in all systems.
if I ignore the 2nd point above mentioned and print (int)'?' then it
prints 63
So my question is if I do multicast all together that is (int)(char)(byte)-1 then I get 65535 but if I do casting part by part that
(byte)-1
(char)-1
(int)'?'
then I get 63,why is it so?

For 1):
First, you have an integer (32 bits) the binary representation of -1 is:
1111 1111 1111 1111 1111 1111 1111 1111
then, it is converted to a byte (8 bits):
1111 1111
If you print that, you'll get -1 (that's the byte representation for -1) then, it is cast to a char (a 16 bit unsigned character) which will give you:
1111 1111 1111 1111
(because it will "expand" the sign) if you try to print this as a char, you'll get an "irrecognizable" character (in some systems it will print the question mark) then, you do a cast to int; but, a char is unsigned, so there is expansion os the sign (because there is no sign), so you finally have:
0000 0000 0000 0000 1111 1111 1111 1111
which, in decimal equals 65535
For 2):
No, (int)(char)(byte)-1 is not equivalent to (int)(char)-1 (see explanation for #1)

It's about converting a signed type to an unsigned one. In Java the char range is [0,2^16). So when you try to convert -1 (signed type, negative value) to an unsigned type you end up with
2^16 - 1 = 65535

Related

Why 2^31 can't store in integer variable but - 2^31 can?

Integer variables are 4-bytes or 32-bits, and 2^31 and -2^31 both in binary numbers are 32 bits. But when you put 2^31 = 2,147,483,648 in an integer variable it shows an error, but for -2^31 it is ok. Why?
Integer variables are 4-bytes or 32-bits, and 2^31 and -2^31 both in binary numbers are 32 bits
No they are not.
in basic binary, negative numbers aren't a thing. We have zeroes and ones. There is no - sign.
In binary, 2^31 becomes:
1000 0000 0000 0000 0000 0000 0000 0000
In binary, -2^31 cannot be represented without first defining how negative numbers are to be stored.
Commonly (and java does this too), a system called 2's complement is used. 2's complement sounds real complicated: Take the number, say, 5. Represent it in binary (for this exercise, let's go with byte, i.e. 8 bits): 0000 0101. Now, flip all bits: 1111 1010, and then add 1: 1111 1011.
That is -5 in signed 2's complement binary.
This bizarre system has two amazing properties: Math continues to work as normal without needing to know if the number is signed or unsigned. Let's try it. -5 + 2 is -3, right? let's see.. what's 1111 1011 + 0000 0010? Without worrying about 2's complement at all, I get 1111 1101. Let's apply 2's complement conversion: first flip the bits: 0000 0010, then add 1: 0000 0011, which is... 3. So -5 + 2 is -3. Check. The other amazing property is that it doesn't 'waste' 2 of the 2^32 "slots" on zeroes. Let's try the 2's complement of 0: 0000 0000, then flip all bits: 1111 1111, then add 1: 0000 0000 (with a bit overflow that we ignore). That's nice: 0 is its own 2's complement. We can't tell 0 and -0 apart, but that's generally a good thing.
Another property of this system is that the first bit is the 'sign' bit. if it is 1, it is negative, if 0, it is not.
Let's try to 2's complement 1000 0000 0000 0000 0000 0000 0000 0000. First, flip the bits: 0111 1111 1111 1111 1111 1111 1111 1111. Then add 1: 1000 0000 0000 0000 0000 0000 0000 0000. Wait. That's... what we had!!
Yup. and because the first bit is negative, 1000 0000 0000 0000 0000 0000 0000 0000 is NEGATIVE.
Perhaps you are forgetting that 0 is a thing, and 0 is neither positive nor negative.
So, if 0 needs to be representable, and gets a 0 sign bit (zero in bits is 0000000... of course), that means the 'space' in the half of all representable numbers that start with a 0 is now one smaller, because 0 has eaten one slot. That means there is one more negative number representable vs. the positive numbers. (or, alternatively, that 0 'counts' as positive, therefore 0 is the first positive number, but -1 is the first negative number). Therefore, there must be at least 1 negative number that has no positive equivalent in 2's complement. That number is... 2^31. -2^31 fits in 32-bit signed. +2^31 doesn't.
Let's imagine a 3-bit signed number, with 2's complement. We can list them all:
000 = 0
001 = 1
010 = 2
011 = 3
100 = -4
101 = -3
110 = -2
111 = -1
Note how -4 is in there, but +4 is not, and note how we covered 8 numbers. 2^3 = 8 - 3 bits can represent 8 numbers, not more than that.
From the oracle documentation we got that:
int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of -2^31 and a maximum value of 2^31-1. 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. See the section The Number Classes for more information. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.
From another document(simple and quite understandable) we got:
When an integer is signed, one of its bits becomes the sign bit, meaning that the maximum magnitude of the number is halved. (So an unsigned 32-bit int can store up to 2^32-1, whereas its signed counterpart has a maximum positive value of 2^31-1.)
In Java, all integer types are signed (except char).
Is because the first bit indicate the sign bit. Maximum positive value it can store it 2^31 - 1. There are many resources available for this.

how to convert integer to hex signed 2's complement:

Pretty basic stuff i am sure but bits are not my forte.
So for some internal calculation i am trying to convert a given input ( constraint is that it would be a integer string for sure) into its hex equivalent, what stumped me is on how to get
Hex signed 2's complement:
My noob code:
private String toHex(String arg, boolean isAllInt) {
String hexVal = null;
log.info("arg {}, isAllInt {}", arg, isAllInt);
if (isAllInt) {
int intVal = Integer.parseInt(arg);
hexVal = Integer.toHexString(intVal);
// some magic to convert this hexVal to its 2's compliment
} else {
hexVal = String.format("%040x", new BigInteger(1, arg.getBytes(StandardCharsets.UTF_8)));
}
log.info("str {} hex {}", arg, hexVal);
return hexVal;
}
Input: 00001
Output: 1
Expected Output: 0001
Input: 00216
Output: D8
Expected Output: 00D8
00216
Input: 1192633166
Output: 4716234E
Expected Output: 4716234E
any predefined library is much welcome or any other useful pointers!
So to pad the hex digits up to either 4 digits or 8 digits, do:
int intVal = Integer.parseInt(arg);
if (intVal >= 0 && intVal <= 0xffff) {
hexVal = String.format("%04x", intVal);
} else {
hexVal = String.format("%08x", intVal);
}
See Java documentation on how the format strings work.
Answering the two's complement aspect.
Two's Complement Representation
Two's complement is an agreement how to represent signed integral numbers in e.g. 16 bits (in olden times, different representations have been used by various processors, e.g. one's complement or sign-magnitude).
Positive numbers and zero are represented as expected:
0 is 0000 0000 0000 0000 or hex 0000
1 is 0000 0000 0000 0001 or hex 0001
2 is 0000 0000 0000 0010 or hex 0002
3 is 0000 0000 0000 0011 or hex 0003
4 is 0000 0000 0000 0100 or hex 0004
Negative numbers are represented by adding 1 0000 0000 0000 0000 to them, giving:
-1 is 1111 1111 1111 1111 or hex ffff
-2 is 1111 1111 1111 1110 or hex fffe
-3 is 1111 1111 1111 1101 or hex fffd
This is equivalent to: take the positive representation, flip all bits, and add 1.
For negative numbers, the highest bit is always 1. And that's how the machine distinguishes positive and negative numbers.
All processors in use today do their integer arithmetic based on two's complement representation, so there's typically no need to do special tricks. All the Java datatypes like byte, short, int, and long are defined to be signed numbers in two's complement representation.
In a comment you wrote
2's compliment is hex of negative of original value
That mixes up the concepts a bit. Two's complement is basically defined on bit patterns, and groups of 4 bits from these bit patterns can nicely be written as hex digits. Two's complement is about representing negative values as bit patterns, but from your question and comments I read that you don't expect negative values, so two's complement shouldn't concern you.
Hex Strings
To represent signed values as hex strings, Java (and most other languages / environments) simply looks at the bit patterns, ignoring their positive / negative interpretation, meaning that e.g. -30 (1111 1111 1110 0010) does not get shown as "-1e" with a minus sign, but as "ffe2".
Because of this, negative values will always get translated to a string with maximum length according to the value's size (16 bits, 32 bits, 64 bits giving 4, 8, or 16 hex digits), because the highest bit will be 1, resulting in a leading hex digit surely not being zero. So for negative values, there's no need to do any padding.
Small positive values will have leading zeros in their hex representation, and Java's toHexString() method suppresses them, so 1 (0000 0000 0000 0001) becomes "1" and not "0001". That's why e.g. format("%04x", ...), as in #nos's answer, is useful.

What happens when a long outside of range for int (-2^31..2^31-1) is cast to int?

I was running code in an attempt to figure out the behavior of Java when losing precision due to casting between the integral decimal numeric types, and I found an unexpected result:
long l2 = 999999999999999999L; //outside of range -2147483648..2147483647 for int
int i3=(int)l2;
System.out.println(l2); //999999999999999999, as expected.
System.out.println(i3); //I expected 2147483647, but got -1486618625
Can someone please explain how I'm getting a large negative int out of a large positive long? I would have expected the system to at least make a best effort casting attempt, returning the maximum positive integer (the closest valid int to the long which is too large to be stored in integer.) Instead, I'm getting a negative number which does not make sense to me.
The narrowing primitive conversion of a long to an int discards all but the lower order 32 bits of the original number, so you don't get Integer.MAX_VALUE.
The JLS, Section 5.1.3, states:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
This is in contrast to a primitive narrowing conversion from a floating-point type to an int, which may result in Integer.MAX_VALUE if the original value was too big.
double l2 = 999999999999999999.0;
System.out.println((int) l2);
This prints:
2147483647
Let's first take a look at the result number bits :
Now look at the bits representation of 999999999999999999 :
Notice that the first 32 bits is the same in both case.
Now considering the JLS, Section 5.1.3, as rgettman stated :
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits, where n is the number of bits used to represent type T. In addition to a possible loss of information about the magnitude of the numeric value, this may cause the sign of the resulting value to differ from the sign of the input value.
So you would only keep the 32 first bits (10100111011000111111111111111111) when doing the cast. Therefore, considering the highest bit of a signed integer represent the sign of the number you will have a negative(1)0100111011000111111111111111111
Which is equals to -1486618625 as decimal value.
A cast does not do any conversations nor does it care about the data. (or about truncating)
999999999999999999 in binary is 0000 1101 1110 0000 1011 0110 1011 0011 1010 0111 0110 0011 1111 1111 1111 1111.
When casting this to an signed int, just the lower 32 bits will be used:
1010 0111 0110 0011 1111 1111 1111 1111 - Now, that number means (its an signed integer now due to casting):
Leading 1 = negative number
010 0111 0110 0011 1111 1111 1111 1111 would be 660865023 in dec... not correct.
Java uses the Two's complement, which means if you are only looking at the "number" of a negative number, you need to invert every bit and add 1 to get the actual numeric value:
so:
010 0111 0110 0011 1111 1111 1111 1111
101 1000 1001 1100 0000 0000 0000 0000 + 1
101 1000 1001 1100 0000 0000 0000 0001
101 1000 1001 1100 0000 0000 0000 0001 is 1486618625 - and it's negative: Voila, your -1486618625
The highest bit of a signed integer is the sign bit. So, if you overflow an operation into that bit, you will get a negative number. In this case you are doing it by casting.
= 1101 1110 0000 1011 0110 1011 0011 1010 0111 0110 0011 1111 1111 1111 1111
Truncated to (int):
1010 0111 0110 0011 1111 1111 1111 1111
Twos' compliment transform:
0101 1000 1001 1100 0000 0000 0000 0001 = 1486618625

Bitwise operator ~ giving the ouput not expected [duplicate]

This question already has answers here:
How does the bitwise complement operator (~ tilde) work?
(18 answers)
Closed 9 years ago.
I wrote a simple program in which I have a bitwise operator which gives the signed value in java. But when I do so it returns a value higher different than the original value.
class bit
{
public static void main(String[] args)
{
int j=10;
System.out.println("jjjj"+~j);
}
}
Gives the output has:
-11. Which the expected output should be -9. What is the problem?
0000 1010 // = 10 i.e binary representation of 10
1111 0101 // = ~10 i.e inversion of bits
Negative numbers are stored in 2's complement form. Check this for details
0000 1011 // = 11 i.e binary 11
1111 0100 // inversion of bits
1111 0101 // 2's complement of 11 = -11
Thus,
~10 = -11
If we look at the binary for the number 10 we can see
0000 0000 0000 0000 0000 0000 0000 1010
Where the first 0 is the signing bit.
If we now flip the binary INCLUDING the signing bit, we get:
1111 1111 1111 1111 1111 1111 1111 0101
Which... if you consider that java uses signed integers, is -11.
If we get away from signed numbers for a second and just consider the value of a 4-byte unsigned integer that is ~10 we get the value of: 4294967285.
To convert a unsigned integer to a two's complement signed integer we subtract the value of 2^32 from the integer if its over 2^31 - 1.
2^32 - 4294967285 = -11

Java and unsigned values

I'm parsing unsigned bits from a DatagramSocket. I have a total of 24bits (or 3 bytes) coming in - they are: 1 unsigned 8bit integer followed by a 16bit signed integer. But java never stores anything more than a signed byte into a byte/byte array? When java takes in these values, do you lose that last 8th bit?
DatagramSocket serverSocket = new DatagramSocket(666);
byte[] receiveData = new byte[3]; <--Now at this moment I lost my 8th bit
System.out.println("Binary Server Listing on Port: "+port);
while (true)
{
DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
byte[] bArray = receivePacket.getData();
byte b = bArray[0];
}
Did I now lose this 8th bit since I turned it into a byte? Was it wrong I initialized a byte array of 3 bytes?
When java takes in these values, do you lose that last 8th bit?
No. You just end up with a negative value when it's set.
So to get a value between 0 and 255, it's simplest to use something like this:
int b = bArray[0] & 0xff;
First the byte is promoted to an int, which will sign extend it, leading to 25 leading 1 bits if the high bit is 1 in the original value. The & 0xff then gets rid of the first 24 bits again :)
No, you do not lose the 8th bit. But unfortunately, Java has two "features" which make it harder than reasonable to deal with such values:
all of its primitive types are signed;
when "unwrapping" a primitive type to another primitive type with a greater size (for instance, reading a byte to an int as is the case here), the sign bit of the "lower type" is expanded.
Which means that, for instance, if you read byte 0x80, which translates in binary as:
1000 0000
when you read it as an integer, you get:
1111 1111 1111 1111 1111 1111 1000 0000
^
This freaking bit gets expanded!
whereas you really wanted:
0000 0000 0000 0000 0000 0000 1000 0000
ie, integer value 128. You therefore MUST mask it:
int b = array[0] & 0xff;
1111 1111 1111 1111 1111 1111 1000 0000 <-- byte read as an int, your original value of b
0000 0000 0000 0000 0000 0000 1111 1111 <-- mask (0xff)
--------------------------------------- <-- anded, give
0000 0000 0000 0000 0000 0000 1000 0000 <-- expected result
Sad, but true.
More generally: if you wish to manipulate a lot of byte-oriented data, I suggest you have a look at ByteBuffer, it can help a lot. But unfortunately, this won't save you from bitmask manipulations, it is just that it makes it easier to read a given quantity of bytes as a time (as primitive types).
In Java, byte (as well as short, int and long) is only a signed numeric data types. However, this does not imply any loss of data when treating them as unsigned binary data. As your illustration shows, 10000000 is -128 as a signed decimal number. If you are dealing with binary data, just treat it as its binary form and you will be fine.

Categories

Resources