So I basically want to know, does java automatically turn int to a double or a double to a int.
To make this more clear look at this example:
say where given this heading
public static void doThis (int n, double x)
and in the main method we declare something like this :
doThis(0.5,2);
Is this a invalid call?
how about this?
doThis(3L,4);
these last two
doThis(3,4);
doThis(2.0,1.5);
Thanks
Values of type int can be implicitly converted to double, but not vice versa.
Given this declaration:
public static void doThis (int n, double x)
these are legal:
doThis(1, 0.5); // call doThis with an int and a double
doThis(1, (double)2); // second int is converted to a double, then passed
doThis(1, 2); // same as above; the compiler automatically inserts the cast
doThis((int)3.5, 0.5); // first double is converted to an int, then passed
doThis((int)3.5, 42); // the double is converted to an int, and the int is converted to a double
and these are not:
doThis(5.1, 0.5); // the compiler will not automatically convert double to int
doThis(5L, 0.5); // nor will it convert long to int
The intention behind the automatic conversion rules is that the compiler will not automatically convert types if doing so could lose data. For example, (int)4.5 is 4, not 4.5 - the fractional part is ignored.
You can pass an int literal where a double is required, but not vice versa. If you try to compile the following example, you can see for yourself.
public class MWE{
public static void doThis (int n, double x) {
}
public static void main(String[] args) {
doThis(0.5,2); // Compiler error
doThis(3L,4);// Compiler error
doThis(3,4); // No Error
doThis(2.0,1.5); // Compiler error
}
}
You can do that, you can pass int when double is needed(it get casted by the compiler).
But you cant pass double in place of int.
More info over here.
When passing values of different types, there are a couple of rules of thumb:
Floating points cannot be substituted for integers, but the reverse is possible.
Primitives of the same type (integer or floating point) with a higher but depth cannot be substituted for ones with lower bit depth, but the reverse is possible.
Substitution is just an automatic cast by the Java compiler. You can always cast manually.
To clarify, the floating point types are float and double, while the integer types are byte, short, int, and long.
In this case, double is a floating point and int is an integer. You can substitute int in place of a double, but not vice versa.
In a method invocation, each argument value can have any of these conversions applied to it (JLS 5.3):
5.3. Method Invocation Conversion
Method invocation contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
a boxing conversion (§5.1.7) optionally followed by widening reference
conversion
an unboxing conversion (§5.1.8) optionally followed by a widening
primitive conversion.
In this example, we're dealing with a primitive widening conversion:
5.1.2. Widening Primitive Conversion
19 specific conversions on primitive types are called the widening
primitive conversions:
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
As you can see in the list, going from a int to double is perfectly fine, but the opposite is not true.
Related
The java.lang.Math class has ceil(), floor(), round() methods, but does not have trunc() one.
At the same time I see on the practice that the .intValue() method (which does actually (int) cast) does exactly what I expect from trunc() in its standard meaning.
However I cannot find any concrete documentation which confirms that intValue() is a full equivalent of trunc() and this is strange from many points of view, for example:
The description "Returns the value of this Double as an int (by
casting to type int)" from
https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html does
not say anything that it "returns the integer part of the fractional
number" or like that.
The article
What is .intValue() in Java?
does not say anything that it behaves like trunc().
All my searches for "Java trunc method" or like that didn't give
anything as if I am the only one who searches for trunc() and as if I
don't know something very common that everyone knows.
Can I get somehow the confirmation that I can safely use intValue() in order to get fractional numbers rounded with "trunc" mode?
So the question becomes: Is casting a double to a int equal to truncation?
The Java Language Specification may have the answer. I'll quote:
specific conversions on primitive types are called the narrowing
primitive conversions:
[...]
float to byte, short, char, int, or long
double to byte, short, char, int, long, or float
A narrowing primitive conversion may lose information about the
overall magnitude of a numeric value and may also lose precision and
range.
[...]
A narrowing conversion of a floating-point number to an integral type
T takes two steps:
In the first step, the floating-point number is converted either to [...] an int, if T is byte, short, char, or int, as follows:
If the floating-point number is NaN (§4.2.3), the result of the first step of the conversion is an int or long 0.
Otherwise, if the floating-point number is not an infinity, the floating-point value is rounded to an integer value V, rounding toward
zero using IEEE 754 round-toward-zero mode (§4.2.3). Then there are
two cases:
If T is long, and this integer value can be represented as a long, then the result of the first step is the long value V.
Otherwise, if this integer value can be represented as an int, then the result of the first step is the int value V.
Which is described in IEEE 754-1985.
You can use floor and ceil to implement trunc
public static double trunc(double value) {
return value<0 ? Math.ceil(value) : Math.floor(value);
}
With Google Guava DoubleMath#roundToInt() you can convert that result into an int:
public static int roundToInt(double x, RoundingMode mode) {
double z = roundIntermediate(x, mode);
checkInRangeForRoundingInputs(
z > MIN_INT_AS_DOUBLE - 1.0 & z < MAX_INT_AS_DOUBLE + 1.0, x, mode);
return (int) z;
}
private static final double MIN_INT_AS_DOUBLE = -0x1p31;
private static final double MAX_INT_AS_DOUBLE = 0x1p31 - 1.0;
I'm doing my Java class exercises. I have this code which contains an overloaded method:
class A {
// Overloaded method
public void f(int n, float x) {
System.out.println("f(int n, float x) n = " + n + " x = " + x);
}
private void f(long q, double y) {
System.out.println("f(long q, double y) q = " + q + " y = " + y);
}
public void f(double y1, double y2) {
System.out.println("f(double y1, double y2) y1 = " + y1 + " y2 = " + y2);
}
public void g() {
int n = 1;
long q = 12;
float x = 1.5f;
double y = 2.5;
System.out.println("--- dans g ");
f(n, q);
f(q, n);
f(n, x);
f(n, y);
}
}
Main:
public static void main(String[] args){
A a = new A() ;
a.g() ;
System.out.println ("--- dans main") ;
int n=1 ;
long q=12 ;
float x=1.5f ;
double y = 2.5 ;
a.f(n, q) ; // my problem is here
a.f(q, n) ;
a.f(n, x) ;
a.f(n, y) ;
}
When I call the method a.f(n,q) in main I expect an error, but it calls the method f(int n, float x) while my q is a long number and it's size is bigger then a float's size (8 byte / 4 byte) So I wonder how these primitive types works?
Method invocations occupy a pretty length chunk of the spec. To summarize, the compiler proceeds as follows:
Identify classes on which the method might be invoked.
Identify methods on those classes which might be invoked.
If more than one method was identified, pick the most specific one.
Step 2 is the most interesting one here: this proceeds in a number of steps. To summarize:
If there is a non-varargs method on the class with the exact same parameter types (strict invocation), choose that.
If there is a non-varargs method on the class with parameter types for which automatic conversions from the actual parameters (loose invocation), choose that.
If there is a varargs method on the class with parameter types that match with automatic conversion, choose that.
You're supplying parameters that don't exactly match any of the parameter types of the overloads, so you need check if you can convert that parameters to allow strict invocation. The conversions in strict invocations are:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
a widening reference conversion (§5.1.5)
An int can be converted by identity conversion to int. A long can be converted by widening primitive conversion to a float.
Hence f(int, float) is applicable.
f(long, double) and f(double, double) are also applicable, since int can be widened to long and double; and long can be widened to double.
However, these are less specific than f(int, float), since int can be widened to long and double, and float can be widened to double. Hence, by the informal intuition laid out in JLS Sec 15.12.2.5, these methods are less specific than f(int, float). As such, f(int, float) is the one that is invoked.
longs can be converted to float without raising errors. But you may lose precision.
For details see the specs.
The following 19 specific conversions on primitive types are called the widening primitive conversions:
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
Widening primitive conversions do not lose information about the overall magnitude of a numeric value.
...
Conversion of an int or a long value to float, or of a long value to double, may result in loss of precision-that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the long value.
I tried this method overloading code and I got the error
no suitable method found for add(double,double)
The code:
class Adder {
static float add(float a, float b) {
return a + b;
}
static int add(int a, int b) {
return a + b;
}
}
class TestOverloading1 {
public static void main(String[] args){
System.out.println(Adder.add(11.5, 11.5));
System.out.println(Adder.add(27, 21));
}
}
On writing, 11.5f in params, this works well.
I understood the differences between float and double from here and here.
So, why does Java take the parameters as double datatype by default? Is the higher precision of double behind such a bias?
I am aware that it takes the double by default. But, I wish to know what is the reason behind this?
A floating point literal without any suffix (such as 11.5) is of type double by definition (similarly an integer literal without any suffix is of type int).
A double parameter is not acceptable for a method that accepts float arguments (since a casting from double to float may result in loss of data, and therefore the compiler won't perform such casting automatically).
On the other hand, 11.5f is a float literal, so you can pass such literals to your add(float a,float b) method.
doing
Adder.add(11.5,11.5)
is the same as
double a = 11.5;
double b = 11.5;
Adder.add(a, b)
that doesnt match the parameters in the static method
static float add(float a,float b){return a+b;}
so you are required to:
cast those literals to float:
Adder.add(11.5f, 11.5f );
or declare a and b as float
float a = 11.5;
float b = 11.5;
Adder.add(a, b)
"11.5" without nothing is considerated as double by Java.
You can use something as :
System.out.println(Adder.add(new Float(11.5),new Float(11.5)));
In Java when we type decimal number as 11.5, then it is considered as double. double is 64-bit while float is 32-bit so conversion is not possible, that's why compile time exception occurs. For more info please visit : Primitive Data Types
It is just a specification. Just like why int have default value 0 in Java.
Double is the default type for decimal values:
double: The double data type is a double-precision 64-bit IEEE 754
floating point. Its range of values is beyond the scope of this
discussion, but is specified in the Floating-Point Types, Formats, and
Values section of the Java Language Specification. For decimal values,
this data type is generally the default choice. As mentioned above,
this data type should never be used for precise values, such as
currency.
Source: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
SSCCE:
public class Test {
public static void main(String[] args) {
Long a = new Long(1L);
new A(a);
}
static class A {
A(int i) {
System.out.println("int");
}
A(double d) {
System.out.println("double");
}
}
}
Output:
double
There will be no compilation error printed, it works fine and calls double-parameter constructor. But why?
It's down to the rules of type promotion: a long is converted to a double in preference to an int.
A long can always fit into a double, although precision could be lost if the long is larger than the 53rd power of 2. So your compiler picks the double constructor as a better fit than the int one.
(The compiler doesn't make a dynamic check in the sense that 1L does fit into an int).
Converting long to int is a narrowing primitive conversion because it can lose the overall magnitude of the value. Converting long to double is a widening primitive conversion.
The compiler will automatically generate assignment context conversion for arguments. That includes widening primitive conversion, but not narrowing primitive conversion. Because the method with an int argument would require a narrowing conversion, it is not applicable to the call.
int is of 4 bytes where as long and double are of 8 bytes
So, it is quite obvious that there is a chance for loss of 4 bytes of data if it is casted to an int. Datatypes are always up casted. As the comment from #Bathsheba mentioned, there is a chance of data loss even in case of using double, but the loss is much smaller when compared with int.
As you can see, double uses 52 bits for storing significant digits. Where as if it chooses int, the variable will have 32 bits available to it. Hence jvm chooses the double instead of int.
Source: Wikipedia
Because a long doesn't "fit" in an int.
Check https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html
The following works
float a=3;
but the following doesn't:
Float a=3;
Shouldn't 3 be automatically promoted to float (as widening conversions don't require an explicit cast) and then Boxed to Float type ?
Is it because of a rule I read in Khalid Mogul's Java book ?
Widening conversions can't be followed
by any boxing conversions
The reason why Float a=3; won't work is because the compiler wraps the 3 into it's Integer object (in essence, the compiler does this: Float a = new Integer(3); and that's already a compiler error). Float object isn't and Integer object (even though they come from the same Number object).
The following works:
Number a = 3;
which in essence is translated by the compiler as:
Number a = new Integer(3);
or as Joachim Sauer mentioned,
Number a = Integer.valueOf(3);
Hope this helps.
Float Integer
^ ^
| |
| |
v v
float <-----------> int
There is a boxing/unboxing conversion betwen the primitive and the wrapper, and there is a promotion from one numeric primitive to another. But Java is not able to make this conversion twice (convert from int to Float, in your case).
Float a= 3.0f; will work.