Difference between (float)m/f and (float)(m/f) - java

int m = 10;
int f = 3;
float r = (float)m/f; // gives 3.333333 as output
float r = (float)(m/f); // gives 3.0 as output
Can anyone tell me how the parentheses are changing the answer because I am basically typecasting the integer value of m/f into float. What I don't understand is how the addition of brackets around m/f is changing the answer.

In the second case:
(float)(m/f)
you are doing integer division first and then casting to float and therefore you lose the fraction. In the first case you cast m to float and therefore end up performing floating point division.
The cast operator has higher precedence in both C++ and Java but using parenthesis around the division forces it to be evaluated first.
In C++ his behavior is due to the usual arithmetic conversions which is covered in the draft C++ standard section 5 Expressions paragraph 10 which says:
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
This pattern is called the usual arithmetic conversions, which are defined as follows:
and includes the following bullet:
— Otherwise, if either operand is float, the other shall be converted to float.
In Java this behavior is covered in the JLS section 5.6.2. Binary Numeric Promotion which says:
When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:
and includes:
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
and includes:
Otherwise, if either operand is of type float, the other is converted to float.
and includes the following example:
int i = 0;
float f = 1.0f;
// First int*float is promoted to float*float, then

The difference is what gets converted to float. In the first case m gets converted to float, so the entire expression becomes floating point. In the second, you perform the expression (integer division) and then convert to float, at which point it's too late to save those precious significant digits.

(float)m/f divides (float)m by f. Since one of the operands is a float, the operator is floating-point division, and the answer is 3.333 etc.
(float)(m/f) calculates (m/f) and casts it to float. Since both operands are integer, the operation is integer division, and m/f is 3. Then 3 is casted to float to become 3.0.

On the first example, m gets casted to float first then divided which gives you a floating-point number. The second example, the division is an int division so it will give you an int number that then gets transformed to a floating-point number.
Adding parentheses, change precedence of operators. Type casting is applied before division normally but using parentheses you tell compiler to divide before casting to float.

Order of operations: Casting applies before division, and division between two integers always rounds (down) to the nearest integer in Java.
float r = (float)m/f; // Is the same as ((float)m)/f, and because there's a
// float in the division, we keep everything a float.
float r = (float)(m/f); // Is division between two integers, so we round down
// to the nearest integer before casting to a float.

Related

Why will Java convert the double to float type in this situation?

Today, I defined two float variable f1 and f2. Then I perform an addition, "+", arithmetic operation and assign to float variable f.
float f1 = 0.5048076923076923F;
float f2 = 0.5048076923076923F;
float f = f1 + f2;
This is the output:
According to this picture, All floating point values (float and double) in an arithmetic operation (+, −, *, /) are converted to double type:
picture source: http://www.mathcs.emory.edu/~cheung/Courses/170/Syllabus/04/mixed.html
I found an identical question but it hasn't explain why. Why doesn't eclipse have any issue tips? Is it the reason why the value of "f1 + f2" is a float type? And, why will Java auto convert the double to float type if like the above picture saying?
You seem to be saying that there is a conversion to float in the following.
float f1 = 0.5048076923076923F;
float f2 = 0.5048076923076923F;
float f = f1 + f2;
In fact, there is no conversion. The values are all float.
In particular, the literal 0.5048076923076923F is a float. The trailing F makes it a float. If you want a double literal, leave off the F or replace it with D.
When your teacher says "all floating point values are converted to double" he is wrong. The JLS says (in effect) that a numeric primitive operand will be converted to double when the other operand is a double. If both operands are float, then the operation will performed using single-precision floating point arithmetic.
The JLS reference is JLS 5.6.2: Binary Numeric Promotion.
It has been pointed out that there may be additional conversions happening at the hardware level. For example, the JLS says this:
Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow.
However:
This is only allowed if the expression is not strictfp.
These are not the "conversions" that the JLS talks about in JLS 5.6.2.
This still contradicts what the OP's teacher is saying. He (or she) states that the all floating point calculations are done using double. The JLS states that under certain circumstances, a hardware platform may use extended precision arithmetic (possibly with more precision than 64 bit floating point), and in other circumstances it must not do this.
Your teacher is incorrect, kindly refer him to section 5.6.2 of the Java Language Specification, which states:
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.
As you can see, floats are only converted to double if the other operand is a double, not in all cases as your syllabus incorrectly states.
That is, the sum of two floats is a float, but the sum of a float and a double is a double.
PS: And no, Java will never convert a double to a float unless you explicitly ask it to, as in:
float f = (float) Math.PI;
Hi for floating points values JVM uses instructions like this:
'+' : fadd : pops two floats, adds them, and pushes the float result
'-' : fsub : pops two floats, subtracts them and pushes the flot result
similarly for there are other instructions set for other operators like * and / etc.
So as per JVM implementation point of view float + float will result to float.
But float + double will result to double.
For more information, you can read chapter 14. Floating-Point Arithmetic
of the book "Inside Java Virtual Machine"
What the other answers are missing is the hardware level. Floating point processors, in general, convert all operations to double (or quad), and then return the result in the requested precision. The Java specification may not recognize the conversion, but if it uses the floating point hardware then the conversion happens.

