Weird Result Incrementing a Short Beyond its Maximum Value - java

When i execute this code it gives value of s as -7616.
Why so? Is this because loss of data while converting it to short from int or something else?
public static void main(String[] args) {
// TODO code application logic here
short s=0;
int x=123456;
int i=8;
s +=x;
System.out.println(s);
}

You are simply overflowing the maximum value of a short :
short: The short data type is a 16-bit signed two's complement
integer. It has a minimum value of -32,768 and a maximum value of
32,767 (inclusive). As with byte, the same guidelines apply: you can
use a short to save memory in large arrays, in situations where the
memory savings actually matters.
What happens when there is such overflow is equivalent to this algorithm :
/** Returns an integer which is equal to the short obtained by the ((short) n) conversion */
public static int int2short(int n) {
int sign = n > 0 ? 1 : -1;
int increment = sign * (Short.MAX_VALUE - Short.MIN_VALUE + 1);
for ( ; n > Short.MAX_VALUE || n < Short.MIN_VALUE ; n -= increment);
return n;
}

Good question! It made me think about things I haven't thought about in a long while and I had to brush up on a couple of concepts. Thanks for helping me knock the rust off my brain.
For me this type of question is best visualized in binary (for reasons that will quickly become apparent):
Your original number (forgive the leading zeroes; I like groups of 4):
0001 1110 0010 0100 0000
A short, however, is a 16-bit signed two's complement integer according to the Java Language Specification (JLS) section 4.2. Assigning the integer value 123456 to a short is known as a "narrowing primitive conversion" which is covered in JLS 5.1.3. Specifically, 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."
Discarding all but the lowest 16 bits leaves us with:
1110 0010 0100 0000
In an unsigned integer this value is 57,290, however the short integer is a signed two's complement integer. The 1 in the leftmost digit indicates a negative number; to get the value of the number you must invert the bits and add 1:
Original:
1110 0010 0100 0000
Invert the bits:
0001 1101 1011 1111
Add 1:
0001 1101 1100 0000
Convert that to decimal and add the negative sign to get -7,616.
Thanks again for asking the question. It's okay to not know something so keep asking and learning. I had fun answering...I like diving into the JLS, crazy, I know!

Incrementing a short beyond its maximum value is called overflow. When overflow occurs, the value becomes the minimum value of the type, and start counting up again.
So here's how you got -7616 from trying to store 0+123456 in a short:
0 --> 32767
-32768 --> 32767
-32768 --> -7616
In other words,
32768+ 32768+ 32768+ (32768 -7616) = 123456

The compound assignment operator += (all of them really) cast their result
A compound assignment expression of the form E1 op= E2 is equivalent
to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1
is evaluated only once.
So
s += x;
becomes
s = (short) (s + x);
Now, because s is a short and x is an int, binary numeric promotion is performed on the short value before the addition is applied. The short value is converted to an int (which is not a problem).
s = (short) (8 + 123456)
s = (short) (123464)
The cast applies a narrowing primitive conversion which
[...] may lose information about the
overall magnitude of a numeric value and may also lose precision and
range.
That's what happens
s = -7608

Related

Explanation about a result

