Arithmetic with byte in Java - java

I know that the byte and the short data types are not given 2's complement treatment in Java. What I mean by this statement of mine is demonstrated in the example below:
byte b1 = 0xFF; //error, 255 is outside the range of byte
byte b2 = 0b1100; //12 is stored, and not -4
Now, take the following example:
byte b3 = 0;
b3 += 0xFF;
System.out.println(b3); //prints -1 on the console
Should the 2nd line in the above example have thrown an error, single 0xFF is 255 and is outside the byte range?
Also, what this unfair game with byte and short? I mean, why not interpret them using the 2's complement system, just like int and long?

They are 2's complement - no idea where you got that from (but it's wrong). This:
byte b1 = 0xFF;
does not work because it is indeed outside the range of a byte. This however:
byte b3 = 0;
b3 += 0xFF;
because += is done on a wider range of int, you assign it to byte, which takes the last 8 bits, which happen to be -1.

Rather than trying to work this out by attempting to draw logical inferences, you should read the Java Language Specification:
Point 1. byte and short are signed types.
"The values of the integral types are integers in the following ranges:
For byte, from -128 to 127, inclusive
For short, from -32768 to 32767, inclusive" Source JLS 4.2.1
Point 2. The signed integral types are 2's complement.
"The integral types are byte, short, int, and long, whose values are 8-bit, 16-bit, 32-bit and 64-bit signed two's-complement integers, respectively, and char, whose values are 16-bit unsigned integers representing UTF-16 code units (§3.1)." Source JLS 4.2
Point 3. You can't assign an int variable to a byte variable.
If the type of the right-hand operand is not assignment compatible with the type of the variable (§5.2), then a compile-time error occurs. Source JLS 15.26.1
Point 4. You can assign an int compile-time constant expression to a byte variable provided that the value of the expression is in the range of byte.
"In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:
A narrowing primitive conversion may be used if the variable is of type byte, short, or char, and the value of the constant expression is representable in the type of the variable." Source JLS 5.2
Point 5. b3 += 0xFF is equivalent to b3 = (byte)(b3 + 0xFF)
Source JLS 15.26.2
Point 6. There are no byte or short literals.
Source JLS 3.10.1

if you want to convert -minus values java 8 comes with utility methods to support unsigned operations
byte b1 = (byte) 0xFF;
Byte.toUnsignedInt(b1); // this method will return 255

Related

I have to cast the first two octets from int to byte but not the other octets. Why?

byte[] ipAddr = new byte[] {(byte) 142, (byte) 250,68,46};
I am getting to know the various java net functions and I have to cast the first two octets to a byte in order for it to compile.
Otherwise I get this error
java: incompatible types: possible lossy conversion from int to byte
Any idea why I have to cast specifically the first octets and not all? Why does java take it as an int instead of a byte?
In java, bytes are 8-bit signed datatypes, so the value ranges from -128 to +127. Your first two values are greater than the maximum so you need to manually allow the conversion (by casting, in your case).
Those two octets just happen to be larger than the maximum value allowed in a byte which is 127 (2^7-1). Any value greater than 127 will have to be cast (or dealt with more carefully) and you'll lose data in a straight cast due to the size difference. See here for more: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html#:~:text=Primitive%20values%20do%20not%20share,value%20of%20127%20(inclusive).
#Dennis is on the right track, but the explanation is a bit more complicated than that.
Normally, an int valued expression cannot be assigned to a byte variable without a cast.
When the int valued expression is a constant expression, AND when the value of the expression is within the range of byte, then the assignment to a byte variable is allowed without a cast.
However, this only applies in assignment contexts, and only for constant expressions that satisfy the JLS definition.
In your example, the integer literals are all constant expressions, but the first two are not in the required range for lossless assignment ot a byte; i.e -128 to +127.

In java, how come method read() from FileInputStream works does not throw " incompatible types: possible lossy conversion"?