Type Casting ambiguity in Java

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;

How does java compare numbers of different types?

In short: how does Java compare numbers of different types? Specifically: int, long, float, and double. For the purpose of this question, comparing means >, <, >=, and <=; I understand the difficulties and problems of using == and != with floating point numbers.
If two numbers are of the same type (both ints, both doubles, or etc.), comparing them is easy; there are probably direct CPU instructions to do it, and even if not (ancient CPUs?) there are standards for doing so.
Comparing certain pairs of types seems straightforward; if a is an int and b is a long, then we can upcast a to a long in a lossless way and compare them directly (similarly if a and b are reversed, or if we exchange int/long for float/double). I don't know if java actually does it this way, though.
But more controversial is comparing ints/longs with floats/doubles. If I have (say) a long of an integer value that a float can't represent exactly, then how it rounds to a float will affect how it compares to that float. However, there is a right answer, even if it's not clear what it is by casting.
For example if (these are not real examples but real examples exist) a=10001 but float can only encode 10000f and 10002f but nothing in between, then there is a standard rounding procedure where (float) a is exactly one of those two things. But what we should have is that 10000f < a and a < 10002f, which can't be achieved by rounding and then comparing.
So does Java do this in a smarter way? Or does it round and then make some mistakes?
This is all answered in the Java Language Specification. The conversions are listed in 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.
And the widening primitive conversion details specify the following (section 5.1.2).
A widening primitive conversion from int to float, or from long to float, or from long 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 integer value, using IEEE 754 round-to-nearest mode
which is further clarified thus (section 4.2.4).
The Java programming language requires that floating-point arithmetic behave as if every floating-point operator rounded its floating-point result to the result precision. Inexact results must be rounded to the representable value nearest to the infinitely precise result; if the two nearest representable values are equally near, the one with its least significant bit zero is chosen. This is the IEEE 754 standard's default rounding mode known as round to nearest.
So, yes, comparing a long to a float or a double can return an incorrect result, because there are long values that can't be represented by float or double.
java.lang.BigInteger and java.lang.BigDecimal provide functionality to extend mathematical processing to an arbitrary precision... Limited, of course, by the constraints of the computer's resources (CPU and memory mostly)

Why precision lost for double casting in Java?