Hi i hav a little problem about some code that i can't give an explanation about the result i have.
//what happens?
public static void what() {
int number = 2147483647;
System.out.println(number + 33);
}
//Here is my solution for the probleme
public static void what() {
long number = 2147483647;
System.out.println(number + 33);
}
The first code with the int number as variable gives me -2147483616 as result. So when i change the int to long i get the good result expected. So question is who can help me give and explanation of why int number + 33 = -2147483616
Java integers are based on 32 Bits. The first bit is kept for the sign (+ = 0 / - = 1).
So 2147483647 equals 01111111 11111111 11111111 11111111.
Adding more will force the value to turn to negative because the first bit is turned into a 1.
10000000 00000000 00000000 00000000 equals -2147483648.
The remaining 32 you are adding to -2147483648 brings you to your result of -2147483616.
The primitive int type has a maximum value of 2147483647, which is what you are setting number to. When anything is added to this value the int type cannot represent it correctly and 'wraps' around, becoming a negative number.
The maximum value of the long type is 9223372036854775807 so the second code snippet works fine because long can hold that value with no problem.
You have reached the maximum of the primitive type int (2147483647).
If int overflows, it goes back to the minimum value (-2147483648) and continues from there.
Consider the calculation of the second snippet, and what the result actually means.
long number = 2147483647;
number += 33;
The result in decimal is 2147483680, in hexadecimal (which more easily shows what the value means) it is 0x80000020.
For the first snippet, the result in hexacimal is also 0x80000020, because the result of arithmetic with the int type is the low 32 bits of the "full" result. What's different is the interpretation: as an int, 0x80000020 has the top bit set, and the top bit has a "weight" of -231, so this result is interpreted as -231 + 32 (a negative number). As a long, the 32nd bit is just a normal bit with a weight of 231 and the result is interpreted as 231 + 32.
The primitive type int is a 32-bit integer that can only store from -2^31 to 2^31 - 1 whereas long is a 64-bit integer so it can obviously store a much larger value.
When we calculate the capacity of int, it goes from -2147483648 to 2147483647.
Now you are wondering.. why is it that when the number exceeds the limit and I add 33 to it, it will become -2147483616?
This is because the data sort of "reset" after exceeding its limit.
Thus, 2147483647 + 1 will lead to -2147483648. From here, you can see that -2147483648 + 32 will lead to the value in your example which is -2147483616.
Some extra info below:
Unless you really need to use a number that is greater than the capacity of int, always use int as it takes up less memory space.
Also, should your number be bigger than long, consider using BigInteger.
Hope this helps!

Casting of byte data type

Please explain how below code is working, as we know byte data type in java allows a range from -128 to 127.
My code snippet is:
public class DataTypes {
public static void main(String args[]){
byte b = (byte)140;
System.out.println(b);
}
}
Output: -116
A Byte will have 8 bits in its memory space. Using this space it can hold 256 values. This will span from -128 to 127 including 0. To support this spanning, a Byte value will be represented in binary format using two's compliment method. The MSB (Most Significant Bit) will determine the sign (0 - positive & 1 - negative) of the value.
If we consider the case of 140, it will be clear if we represent 140 in binary format which is 1000 1100. Remember the MSB will determine the sign and a 1 means the number is a negative value and 0 means it's a positive value. In this case we have a 1 making it a negative number.
If we apply reverse process to this two's compliment, we will first get 0111 0011 by inverting all the 1s to 0s and 0s to 1s. Then by adding 1, we get 0111 0100 which is equal to 116 in decimal format. But the MSB said it's a negative value, hence -116
Maybe this will help explain. The uppermost bit determines the 'sign'(positive or negative) of a variable. Since Java does not have an explicit 'unsigned' integer form the best you can do is apply a 'bitwise' operation to the item in advance of displaying it force it to be considered 'unsigned'...or you can display it using it's hex format which is inherently unsigned.
public class DataTypes {
public static void main(String args[]){
byte b = (byte)140;
System.out.println("hex value = "+String.format("0x%02X",b)+"\n");
System.out.println("dec value = "+String.format("%d",(b & 0xff))+"\n");
}
}
and a result of
hex value = 0x8C
dec value = 140
140 is a int. It is converted to a byte, according to the Java Language Specification, section 5.1.3, as follows:
A narrowing conversion of a signed integer to an integral type T simply discards all but the n lowest order bits
The lowest 8 bits of the int with value 140 are 10001100, which is the correct value for the byte, but which is negative since its highest bit, the sign bit, is 1.
I think, when you cast the integer (140) to byte, the integer value converted into unsigned byte then b variable value is converted into signed byte. The number 140 considered as unsigned value because the number has not sign value indicator (+ or -)
Note about unsigned byte (the right value is representation (in file byte(s)) of left value):
0-127 = 0-127
(-128) - (-1) = 128 - 255