I am currently going through Java I/O tutorial and having hard time understanding the read() method of FileInputStream class. I know that per documantion that read() method reads "byte" of data from stream and returns an integer representing the byte (between 0 and 256) or -1 if it reaches the end of file.
Byte in java has a range between -128 and 127, so, how come when I edit xanadu.txt and add ASCI symbol "ƒ" (which has a decimal value of 131), java does not complain by throwing an error that value 131 is out of range defined by byte (-128 and 127)? When I try to test this using literals I get two different results.
The following works:
byte b = 120;
int c = b;
System.out.println((char)c);
Output: x
But this does NOT work (even though it works when added to xanadu.txt):
byte b = 131;
int c = b;
System.out.println((char)c);
Output: error: incompatible types: possible lossy conversion from int to byte
byte b = 131;
I tried explicitly casting using byte: (how is this possible?)
byte b = (byte)131;
int c = b;
System.out.println((char)c);
Output: テ
I am total newbie when it comes to I/O streams, somebody please help me understand it.
EDIT: Turns out my knowledge on concepts of type casting was lacking, specifically in understanding the difference between "Widening" and "Narrowing". Reading up more about these concepts helped me understand why explicit (aka narrowing) casting works.
Allow me to explain: Look at the 3rd code block where I am explicitly casting the literal '131' to type of byte. If we are to convert the literal 131 into binary form of 32-bit signed 2's complement integer, we will get 00000000 00000000 00000000 10000011 which is 32-bits or 4 bytes. Recall that Java data type 'byte' can only hold 8-bit signed 2's complement integer, so, 131 is out of range and thus we get error "possible lossy conversion from int to byte". But, when we explicitly cast it to byte, we are 'chopping off' or correct term would be 'narrowing' the binary down to 8 bit integer. So, when we do that, then the resulting binary is 10000011 which is -125 in decimal value. Since -125 is in range of -128 and 127, byte has no issues accepting and storing it. Now when I try to story the value of byte in int c, implicit or "widening" casting takes place, where -125 in binary form of 8-bit 10000011 is converted into equivalent -125 in binary form of 32-bit 11111111 11111111 11111111 10000011. Finally, system.out is trying to output the value of (char)c which is another explicit or "narrowing" casting where its trying to shrink from 32-bit signed to 16-bit unsigned. When casting is complete, we get 11111111 10000011 in binary form. Now, when this binary is converted into character form by java, it returns テ.
I can conclude by saying that it helps converting everything into binary form and go from there. But make sure you understand encoding and 2's complement
I don't know where you got the value 131 from, but as far as I am concerned, LATIN SMALL LETTER F WITH HOOK (ƒ) is not in the original ASCII character set, but in extended ASCII, with a decimal value of 159. See here. It is also encoded in UTF-16 (how Java chars are encoded) as hex 192 (decimal value 402).
First, ensure that your text files are encoded in extended ASCII, and not UTF-8 (which is the most likely encoding). Then you can use a FileInputStream to read the file, and you will get 159.
Note that 159 is outside the range of the the Java byte type. This is fine, because read returns an int. If the text file is encoded in UTF-8 however, ƒ is encoded in 2 bytes, so read will be reading one byte at a time.
Your second code block doesn't work because as you said, byte goes from -128 to 127, so 131 obviously doesn't fit.
Your third code block forces 131 into a byte, which causes overflow and the value "wraps back around" to -125. b and c are both -125. When you cast this to a char it becomes 65411 because this conversion involves padding the whole number to 16-bits first, then treating it as an unsigned integer.
The reason why this all works when you use FileInputStream.read instead of doing these conversions yourself, is because read actually returns an int, not a byte. It's just that the int it returns will always be in the range -1 ~ 255. This is why we say "read returns a byte", but its actual return type is int.
byte b = 131; // this is 8 bits type, but >8 bits value
int c = b; // this is 32 bits type
System.out.println((char)c); // this is 16 bits type
Output: error: incompatible types: possible lossy conversion from int to byte
byte b = 131;
The two-complement encoding of 131 is:
2^7+2^1+2^0
^^^
sign bit
131 won't fit in a signed byte without an overflow in the two complement representation that is used for signed types. The highest bit=sign bit is set which gets extended when casting from byte to int.
The Java compiler notices that 131 won't fit properly in a byte which leads to the error.