I am surprised to see below difference in Java:
(double)(int1/int2) // return 0.0 - precision lost.
(double)int1/int2 // return 9.3123325E-10 - precision kept.
Is it by design that the bracket in the first expression makes the evaluation lose the precision?
Yes, it's by design. By putting the expression in parens, you're modifying the normal precedence, so int1/int2 will execute first, and because both are (presumably) integers, use integer division, which will truncate the result to an integer. In the second case, the normal precedence applies, so int1 is being converted to a double first, then the division done using floating point division.
It's a matter of order-of-operations. Parentheses have a higher priority than casts, so your first statement will perform the operations in the parentheses first - it casts the quotient to a double.
Casts have a higher priority than division, so in your second statement, the cast is applied before the division operation.
Because of the brackets (double)(int1/int2) first performs integer division (precision lose included) and then casts the result to double.
The (double)int1/int2 performs a double division because the first operand is double.
Absolutely. In statement 1 you do the division and then cast. In statement 2 you first cast int1 to a double, then you do division which promotes int2 to a double and precision is kept.
I don't intend this to sound snarky, but the language (and compiler) is doing what you asked it to do. :)
In the first one, you're doing integer division, then casting to double. Since integer division truncates any decimals, you're losing the decimal bit of the answer, and casting it to double doesn't bring that info back.
In the second, you're casting the top one to double, then doing double division. This makes the answer automatically a double, since it takes the higher-precision unit when dividing, and ensures that you're getting the decimal bit too.
The second is equivalent to ((double) int1) / int2, since casts have higher precedence than /.
I believe this has to do with the fact that parenthesis (per PEMDAS) causes the calculation to happen within the parenthesis before the cast occurs and as such, the decimal value if the division is less than 1 is 0.
Example:
(double) (3/5) = (double) 0; (Since Int can't be .6)
But (double) 3/5 --> (double) .6

Applying casts to the results of integer and floating point division: what's going on here?

I'm a beginner and there's something that's not making much sense to me. Please could be so kind as to explain where I'm going wrong. I'm sorry if this has been asked before.
Here the presence of the decimal point mean these get evaluated using floating point division.
System.out.println(1/3.0); // this prints: 0.3333333333333333
System.out.println(1.0/3); // this prints: 0.3333333333333333
System.out.println(1.0/3.0); // this prints: 0.3333333333333333
Apparently, this below is an example of "truncating-integer division." It seems a bit weird to me but ok.
System.out.println(1/3); // this prints: 0
Is it ok to say: "in the line below, the (double) cast is evaluated 1st. It effectively says: "treat 1/3 as a double - don't use truncating integer division. instead use floating point division.""
System.out.println((double)1/3); // this prints: 0.3333333333333333
Below, however we get 0.0 - how did that happen?
System.out.println((double)(1/3)); // this prints: 0.0
ok so maybe the extra parentheses mean the (1/3) gets evaluated 1st. It is evaluated using truncating integer division yielding 0. And then the double is applied giving us 0.0 Ok that makes sense
Ok so we maybe can propose a couple of general rules here:
Rule 1: (double) expression means apply the (double) cast first then evaluate the expression.
Rule 2: (double) (expression) means evaluate the expression then apply the cast.
Great!
So in the next line below we have: (int) expression, so I guess we can apply rule 1). The (int) cast is evaluated 1st. It effectively says: "treat 1.0/3 as a int - don't use as much memory as you would with a double. Don't use floating point division, instead apply truncating integer division."" So we have 0 right? No.
System.out.println((int)1/3.0); // this prints: 0.3333333333333333
Ok so we have 0.33333 so the (int) cast is not evaluated 1st. It is as if it wasn't there. Let's propose a 3rd rule:
Rule 3: (int) expression means ignore the (int) cast altogether just evaluate the expression like the (int) isn't even there.
Ok applying rule 3 to the line below, we have (int) but we are just going to ignore it. 1.0/3.0 is evaluated with floating point division and we get 0.3333333. Success!
System.out.println((int)1.0/3.0); // this prints: 0.3333333333333333
And in the last line below, again we have (int) but we are just going to ignore it. (1.0/3) is evaluated using floating point division yielding 0.3333333333 right? No.
System.out.println((int)(1.0/3)); // this prints: 0
Ok now I'm confused. Please could you help me get my head round this?
Java's language parsing rules are basically implying a lot of parentheses everywhere in your code based on its rules of order of operations. Understanding where Java thinks the parentheses are will help you understand this behavior. When you say:
(double) 1 / 3.0
... this is equivalent to saying:
((double) 1) / 3.0
This means that 1 gets converted to a double, and 3.0 is automatically a double, so you'll end up doing a floating point division rather than integer division. The same thing would happen with (double) 1 / 3, because the divisor is a double, so even though the dividend is an int, the system realizes that you want to do floating-point division. The compiler doesn't want you to lose precision unless you specifically ask to, so any time either the dividend or the divisor is a double, it will do double division.
On the other hand:
(int) 1 / 3.0
... is the same as saying:
((int) 1) / 3.0
In this case, you're telling the compiler what it already knew: that the divisor (1) is an int. Then you're asking it to divide by a double value (3.0). Since the dividend is a double, it will perform double division.
As you noted, 1/3 will produce zero, because that's how integer division works and both numbers are integers. The same will happen with 1/(int)3.0 because you're telling the compiler to make the 3.0 into an int before the division will occur (as in 1/((int)3.0)).
The final point to keep in mind is that (int) 0.33 will also get converted to 0, because an integer can't hold decimal values in it. So when you say (int)(1.0/3), you're doing double division, but then you're converting the double into an int afterwards, producing 0.
This is specified in the Java Language Specification - Numeric Promotions
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed.
Then:
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.
The concept is called widening conversion:
5.1.2 Widening Primitive Conversion
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
The reason why
(int) (1.0/3) == 0
is because you cast the result of 1.0/3 (0.33333... by the above rules) explicitly to an integer, which is equivalent to "floor(result)" (rounding down), so the result is 0.
Cast has a higher precedence than /, that's why the other operations were misleading to your understanding:
(double) 1 / 3
will explicitly cast 1 to a double value 1.0 first, so again the result by the above rules is equal to 0.3333....
The cast is only applied to the expression immediately after it.
Examples:
(int)1/3
applies the cast to the 1. equivalent to ((int)1)/3
(int)(1/3)
the cast is applied to the result of the expression.
(int)((double)1.333*(float)3.167)
getting a little more complicated. 1.333 casted to double,
multiplied by 3.167 casted to a float, with the result casted to an int
Hope that helps!
There are two factors in all those cases:
Operator precedence
When one of the arguments of the division is a floating point number, the result is a floating point number.
I'll give three examples from your question:
(double) (1/3) - first evaluate the expression in parenthesis - (1/3) is an integer division so the result is 0, then cast it to double, you get 0.0
(int) (1.0/3) - first evaluate the expression in parenthesis - (1.0/3) is a floating point division, so the result is 0.3333, then cast it to int, and you get 0
(double) 1/3 - first perform casting so (double)1 becomes 1.0, then evaluate the division 1.0/3 - this is a floating point division, so the result is 0.3333

Categories

Resources