BigInteger.intValue()>1 giving incorrect boolean

I am trying to convert a BigInteger number into binary. I use a while loop to reduce the BigInteger until it is equal to 1, taking the remainder as the loop runs.
The conditional for the loop is: (decimalNum.intValue()>1).
But the program only goes through the loop once and then thinks that the BigInteger is less/equal to 1 while in reality it is around 55193474935748.
Why is this happening?
("inBinary" is an ArrayList to hold the remainders from the loop.)
Here is the while loop:
while (decimalNum.intValue()>1){
inBinary.add(0, decimalNum.mod(new BigInteger("2")).intValue()); //Get remainder (0 or 1)
decimalNum = decimalNum.divide(new BigInteger("2")); //Reduce decimalNum
}
55,193,474,935,748 doesn't fit into an int: the largest int value is 231 - 1, i.e. 2,147,483,647, which is much smaller. So you get an integer overflow.
This is explained in the javadoc, BTW:
Converts this BigInteger to an int. This conversion is analogous to a narrowing primitive conversion from long to int as defined in section 5.1.3 of The Java™ Language Specification: if this BigInteger is too big to fit in an int, only the low-order 32 bits are returned. Note that this conversion can lose information about the overall magnitude of the BigInteger value as well as return a result with the opposite sign.
If you want to compare a BigInteger to 1, then use
decimalNum.compareTo(BigInteger.ONE) > 0
To get the binary string value of your BigInteger, you could just do
bigInteger.toString(2);
EDIT : As mentionned in the comments by #VinceEmigh, converting BigInteger to int might lead to overflow.

Why Integer.toBinaryString returns 32 bits if the argument is negative?