java - Why is 0x000F stored as unsigned?

I was reading through examples trying to understand how to convert signed bytes to unsigned integer counter parts.
The most popular method that I have come across is:
a & 0xFF
Where a is the signed byte.
My question is why is 0xFF stored as unsigned? Are all hex values stored as unsigned? If so why?
And how does "and"-ing turn off the sign bit in the sign integer?
It would be great if someone could break down the process step by step.
You probably saw this in code that converted a byte to an integer, where they wanted to treat the byte as an unsigned value in the range 0-255. It does not apply to integers in general. If you want to make an integer a "unsigned", you can do:
int unsignedA = a & 0x7FFFFFFF;
This will ensure that unsignedA is positive - but it does that by chopping off the high bit, so for example if a was -1, then unsignedA is Integer.MAX_VALUE.
There is no way to turn a 32-bit signed Java integer into a 32-bit unsigned Java integer because there is no datatype in Java for a 32-bit unsigned integer. The only unsigned integral datatype in Java is 16 bits long: char.
If you want to store a 32-bit unsigned integral value in Java, you need to store it in a long:
long unsignedA = a & 0xFFFFFFFFL;
To elaborate on Erwin's answer about converting a byte to an integer: In Java, byte is a signed integer type. That means it has values in the range -128 to 127. If you say:
byte a;
int b;
a = -64;
b = a;
The language will preserve the value; that is, it will set b to -64.
But if you really want to convert your byte to a value from 0 to 255 (which I guess you call the "unsigned counterpart" of the byte value), you can use a & 0xFF. Here's what happens:
Java does not do arithmetic directly on byte or short types. So when it sees a & 0xFF, it converts both sides to an int. The hex value of a, which is a byte, looks like
a = C0
When it's converted to a 32-bit integer, the value (-64) has to be preserved, so that means the 32-bit integer has to have 1 bits in the upper 24 bits. Thus:
a = C0
(int)a = FFFFFFC0
But then you "and" it with 0xFF:
a = C0
(int)a = FFFFFFC0
& 000000FF
--------
a & FF = 000000C0
And the result is an integer in the range 0 to 255.
In Java, literals (1, 0x2A, etc) are positive unless you explicitly indicate that they are negative. It's how we intuitively write numbers.
This previous question answers you question about converting to unsigned. Understanding Java unsigned numbers

Casting of primitives type

I am beginner in Java. I cannot understand this line even after a long try.
byte num=(byte)135;
this line gives result -121 why it is in signed number ?
Can any one elaborate it ?
In Java, bytes are always signed, and they are in the range -128 to 127. When the int literal 135 is downcasted to a byte, the result is a negative number because the 8th bit is set.
1000 0111
Specifically, 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.
When you cast an int literal such as 135 to a byte, that is a narrowing primitive conversion.

Byte comparision in java

what actually happens here, when byte - byte is occur?
suppose,
byteResult = byte1 - byte2;
where,
byte1 = 0xff;
byte2 = 0x01;
then,
is byte1 turns into integer with value 255 and and byte2 1 and byteResult assigned to 254 then converted into byte with 0xFE? And then the if condition is checked? Please a detail help will be very helpful for me. Sorry if my question is ambiguous!
Here, I found something but not what exactly I want.
Java Byte comparison
No the byte will not be converted into an int.
From the JLS 5.2 Assignment Conversion:
In addition, if the expression is a constant expression (§15.28) of
type byte, short, char, or int: - A narrowing primitive conversion may
be used if the type of the variable is byte, short, or char, and the
value of the constant expression is representable in the type of the
variable.
Also check subtracting 2 bytes makes int?
This is a basic premise of Java programming. All integers are of type int unless specifically cast to another type. Therefore, any arithmetic done with integers automatically 'promotes' all the operands to int type from the narrower type (byte, short), and the result of arithmetic with int operands is always int. (I think I've beaten that to death now).
If you want the short result of arithmetic with two bytes, do this:
short result = (short) (byte1 - byte2)
This explicit cast makes it the programmer's responsibility for throwing away the extra bits if they aren't needed. Otherwise, integer arithmetic is done in 32 bits.

Categories