long x = (long)(2147483649);
Why is this wrong? Why do I have to use L and F for floats and longs but I can use (byte) for example?
Your problem is technically related to Java specification. see https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10
The largest decimal literal of type int is 2147483648 (2^31).
All decimal literals from 0 to 2147483647 may appear anywhere an int
literal may appear. The decimal literal 2147483648 may appear only as
the operand of the unary minus operator - (§15.15.4).
It is a compile-time error if the decimal literal 2147483648 appears
anywhere other than as the operand of the unary minus operator; or if
a decimal literal of type int is larger than 2147483648 (2^31).
Why?
because, as other people said before, in just 32 bits you can only represent from -2147483648 to 2147483647 (2^32 different numbers). So, before promoting it to long the compiler needs to be able to represent it, but it cannot. Indeed, java specification indicates that this is a compile-time error.
The largest decimal literal of type int is 2147483648 (2^31).
Just adding an L/l at the end of the literal (2147483649L), specifies that it is a literal of type long, and now it can contain bigger numbers.
An integer literal is of type long if it is suffixed with an ASCII
letter L or l (ell); otherwise it is of type int (§4.2.1). The suffix
L is preferred, because the letter l (ell) is often hard to
distinguish from the digit 1 (one).
So there are only two type of literal numbers in decimal format (for integer numbers).
You can, but not this int. The number you are trying to cast is 80000001 in hex. This number is not a valid int.
This works because 2147483647 is 7fffffff in hex - a perfgectly acceptable int.
long x = (long)(2147483647);
2147483649 = Integer.MAX_VALUE + 2
Can't fit that into an int variable.
try long x = 2147483649L;
Integer range is defined between Integer.MIN_VALUE and Integer.MAX_VALUE (-2147483648 and 2147483647)
your number 2147483649 is out of that range, therefore can not event be a valid integer
your compiler should even complains like:
Related
In the following program , I am assigning a integer data type to a char data type.
public static void main(String args[]) {
char ch =65;
System.out.println(ch);
}
I know the fact that int occupies 32 bits and char occupies 16 bits . With that knowledge , I was expecting the compiler throw an error of some message "Attempt to convert a data of higher size to a lower size ".
Why is the compiler not complaining and internally converting and printing the output as 'A' (I understand the fact that it is the ASCII equivalent of 65, my question is only related to the size of data types) ?
The compiler does in fact validate the range. That is working because int 65 is within the expected range.
The following won't compile:
char c = (int)Character.MAX_VALUE + 1
char c = 65536
And this will, just like your assignment:
char c = 65535 //Within range
When the value is not a constant at compile time, though, there's need for cast:
private static void charRange(int i) {
char c = (char) i;
System.out.println(" --> " + (int) c);
}
charRange(65);
charRange(Character.MAX_VALUE + 20);
And the check doesn't happen (making room for overflow)
--> 65
--> 19
There is an exception to Java's general rule about converting an int to a char. If the int is a compile time constant expression (e.g. a literal) AND the int value of the expression is within the required range (0 to 65535), then it is legal to assign the int expression to a char.
Intuitively, for a compile-time constant expression, the compiler knows if the expression value can be assigned without loss of information.
This is covered by JLS 5.2 ... in the paragraph that starts "In addition, if the expression is a constant expression ..."
Programing languages like Java or C# come with a set of integer primitive types. Each type has a well-defined range in the form of [min value, max value]. This values are stored in a fixed sequence of bits from most significant bit to the least one.
For example, let the decimal number 123456 be represented for the next 32 bit sequence
0000000000000011110001001000000
When you attempt to convert a 32-bit number type to a 16-bit one, the compiler copies the 16 least significant bits (or the last 16 bits) then 123456 number is wrapped to
1110001001000000
And if you convert this binary number to decimal it is 57920. As you realize, the 32-bit number cant fit into a 16-bit sequence, and the original sequence was arbitrarily wrapped. This is known as integer overflow, and also happens when you add or multiply 2 number which result is out of bounds of the integer type range.
As programmer, you should be aware of overflow, and react to this to avoid a program failure. You also should read further details about signed integer representation.
Consider the following code:
int x1 = 0b1111_1111_1111_1111_1111_1111_1111_111; // binary for 2147483647
System.out.println(x1); // prints 2147483647
int x2 = 2147483648; // The literal 2147483648 of type int is out of range
// x3 is binary representation for 2147483648
int x3 = 0b1000_0000_0000_0000_0000_0000_0000_0000; // accepted without any compile errors
System.out.println(x3); // prints -2147483648
// x4 is binary representation for 4294967295
int x4 = 0b1111_1111_1111_1111_1111_1111_1111_1111; // long value: 4294967295
System.out.println(x4); // prints -1
int x5 = 0b1111_1111_1111_1111_1111_1111_1111_1111_1; // The literal 0b1111_1111_1111_1111_1111_1111_1111_1111_1 of type int is out of range
The Integer.MAX_VALUE is 2147483647 and compiler accepts any int in that range, and throws an error when this value goes beyond 2147483647. However, the int x3(int: -1, long: 2147483648) and x4(int: -1, long: 4294967295) in above snippet is accepted without any errors but throws errors in case of x5.
First question: Why the compiler did not complain about the range of x3?
Second question: If the value of x3 and x4 is accepted without any errors, why does it throw errors in case of x5?
TL;DR
Why the compiler did not complain about the range of x3?
Because it fits in 32 bits, and the Java Language Specification (JLS) says that literal is valid when it does.
If the value of x3 and x4 is accepted without any errors, why does it throw errors in case of x5?
Because it doesn't fits in 32 bits, given that it is 33 bits long.
Comment on Code Style
You should insert the _ separators in a binary literal where the nibble boundaries are, so instead of 0b1111_1111_1111_1111_1111_1111_1111_111 it should be 0b111_1111_1111_1111_1111_1111_1111_1111.
That then correctly represents that it is the first nibble that's missing a digit. It also makes it directly comparable to the hex representation, e.g. 0x7F_FF_FF_FF.
Your way of inserting _ is very confusing.
Long answer
In Java, numbers formatted using Integer.toBinaryString(int i), Integer.toHexString(int i), and Integer.toOctalString(int i) are formatted as unsigned numbers.
This fits the Java integer literal syntax as defined by JLS 3.10.1. Integer Literals, which states:
It is a compile-time error if a hexadecimal, octal, or binary int literal does not fit in 32 bits.
Since 0b1000_0000_0000_0000_0000_0000_0000_0000 and 0b1111_1111_1111_1111_1111_1111_1111_1111, as well as their hex counterparts 0x80_00_00_00 and 0xFF_FF_FF_FF, all fit in 32 bits, they are valid int literals.
If you print them using the methods above, they match the literal, even though they would all print -1 if printed as a (signed) decimal:
System.out.println(Integer.toBinaryString(0b1111_1111_1111_1111_1111_1111_1111_1111));
System.out.println(Integer.toOctalString(037_777_777_777));
System.out.println(Integer.toHexString(0xFF_FF_FF_FF));
11111111111111111111111111111111
37777777777
ffffffff
The first bit for both x3 and x4 is 1, hence they are treated as negative numbers. They are both declared as 32 bit numbers, so they fit an int data type and the compiler doesn't complain. x5 gives error because you are attempting to assign 33 bits to a 32 bit data type, so it overflows.
The primitive int is a 32 bit number, with the leading bit being the sign of the integer, so when you used int for 2147483648 you caused an overflow error. To fix your problem, use the primitives double or long for higher values.
The Java Language Specification has the answer.
4.2. Primitive Types and Values
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
So int is a 32-bit two's-complement. (Also read the great answer about: What is “2's Complement”?)
And in 3.10.1. Integer Literals it shows:
The largest positive hexadecimal, octal, and binary literals of type int - each of which represents the decimal value 2147483647 (2^31-1) - are respectively:
0x7fff_ffff,
0177_7777_7777, and
0b0111_1111_1111_1111_1111_1111_1111_1111
The most negative hexadecimal, octal, and binary literals of type int - each of which represents the decimal value -2147483648 (-2^31) - are respectively:
0x8000_0000,
0200_0000_0000, and
0b1000_0000_0000_0000_0000_0000_0000_0000
The following hexadecimal, octal, and binary literals represent the decimal value -1:
0xffff_ffff,
0377_7777_7777, and
0b1111_1111_1111_1111_1111_1111_1111_1111
It is a compile-time error if a hexadecimal, octal, or binary int literal does not fit in 32 bits.
As per JLS §3.10.1
The largest decimal literal of type int is 2147483648.
Can this statement be considered as true because Integer.MAX_VALUE is 2147483647?
Please note that emphasis in above statement is on "int". If it is argued that it is being talked in context of "decimal literal" then even 2147483649 and so on, should be also true.
So, if something is of type int then its largest value has to be 2147483647.
Am I getting it wrong or that statement should be updated?
Note that there are no negative integral literals and Integer.MIN_VALUE is −2147483648. So -2147483648 is parsed as “apply unary minus to 2147483648”. It would be very bad if 2147483648 would not be a valid decimal int literal or you couldn't use an int literal of value Integer.MIN_VALUE directly in your program.
Side note: The JLS defines what is correct. So it is correct by definition. It can be bad, though.
From the same JLS section
The decimal literal 2147483648 may appear only as the operand of the unary minus operator
i.e
int value = -2147483648;
exists
but
int value = 2147483648;
is a compile time error.
Every literal is of a specific type of literal (boolean literal, integer literal, floating point literal, etc), although it may be assigned to a field/variable of different type. For example, 2147483647 is a valid integer literal, while 2147999999 is not (while 2147999999L is, although it is a long literal). While the writing is unclear there appears to be no contradiction of any sort.
Note: Reimeus has the right answer above.
Yep, you are right, the JLS says
The largest decimal literal of type int is 2147483648 (2^31)
but if you try to compile
int j = 2147483648;
you get
Error:(20, 17) java: integer number too large: 2147483648
2^31 is equal to 2147483648, which is 0x80000000, but in 32 bit two's complement notation this is actually equal to -1.
So, 2^31 cannot be represented in an int.
An int can only represent values from Integer.MIN_VALUE, which is -2^31, to Integer.MAX_VALUE, which is (2^31)-1. And luckily the compiler does not accept integer literals outside of that range.
So I understand what a dataype and literal is but I am confused about one thing.
Why do I have to put an L when the datatype is long? How come I don't have to do that for short or byte?
// Why does a not work but b does? Both are longs?
long a = 9223372036854775807;
long b = 9223372036854775807L;
There are only two integer literals types defined in Java: int and long. The latter is distinguished from the former by a suffix L or l. (A character literal is also of integral type (can be assigned to an int, for example) but the Java Language Specification (JLS) treats it separately from integer literals.)
Remember that (apart from inferring generic type parameters), the type of the left hand side of an assignment has no effect on the evaluation of the right-hand side. Therefore, if you assign something to a variable of type long, the expression will be evaluated first and only then will the result be converted to long (if possible and necessary).
The statement
long a = 10;
is perfectly valid. The right hand side expression consisting only of the integer literal 10 will be evaluated and then promoted to long which is then assigned to the variable a. This works well unless you want to assign a value that is too large to be represented in an int in which case you'll have to make the literal of type long as well.
This “problem” is not limited to literals. Consider the following statement that frequently bites new users:
long a = Integer.MAX_VALUE + 1;
The expression on the right hand side is evaluated using int arithmetic and therefore overflows. Only then the result (−2147483648) is promoted to long and assigned to a but it is too late by now. Had the 1 been written as 1L, the overflow would not have happened.
How come I don't have to do that for short or byte?
First, note that a literal of type int can hold any value you could possibly assign to a short or byte so the problem described above cannot occur. Moreover, it is not as much that you “don't have to” use a short or byte literal but that you cannot because such literals are not defined. This has always bothered me because it means that we often have to cast to byte if we want to call a function with a literal argument.
If you like reading standardese, you can look up the chapter about Integer Literals (§ 3.10.1) in the JLS.
Clearly stated in the documentation:
"An integer literal is of type long if it ends with the letter L or l; otherwise it is of type int. It is recommended that you use the upper case letter L because the lower case letter l is hard to distinguish from the digit 1."
Your 2nd question is answered there as well:
"Values of the integral types byte, short, int, and long can be created from int literals"
If you didn't set L, the compiler will try to parse the literal as an int like as below sample scenario.
long accepts a value between the ranges of: -9,223,372,036,854 to +9,223,372,036,854,775,807. Now I have create a Long variable called testLong, although when I insert 9223372036854775807 as the value, I get an error stating:
"The literal of int 9223372036854775807 is out of range."
Solution is add a capital L to the end:
there is something puzzling me and I did not find much information on the VM specs. It's a bit obscure and that'd be nice if someone could explain me.
These few lines of code.....
double myTest = Double.MAX_VALUE;
System.out.println("1. float: " + (float)myTest);
System.out.println("2. int: " + (int)myTest);
System.out.println("3. short: " + (short)myTest);
System.out.println("4. byte: " + (byte)myTest);
..... produce this output:
float: Infinity
int: 2147483647
short: -1
byte: -1
byte, short and int are 8, 16, 32 bit with two's complement. float and double are 32 and 64 bit IEEE 754 (see here).
From my understanding, the max value of a double implies that all the bits of the mantisse (52 bits) are switched to 1. Therefore it's not (very) surprising that a cast to short or to byte returns -1 i.e all bits are switched to 1. It seems that the cast keeps the 'tail' of the double so that it fits into 8 bit byte or 16 bit short.
What surprises me is the cast to int and, to a lesser extent, the cast to float.
How is it possible to get "2. int: 2147483647" which is 0x7FFFFFFF, the maximal value while short and byte 3. and 4. are -1 ?
The cast to float is also weird. If the 32 bits at the 'tail' of myTest were kept, then shouldn't it generate a NaN ?
JLS spells out the rules in section 5.1.3 Narrowing Primitive Conversion. The rules depend on the target type.
float:
A narrowing primitive conversion from double to float is governed by the IEEE 754 rounding rules (§4.2.4). This conversion can lose precision, but also lose range, resulting in a float zero from a nonzero double and a float infinity from a finite double. A double NaN is converted to a float NaN and a double infinity is converted to the same-signed float infinity.
int and long:
one of the following two cases must be true:
...
The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long.
byte, char and short:
If the target type is byte, char or short, the conversion it two-step. First, the double is converted to long as explained above. Then, the long is converted to the final type as follows:
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.