Does One Double Promote Every Int in the Equation to Double

Does one double promote every int in the equation to double?

I purposefully did not compile and run then on my system, since this is the type of thing that could be compiler dependent.

This is not compiler dependent. C++ clearly defines the order of these operations and how they are converted.

How the conversion happens is dependent on the order of operations.

double result1 = a + b / d + c; // equal to 4 or to 4.5?

In this example, the division happens first. Because this is an int divided by a double, the compiler handles this by converting the int into a double. Thus, the result of b / d is a double.

The next thing that C++ does is add a to the result of b / d. This is an int added to a double, so it converts the int to a double and adds, resulting in a double. The same thing happens with c.

double result3 = a / b + d; // equal to 4 or to 4.5?

In this example, division is handled first. a and b are both ints, so no conversion is done. The result of a / b is of type int and is 0.

Then, the result of this is added to d. This is an int plus a double, so C++ converts the int to a double, and the result is a double.

Even though a double is present in this expression, a / b is evaluated first, and the double means nothing until execution reaches the double. Therefore, integer division occurs.

I find promotion and conversion rules pretty complex. Usually integer-like numbers (short, int, long) are promoted to floating-point equivalents (float, double). But things are complicated by size differences and sign.

See this question for specifics about conversion.

Does dividing float by int always give float? C++

From the C++20 standard draft [expr.arith.conv]:

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:

  • (1.1)
    If either operand is of scoped enumeration type, no conversions are performed; if the other operand does not have the same type, the expression is ill-formed.
  • (1.2)
    If either operand is of type long double, the other shall be converted to long double.
  • (1.3)
    Otherwise, if either operand is double, the other shall be converted to double.
  • (1.4)
    Otherwise, if either operand is float, the other shall be converted to float.
  • (1.5)
    Otherwise, the integral promotions ([conv.prom]) shall be performed on both operands.56 Then the following rules shall be applied to the promoted operands:
    ...

This paragraph has not changed in any fundmental way since at least C++11 (which was the oldest I checked), so your teacher has some explaining to do.

Integer division: How do you produce a double?

double num = 5;

That avoids a cast. But you'll find that the cast conversions are well-defined. You don't have to guess, just check the JLS. int to double is a widening conversion. From §5.1.2:

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
integer value, using IEEE 754
round-to-nearest mode (§4.2.4).

5 can be expressed exactly as a double.

C++ compound assignment and type conversion issue

If you print out ans without casting it to (int) you'll see the second result is 6434.9999999999990905052982270717620849609375. That's pretty darn close to the right answer of 6535, so it's clearly not a type promotion error any more.

No, this is classic floating point inaccuracy. When you write ans *= (double) (a + 1 - i) / i you are doing the equivalent of:

ans = ans * ((double) (a + 1 - i) / i);

Compare this to the third version:

ans = ans * (a + 1 - i) / i;

The former performs division first followed by multiplication. The latter operates left to right and so the multiplication precedes the division. This change in order of operations causes the results of the two to be slightly different. Floating point calculations are extremely sensitive to order of operations.

Quick fix: Don't truncate the result; round it.

Better fix: Don't use floating point for integral arithmetic. Save the divisions until after all the multiplications are done. Use long, long long, or even a big number library.

Is it valid to compare a double with an int in java?

Yes, it's valid - it will promote the int to a double before performing the comparison.

See JLS section 15.20.1 (Numerical Comparison Operators) which links to JLS section 5.6.2 (Binary Numeric Promotion).

From the latter:

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.

  • ...

Promotion in java

It's important to remember the order of operations!

3.0 + 5/2
3.0 + (5/2)
3.0 + 2
3.0 + 2.0
5

5/2 executes first, giving back 2.

Hope this helps!

Confusion with simple math in C++

The expression 0.5 * 17 results in a floating point value by virtue of the fact that one of its components, 0.5, is floating point.

However, when you assign a floating point number like 8.5 to an integer, it's truncated to 8. And, to be clear about this, it's truncated at the point of assignment.

So the first code segment calculates the value 100 + 8.5 = 108.5 and truncates that to 108 when you assign it to the integer(a). The subtraction of 100 from that then gives you 8.

In the second code segment, you calculate the value 100 - 8.5 = 91.5 and truncate that to 91 when assigning to the integer. The subtraction of that from 100 gives you 9.

The reason the final two code segments work is because the 8.5 is being truncated earlier in int myInt2 = 0.5 * 17, before being added to or subtracted from 100. In that case, 100 + 8 = 108 and 100 - 8 = 92, both which are different from 100 by exactly 8 (sign notwithstanding).


(a) It may help to think of it graphically:

int myInt2 = myInt + (0.5    * 17);
^ int + double * int
| \ \__________/
| \ |
| \ double
| \_____________/
| |
+- truncate <- double
  • The 0.5 * 17 is calculated first to give the floating point 8.5.
  • This is then added to the integer myInt = 100 to give the floating point 108.5.
  • This is then truncated to 108 when being assigned to the integer myInt2.


Related Topics



Leave a reply



Submit