How does overflow work in java? - java

I've read about overflow, I know that "Overflow is when a number is so large that it will no longer fit within the data type, so the system “wraps around” to the next lowest value and counts up from there".
For example:
short s = (short)1921222; // Stored as 20678
In that example we started counting from -32768 (Short.MIN_VALUE), but when I try to prove in another integer data types, it doesn't seem work the same way...
byte b = (byte)400; // Stored as -112
The example above started counting from 0 that was the only way I found to get -112
I don't know if I am doing something wrong.

The Java Language Specification says:
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.
So, short and byte are both two's complement integers.
short is 16 bits, meaning it can hold 2^16 = 65536 different values. After the 65536th value, it overflows.
1921222 modulo 65536 is 20678 . This is less than 32768 (2^15, the turning point for the two's complement) so we keep a positive number.
byte is 8 bits, meaning it can hold 2^8 = 256 different values. This one overflows after the 256hth value.
400 modulo 256 is 144. This value is higher than 128, the turning point for the two's complement - hence it will be interpreted as a negative two's complement number.

The cast is truncating the number. (JLS)
0000 0001 1001 0000
loses the high byte to become
1001 0000
which is -112.

In java, byte primitive type is an 8 bit signed integer, that's why you got -112 from calling:
byte b = (byte) 400;
You can avoid that and get its un-signed value, by binary adding it with 0xFF like this:
int b = (byte) 400 & 0xFF;
For further details you can check:
Java Primitive data types Documentation.
How to Convert Int to Unsigned Byte and Back

In addition to the other answers, you can get to that answer by manual calculation as well.
In Java, the data type byte is an 8-bit, signed integer. So the values are in the interval [-128, 127]. If you have a value of 400 and you want to see the actual value for that type, you can subtract the size of the interval from that number until you reach a value that's inside the interval.
As I said, byte is 8 bit, so the size of the interval is 256. Subtract that from your initial value: 400 - 256 = 144. This value is still outside of the interval so you have to subtract again: 144 - 256 = -112. This value is now inside the interval and is indeed the value you've seen in your test.
The same is true for your first example: short is 16 bit and signed, so the interval is [-32768, 32767] with size 65536. Doing repeated subtraction from the value 1921222 will eventually give you the value 20678 as seen in your test.

Related

How to calculate the value of any primitive , who has out of range value

Example
byte x;
x=(byte)2355;
System.out.println(x);
so, how can I calculate the value which will be in x;
The 2355 literal value is interpreted as an int, which in Java is represented by the following 32 bits:
00000000000000000000100100110011
A byte has only 8 bits, so you lose the leading 24 bits:
00110011
Converted back to decimal, this leaves you with a value of 51.
You can find the bit sizes of the various primitive data types here. Also keep in mind that you need to take two's complement into account when dealing with signed primitives.
The range of the byte data type is -128 to 127 (inclusive). So if you want to deal with numbers outside that range then you can try casting the data type to short, int or long.

Converting Byte To Int,Short To Long...etc

I'm Learning Java and Don't know much about it.
What is the formula of converting from bigger data types to smaller ones?For example:
byte x=10;
long y=250;
x=(byte)y;
System.out.println(x);
after compiling it gives me -6.
and what uses does it have?
You are getting -6 because you made a long to a byte and the value in the long was too big for the byte. Try to convert a byte to a long!
A byte has a range from -128 to 127. A long goes from -2^63 to 2^63-1. You have gotten an overflow becuase of your converting in this way.
a byte can only store at most 256 values however because java is signed, a byte in java stores from -128 to 127.
Your value of 250 is over 127, so it wraps around to negative numbers.
What is the formula of converting smaller data types to bigger ones?
I think you had your variables backwards
y=x;
you don't need to cast since a byte will automatically be expanded into a long
The byte datatype is a signed 1-byte value that may take on values from -128 to 127. When you convert 250l to a byte, Java looks at the binary value 11111010 and shoves that in the byte, but because that first bit is a 1, it's interpreted as a negative value. If you run 11111010 through 2's-complement, you get 110 or 6, so 11111010 is -6.
Short answer: Converting larger datatypes to smaller one gives you hinky results. Don't do it without significant error-checking.

buff.getInt() & 0xffffffffL is an identity?

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.

Why byte b = (byte) 0xFF is equals to integer -1?

Why byte b = (byte) 0xFF is equal to integer -1?
Ex:
int value = byte b = (byte) 0xFF;
System.out.println(value);
it will print -1?
Bytes are signed in Java. In binary 0x00 is 0, 0x01 is 1 and so on but all 1s (ie 0xFF) is -1, 0xFE is -2 and so on. See Two's complement, which is the binary encoding mechanism used.
b is promoted to an int in determining which overload of system.out.println to call.
All bytes in Java are signed.
The signed byte 0xff represents the value -1. This is because Java uses two's complement to represent signed values. The signed byte 0xff represents -1 because its most significant bit is 1 (so therefore it represents a negative value) and its value is -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 = -1.
perhaps your confusion comes from why (byte)0xFF is somehow equal to (int)0xFFFFFFFF. What's happening here is the promotion from smaller to larger signed types causes the smaller value to be sign extended, whereby the most significant bit is copied to all of the new bits of the promoted value. an unsigned type will not become sign-extended, they get zero extended, the new bits will always be zero.
If it helps you to swallow it, think of it this way, every integer of any size also has some 'phantom' bits that are too significant to be represented. they are there, just not stored in the variable. a negative number has those bits nonzero, and positive numbers have all zeros for phantom bits when you promote a smaller value to a larger one, those phantom bits become real bits.
If you are using a signed int then 0xFF = -1 due to the 2-complement.
This wiki article explains it well, see the table on the right:
http://en.wikipedia.org/wiki/Two%27s_complement
Because Java (and most languages) represent negative integer values using two's-complement math. In two's-complement, 0xFF (11111111) represents (in a signed int) the value -1.
reduced modulo
byte = 256
0xff = 255
255 / 256 -> remainder 255
So 255 - 256 = -1
Simple Logic
Cheers
Its not just Java that does 2's complement math. That is the way every microprocessor and DSP that I can think of does math. So, its the way every programming language represents it.

When casting a small integer type to a wider one, is it safe to rely on &ing with a mask to remove the sign?

I have code that stores values in the range 0..255 in a Java byte to save space in large data collections (10^9 records spread over a couple hundred arrays).
Without additional measures on recovery, the larger values are interpreted as being negative (because the Java integer types use two's complement representation).
I got this helpful hint from starblue in response to a related question, and I'm wondering if this technique is safe to rely on:
int iOriginal = 128, iRestore;
byte bStore = (byte) iOriginal; // reading this value directly would yield -128
iRestore = 0xff & bStore;
Yes, it's safe, indeed it's the most effective way of converting a byte into an (effectively) unsigned integer.
The byte half of the and operation will be sign-extended to an int, i.e. whatever was in bit 7 will be expanded into bits 8-31.
Masking off the bottom eight bits (i.e. & 0xff) then gives you an int that has zero in every bit from 8 - 31, and must therefore be in the range 0 ... 255.
See a related answer I gave here.

Categories