I was just messing around the Integer.toBinaryString(int) method.
When I pass a positive number say 7, it outputs 111 but when I pass negative 7, it outputs 11111111111111111111111111111001. I understand that Java uses 2's complement to represent negative numbers, but why 32 bits (I also know that an int is 32 bits long but doesn't fit in the answer)?
Ok so I did some digging...
I wrote up a little program probably close to what you did.
public class IntTest {
public static void main(String[] args){
int a = 7;
int b = -7;
System.out.println(Integer.toBinaryString(a));
System.out.println(Integer.toBinaryString(b));
}
}
My output:
111
11111111111111111111111111111001
So 111 is the same if it had 29 "0"s in front of it. That is just wasted space and time.
If we follow the instructions for twos compliment from this guy here you can see that what we must do is flip the bits ( zeros become ones and ones become zeros ) then we add 1 to the result.
So 0000 0000 0000 0000 0000 0000 0000 0111 becomes 1111 1111 1111 1111 1111 1111 1111 1001
The ones can not be thrown out because they are significant in the twos compliment representation. This is why you have 32 bits in the second case.
Hope this helps! -- Code on!!!
Because Java ints are signed 32-bit. If you use a negative number the first bit must be 1.
System.out.println(Integer.toBinaryString(0));
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE)); // 31 bits
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE - 1)); // 31 bits
System.out.println(Integer.toBinaryString(Integer.MAX_VALUE + 1)); // 32 bits
System.out.println(Integer.SIZE);
Output is
0
1111111111111111111111111111111
1111111111111111111111111111110
10000000000000000000000000000000
32
Note that Integer.MAX_VALUE + 1 is Integer.MIN_VALUE (and it has an extra bit).
It outputs the smallest number it can, stripping leading zeroes. In the case of a negative number, the first bit of the 32 bits is a sign bit (i.e. -1 is 1, 30 zeros, and another 1). So, since it has to output the sign bit (it's significant), it outputs all 32 bits.
Here's a cool semi-relevant example of using the sign bit and the unsigned shift operator :). If you do:
int x = {positive_value};
int y = {other_positive_value};
int avg = (x + y) >>> 1;
The x and y integers can both use the first 31 bits since the 32nd bit is the sign. This way, if they overflow, they overflow into the sign bit and make the value negative. The >>> is an unsigned shift operator which shifts the value back one bit to the right which is effectively a divide by two and floor operation, which gives a proper average.
If you, on the other hand, had done:
int x = {value};
int y = {other_value};
int avg = (x + y) / 2;
And you had gotten an overflow, you would end up with the wrong result as you'd be dividing a negative value by 2.

Bijection between Java float and integer keeping order

Both int and float in Java are 32 bits size values. Is it possible to program a pair of functions
int toInt(float f);
float toFloat(int n);
such that if f1 and f2 are arbitrary float non-NaN values and i1 and i2 are arbitraty int values:
f1 < f2 if and only if toInt(f1) < toInt(f2)
f1 > f2 if and only if toInt(f1) > toInt(f2)
f1 == f2 if and only if toInt(f1) == toInt(f2)
toInt(toFloat(i1) == i1
toFloat(toInt(f1)) == f1
Edit: I have edited the question to exclude NaN values for float, thanks to the answers clarifying what happens with those.
Yes. IEEE floats and doubles are arranged in such a way that you can compare them by doing an unsigned comparison of the raw binary representation. The function to convert from float to raw integer and back are java.lang.Float.floatToIntBits and java.lang.Float.intBitsToFloat. These functions are processor intrinsics, so they have an extremely low cost.
The same is true for longs and doubles. Here the conversion functions are java.lang.Double.doubleToLongBits and java.lang.Double.longBitsToDouble.
Note that if you want to use the normal signed comparison for your integers, you have to do some additional transformation in addition to the conversion to integer.
The only exception to this rule is NaN, which does not permit a total ordering anyway.
You can use
int n = Float.floatToRawIntBits(f);
float f2 = Float.intBitToFloat(n);
int n2 = Float.floatToRawIntBits(f2);
assert n == n2; // always
assert f == f2 || Float.isNaN(f);
The raw bits as a int have the same sort order as the original float with the exception of the NaN values which are not comparable as a float value have a value as an int
Note: there is multiple values for NaN which are not equal to each other as float
No you cannot
There are 2^32 possible int values, all of which are distinct.
However, thee are less than 2^32 floats; ie. 7FF0000000000001 to 7FF7FFFFFFFFFFFF represent NaN's,
There fore, you have more ints than floats an cannot distinctly map them to each other as toFloat(i1) would not be cable of producing a distinct float for every int
I see what you're saying. At first I had a different interpretation of your question. As everyone else has mention: yes. Use the articles described here and here to explain why we should use the methods described by #Peter Lawrey in order to compare the underlying bit pattern between ints and floats
The answer from Rüdiger Klaehn gives the normal case, but it lacks some details. The bijection exits only in the domain of nice and clean floats.
Notice : representation of an IEEE float is sign_bit(1 bit) exponent(8 bits) sinificand(23 bits) and the value is : (-1)<sup>sign</sup> * 2<sup>exp</sup> * significand in clean cases. In fact, the 23 bits represent the fractional part of the actual significand, the integer part being 1.
All is fine for 0 < exp < 255 (which correspond to normal not null floats ) as an unsigned byte and in that domain you have a bijection.
For exp == 255 you have the infinite values is significand == 0 and all the NaN for significand != 0 - ok, you explicitely excluded them.
But for exp == 0 there are still weird things : when significand == 0 you have +0 and -0. I am not sure if they are considered equal. If anybody knows, please feel free to edit the post. But as integer values, they will of course be different.
And when exp == 0 and significand != 0 you find denormalized numbers ... which while not being equal will be converted to either 0 of the littlest number not being 0.
So if you want a bijection only use normal numbers having 0 < exp < 255< and avoid NaN, infinite, 0 and denormal numbers where things are weird.
References :
IEEE floating point
Single-precision floating-point format
Denormal number
f1 == f2
is impossible, see this answer for more info. You will need to include a delta if you actually want to APPROXIMATE your equality-check.

Categories