I'm doing multiplication and division of floats and ints and I forget the implicit conversion rules (and the words in the question seem too vague to google more quickly than asking here).
If I have two ints, but I want to do floating-point division, do I need only to cast one or both of the operands? How about for multiplication — if I multiply a float and an int, is the answer a float?
You can’t assign to an int result from division of a float by an int or vice-versa.
So the answers are:
If I have two ints, but I want to do floating point division…?
One cast is enough.
If I multiply a float and an int, is the answer a float?
Yes it is.
float f = 1000f;
int i = 3;
f = i; // Ok
i = f; // Error
f = i/f; //Ok 0.003
f = f/i; //Ok 333.3333(3)
i = i/f; //Error
i = f/i; //Error
To demonstrate:
int i1 = 5;
float f = 0.5f;
int i2 = 2;
System.out.println(i1 * f);
System.out.println(i1 / i2);
System.out.println(((float) i1) / i2);
Result:
2.5
2
2.5
In order to perform any sort of floating-point arithmetic with integers, you need to convert (read: cast) at least one of the operands to a float type.
If at least one of the operands to a
binary operator is of floating-point
type, then the operation is a
floating-point operation, even if the
other is integral.
(Source: Java language specifications - 4.2.4)
if I multiply a float and an int, is the answer a float?
System.out.println(((Object)(1f*1)).getClass());//class java.lang.Float
(If you use DrJava, you can simply type ((Object)(1f*1)).getClass() into the interactions panel. There's a plugin for DrJava for Eclipse too.)
The simple answer is that Java will perform widening conversions automatically but not narrowing conversions. So for example int->float is automatic but float->int requires a cast.
Java ranks primitive types in the order int < long < float < double. If an operator is used with different primitive types, the type which appears before the other in the above list will be implicitly converted to the other, without any compiler diagnostic, even in cases where this would cause a loss of precision. For example, 16777217-1.0f will yield 16777215.0f (one less than the correct value). In many cases, operations between a float and an int outside the range +/-16777216 should be performed by casting the int to double, performing the operation, and then--if necessary--casting the result to float. I find the requirement for the double casting annoying, but the typecasting rules in Java require that one either use the annoying double cast or suffer the loss of precision.
Related
I am pretty new to Java. Came across a problem and would like to gain more insight on it.
The following code doesn't compile :
byte a = 10;
byte b = 20;
byte c = a + b;
Compilation error -> Type mismatch: cannot convert from int to byte
Its a compilation error since :
All integer literals are treated as Integers in Java.
So, a+b results in an integer literal which needs to be typecasted to byte before storing in a byte type variable since there might be a loss of precision. I completely understands the above concept.
What confuses me is a similar concept with float variables. The below code snippet compiles successfully:
float d = 1.2;
float e = 2.3;
float f = d + e;
According to Java :
All decimal literals are treated as Decimal in Java.
So, on similar note (d + e) must result in a decimal literal which will treated as decimal type and is getting stored in a float type variable. Here also we have a loss of precision. Why compiler doesn't force us here for explicit typecasting as in earlier case ? Why is it not a compilation error here ?
Type casting ambiguity in Java
There are no typecasts in the code you posted.
The following code doesn't compile :
byte a = 10;
byte b = 20;
byte c = a + b;
Compilation error -> Type mismatch: cannot convert from int to byte
Its a compilation error since :
All integer literals are treated as Integers in Java.
No it isn't. It's a compilation error because all operations between types narrower than int produce int values. JLS #4.2.2 Integer Operations:
If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.
If what you claim as a Java rule really was a Java rule, all three lines would have failed to compile. But there is no such rule in Java as the one you claim. You just made it up.
So, a+b results in an integer literal
No it doesn't. It results in an integer value.
which needs to be typecasted to byte before storing in a byte type variable since there might be a loss of precision. I completely understands the above concept.
No, you don't understand it at all.
What confuses me is a similar concept with float variables. The below code snippet compiles successfully:
float d = 1.2;
float e = 2.3;
No it doesn't. Both lines produce compilation errors: error: incompatible types: possible lossy conversion from double to float.
float f = d + e;
This compiles.
According to Java :
All decimal literals are treated as Decimal in Java.
There is no such rule. Again you have just made this up. There is no such thing as a 'decimal literal' in Java, or Decimal either.
So, on similar note (d + e) must result in a decimal literal
No. It results in a float value.
which will treated as decimal type
There is no 'decimal type' in Java. There is BigDecimal, which is a class, not a type, but it doesn't relate to this question in any way.
and is getting stored in a float type variable. Here also we have a loss of precision.
No we don't. JLS #4.2.4 'Floating-Point Operations:
If at least one of the operands to a numerical operator is of type double, then the operation is carried out using 64-bit floating-point arithmetic, and the result of the numerical operator is a value of type double. If the other operand is not a double, it is first widened (§5.1.5) to type double by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit floating-point arithmetic, and the result of the numerical operator is a value of type float. (If the other operand is not a float, it is first widened to type float by numeric promotion.)
You wrote:
Why compiler doesn't force us here for explicit typecasting as in earlier case? Why is it not a compilation error here?
Because it isn't an error. It isn't an instance of the previous error because it doesn't involve types narrower than int.
Don't just make rules up and then ask why Java doesn't comply with them. Check the actual rules.
In java you can't declare float values as :
float d = 1.2;
float e = 2.3;
Because compiler infers 1.2 and 2.3 as double. You have to cast them to float:
float d = (float) 1.2;
float e = (float) 2.3;
or
float d = 1.2f;
float e = 2.3f;
This question already has answers here:
Int division: Why is the result of 1/3 == 0?
(19 answers)
Closed 4 years ago.
This is a basic question but I can't find an answer. I've looked into floating point arithmetic and a few other topics but nothing has seemed to address this. I'm sure I just have the wrong terminology.
Basically, I want to take two quantities - completed, and total - and divide them to come up with a percentage (of how much has been completed). The quantities are longs. Here's the setup:
long completed = 25000;
long total = 50000;
System.out.println(completed/total); // Prints 0
I've tried reassigning the result to a double - it prints 0.0. Where am I going wrong?
Incidentally, the next step is to multiply this result by 100, which I assume should be easy once this small hurdle is stepped over.
BTW not homework here just plain old numskull-ness (and maybe too much coding today).
Converting the output is too late; the calculation has already taken place in integer arithmetic. You need to convert the inputs to double:
System.out.println((double)completed/(double)total);
Note that you don't actually need to convert both of the inputs. So long as one of them is double, the other will be implicitly converted. But I prefer to do both, for symmetry.
You don't even need doubles for this. Just multiply by 100 first and then divide. Otherwise the result would be less than 1 and get truncated to zero, as you saw.
edit: or if overflow is likely, if it would overflow (ie the dividend is bigger than 922337203685477581), divide the divisor by 100 first.
In Java
Integer/Integer = Integer
Integer/Double = Double//Either of numerator or denominator must be floating point number
1/10 = 0
1.0/10 = 0.1
1/10.0 = 0.1
Just type cast either of them.
Convert both completed and total to double or at least cast them to double when doing the devision. I.e. cast the varaibles to double not just the result.
Fair warning, there is a floating point precision problem when working with float and double.
If you don't explicitly cast one of the two values to a float before doing the division then an integer division will be used (so that's why you get 0). You just need one of the two operands to be a floating point value, so that the normal division is used (and other integer value is automatically turned into a float).
Just try with
float completed = 50000.0f;
and it will be fine.
As explain by the JLS, integer operation are quite simple.
If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.
So to make it short, an operation would always result in a int at the only exception that there is a long value in it.
int = int + int
long = int + long
int = short + short
Note that the priority of the operator is important, so if you have
long = int * int + long
the int * int operation would result in an int, it would be promote into a long during the operation int + long
As your output results a double you should cast either completed variable or total variable or both to double while dividing.
So, the correct implmentation will be:
System.out.println((double)completed/total);
This question already has answers here:
Int division: Why is the result of 1/3 == 0?
(19 answers)
Closed 4 years ago.
This is a basic question but I can't find an answer. I've looked into floating point arithmetic and a few other topics but nothing has seemed to address this. I'm sure I just have the wrong terminology.
Basically, I want to take two quantities - completed, and total - and divide them to come up with a percentage (of how much has been completed). The quantities are longs. Here's the setup:
long completed = 25000;
long total = 50000;
System.out.println(completed/total); // Prints 0
I've tried reassigning the result to a double - it prints 0.0. Where am I going wrong?
Incidentally, the next step is to multiply this result by 100, which I assume should be easy once this small hurdle is stepped over.
BTW not homework here just plain old numskull-ness (and maybe too much coding today).
Converting the output is too late; the calculation has already taken place in integer arithmetic. You need to convert the inputs to double:
System.out.println((double)completed/(double)total);
Note that you don't actually need to convert both of the inputs. So long as one of them is double, the other will be implicitly converted. But I prefer to do both, for symmetry.
You don't even need doubles for this. Just multiply by 100 first and then divide. Otherwise the result would be less than 1 and get truncated to zero, as you saw.
edit: or if overflow is likely, if it would overflow (ie the dividend is bigger than 922337203685477581), divide the divisor by 100 first.
In Java
Integer/Integer = Integer
Integer/Double = Double//Either of numerator or denominator must be floating point number
1/10 = 0
1.0/10 = 0.1
1/10.0 = 0.1
Just type cast either of them.
Convert both completed and total to double or at least cast them to double when doing the devision. I.e. cast the varaibles to double not just the result.
Fair warning, there is a floating point precision problem when working with float and double.
If you don't explicitly cast one of the two values to a float before doing the division then an integer division will be used (so that's why you get 0). You just need one of the two operands to be a floating point value, so that the normal division is used (and other integer value is automatically turned into a float).
Just try with
float completed = 50000.0f;
and it will be fine.
As explain by the JLS, integer operation are quite simple.
If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.
So to make it short, an operation would always result in a int at the only exception that there is a long value in it.
int = int + int
long = int + long
int = short + short
Note that the priority of the operator is important, so if you have
long = int * int + long
the int * int operation would result in an int, it would be promote into a long during the operation int + long
As your output results a double you should cast either completed variable or total variable or both to double while dividing.
So, the correct implmentation will be:
System.out.println((double)completed/total);
You can implicitly convert an int to a double: double x = 5;
You can explicitly convert an int to a double: double x = (double) 5;
You can explicitly convert a double to an int: int x = (int) 5.0;
Why can't you implicitly convert a double to an int?: int x = 5.0;
The range of double is wider than int. That's why you need explicit cast. Because of the same reason you can't implicitly cast from long to int:
long l = 234;
int x = l; // error
Implicit casting is only available when you're guaranteed that a loss of data will not occur as a result of a conversion. So you could cast an integer to a double, or an integer to a long data type. Casting from a double to an integer however, runs the risk of you losing data.
Console.WriteLine ((int)5.5);
// Output > 5
This is why Microsoft didn't write an implicit cast for this specific conversion. The .NET framework instead forces you to use an explicit cast to ensure that you're making an informed decision by explicitly casting from one type to another.
The implicit keyword is used to declare an implicit user-defined type conversion operator. Use it to enable implicit conversions between a user-defined type and another type, if the conversion is guaranteed not to cause a loss of data.
Source > MSDN
C# follows the lead of Java's type system, which ranks types int->long->float->double, and specifies that any type which appears to the left of another may be cast to it. I personally think ranking types in this fashion was a bad idea, since it means that code like long l = getSomeValue(); float f=l; double d=f; will compile cleanly without a squawk despite a severe loss of precision compared with storing l directly to d; it has some other unfortunate consequences as well.
I suspect Gosling ranked the types as he did in order to ensure that passing a float and a double to a method which is overloaded for (float,float) and (double,double) would use the latter. Unfortunately, his ranking has the unfortunate side-effect that passing an int or long to a method which is only overloaded for float and double will cause the method to use the float overload rather than the double overload.
C# and .NET follows Java's lead in preferring a long-to-float conversion over a long-to-double; the one thing which "saves" them from some of the consequent method-overloading horrors is that nearly all the .NET Framework methods with overloads for float and double also have an overload for Decimal, and no implicit conversions exist between Decimal and the other floating-point types. As a consequence, attempting to pass a long to a method which has overloads for float, double, and Decimal but not long will result in a compilation error rather than a conversion to float.
Incidentally, even if the people choosing which implicit conversions to allow had given the issue more thought, it's unlikely that implicit conversions from floating-point types (e.g. double) to discrete types (e.g. int) would have been permitted. Among other things, the best integer representation for the result of a computation that yielded 2.9999999999994 would in some cases be 2, and in other cases it would be 3. In cases where a conversion might sometimes need to be done one way and sometimes another, it's generally good for the language to require that the programmer indicate the actual intention.
Imagine that you have this piece of code:
double x = pi/6;
double y = sin(x);
y would then be 0.5.
Now suppose that x is cast as an integer as follows:
int x = pi/6;
double y = sin(x);
In this case x would be truncated to 0, and then the sin(0) would be taken, i.e. y = 0.
This is the primary reason why implicit conversion from double to int is not implemented in a lot of strong-typed languages.
The conversion of int to double actually increases the amount of information in the type, and can thus always be done safely.
WHEN YOU CONVERT FROM DOUBLE TO INT IMPLICITLY then you are trying to store a no. with large memory into a variable having small memory(downcasting)
double d=4.5;
int x=d;//error or warning
which can be dangerous as you may lose out the information like you may lose the fractional part of a double while storing it in an integer
whereas that is not the case while storing an int value in a double variable(upcasting).
int x=2;
double d=x; //correct
so the compiler doesn't allows to implicitly convert from double to int( or storing double value in an int) because someone might do it unknowingly and expect no loss of data. But if you explicitly cast it means that you say to compiler that cast whatever be the danger ,no matter ,i will manage....hope it helps..
In another Bruce Eckel exercise, the code I've written takes a method and changes value in another class. Here is my code:
class Big {
float b;
}
public class PassObject {
static void f(Letter y) {
y.c = 'z';
} //end f()
static void g(Big z) {
z.b = 2.2;
}
public static void main(String[] args ) {
Big t = new Big();
t.b = 5.6;
System.out.println("1: t.b : " + t.b);
g(x);
System.out.println("2: t.b: " + t.b);
} //end main
}//end class
It's throwing an error saying "Possible loss of precision."
PassObject.java:13: possible loss of precision
found: double
required : float z.b = 2.2
passobject.java:20: possible loss of precision
found : double
required : float t.b = 5.6
Can't doubles be floats as well?
Yes, but you have to specify that they are floats, otherwise they are treated as doubles:
z.b = 2.2f
The 'f' at the end of the number makes it a float instead of a double.
Java won't automatically narrow a double to a float.
No, floats can be automatically upcast to doubles, but doubles can never be floats without explicit casting because doubles have the larger range.
float range is 1.40129846432481707e-45 to 3.40282346638528860e+38
double range is 4.94065645841246544e-324d to 1.79769313486231570e+308d
By default, Java will treat a decimal (e.g. "4.3") as a double unless you otherwise specify a float by adding an f after the number (e.g. "4.3f").
You're having the same problem on both lines. First, the decimal literal is interpreted as a double by the compiler. It then attempts to assign it to b, which is of type float. Since a double is 64 bits and a float is only 32 bits (see Java's primitives documentation), Java gives you an error indicating that the float cannot fit inside the double. The solution is to add an f to your decimal literals.
If you were trying to do the opposite (i.e. assign a float to a double), that would be okay since you can fit a float's 32 bits within a double's 64.
Don't use float. There is almost never a good reason to use it and hasn't been for more than a decade. Just use double.
can't doubles be floats as well?
No. Each value or variable has exactly one type (double, float, int, long, etc...). The Java Language Specification states exactly what happens when you try to assign a value of one type to a variable of another type. Generally, assignments of a "smaller" value to a "larger" type are allowed and done implicitly, but assignments where information could be lost because the target type is too "small" to hold all values of the origin type are not allowed by the compiler, even if the concrete value does fit into the target type.
That's why the compiler complains that assigning a double value (which the literal implicitly is) to a float variable could lose information, and you have to placate it by either making the value a float, or by casting explicitly.
One area that often causes confusions is calculations, because these are implicitly "widened" to int for technical reasons. So if you multiply two shorts and try to assign the result to a short, the compiler will complain because the result of the calculation is an int.
float range is lower than double so a float can be easily represented in double, but the reverse is not possible because, let say we take a value which is out of float range then during convention we will lose the exact data