The Payroll Average That Lost Its Fractions
A payroll module keeps headcount and totals as int. With int total = 17; int count = 4; the line double avg = total / count; stores 4.0, and the printed report shows 4.00 where the analyst expects 4.25. A separate cleanup changed several x = x + n; statements into compound form. After the cleanup, byte flags = 8; flags = flags + 1; and short q = 100; q = q * 2; fail to compile, while a reviewer's version using flags += 1; and q *= 2; compiles and runs. The team lead wants both symptoms explained, plus a note on what could go wrong later, before the release branch is cut.
1. Explain why `avg` holds 4.0, give two code changes that yield 4.25, and identify a change that looks correct but is not.
Read the worked answer
Both operands of / are int, so binary numeric promotion leaves them as int and integer division runs: 17 / 4 produces the int value 4, truncating toward zero. The widening to double happens only at the assignment, so 4.0 is stored and the fraction is already gone.
Correct fixes - make at least one operand floating point before the division:
double avg = (double) total / count; // 4.25
double avg = total / (double) count; // 4.25
double avg = 1.0 * total / count; // 4.25
The trap is (double) (total / count). The cast is applied to an already-computed int, so it converts 4 to 4.0 and the report is still wrong. Casting must reach an operand, not the finished quotient.
2. Why do the compound-assignment versions compile when the long forms do not, and what defect can that hidden conversion still cause?
Read the worked answer
Compound assignment E1 op= E2 is specified as E1 = (T) ((E1) op (E2)), where T is the type of the left-hand side. The compiler inserts the narrowing cast implicitly, so flags += 1 is really flags = (byte)(flags + 1) and is legal. The long form flags = flags + 1 promotes byte to int, and assigning an int back to a byte variable requires an explicit cast, so it is a compile-time error. Same story for short.
The residual defect is silent truncation. The cast discards high-order bits without any warning:
byte b = 127;
b += 1; // b is now -128
short q = 20000;
q *= 2; // q is now -25536, not 40000
No exception is thrown, so a value that only occasionally exceeds the type range corrupts data quietly. Range checks or a wider type must be chosen deliberately.
3. Predict the values of `int a = 5; double d = a / 2 * 2.0;` and `double e = a / 2.0 * 2;` and state the rule you applied.
Read the worked answer
Evaluation is left to right with each operator obeying its own operand types.
a / 2: bothint, so integer division gives 2. Then2 * 2.0promotes todouble, givingd == 4.0.a / 2.0: thedoubleoperand promotesa, so this is 2.5. Then2.5 * 2givese == 5.0.
The rule: a fraction survives only if a floating-point operand is present at the moment the division executes. Placement of .0 to the right of the / cannot rescue a division that already ran on two ints.