Home > Enterprise >  What is the casting order of operations in arithmetics in c ?
What is the casting order of operations in arithmetics in c ?

Time:11-22

Why does

  1. result = static_cast<double>(1 / (i 1))

return int in C and why does

  1. result = 1 / (i static_cast<double>(1))

return double? Specifically why is casting after the -operation sufficient to produce a double. Why is it not required before the or in the numerator as well? Is static_cast the preferred way of casting?

Code:

double harmonic(int n) {
  double result = 0;
  for (int i = 0; i < n; i  ) {
    result  = 1 / static_cast<double>(i 1);
  }
  return result;
}

CodePudding user response:

There's no such thing as "casting order" because the type of an expression depends on its operands. Put it simply, if a binary arithmetic operator accepts two operands of different types then the smaller type will be implicitly converted to the wider type

In result = static_cast<double>(1 / (i 1)) it's parsed like this

  • i 1 is an int expression since both i and 1 are of type int
  • 1 / (i 1) returns int for the same reason
  • Then the result of 1 / (i 1) is statically cast to double

OTOH in result = 1 / (i static_cast<double>(1)) it's like this

  • 1 is cast to double
  • i static_cast<double>(1) returns double because i is cast to double due to the other operand
  • 1 / (i static_cast<double>(1)) is a double expression for the same reason

But no one cast like that. It's better to do 1 / (i 1.0) instead

The complete rule is like this

  • If either operand has scoped enumeration type, no conversion is performed: the other operand and the return type must have the same type
  • Otherwise, if either operand is long double, the other operand is converted to long double
  • Otherwise, if either operand is double, the other operand is converted to double
  • Otherwise, if either operand is float, the other operand is converted to float
  • Otherwise, the operand has integer type (because bool, char, char8_t, char16_t, char32_t, wchar_t, and unscoped enumeration were promoted at this point) and integral conversions are applied to produce the common type, as follows:
    • If both operands are signed or both are unsigned, the operand with lesser conversion rank is converted to the operand with the greater integer conversion rank
    • Otherwise, if the unsigned operand's conversion rank is greater or equal to the conversion rank of the signed operand, the signed operand is converted to the unsigned operand's type.
    • Otherwise, if the signed operand's type can represent all values of the unsigned operand, the unsigned operand is converted to the signed operand's type
    • Otherwise, both operands are converted to the unsigned counterpart of the signed operand's type.

The conversion rank above increases in order bool, signed char, short, int, long, long long. The rank of any unsigned type is equal to the rank of the corresponding signed type. The rank of char is equal to the rank of signed char and unsigned char. The ranks of char8_t, char16_t, char32_t, and wchar_t are equal to the ranks of their underlying types.

Arithmetic operators

CodePudding user response:

static_cast<double>(1 / (i 1));

First, 1 / (i 1) get evaluate. Because 1 is an int and i 1 is an int, so this is integer division, so 1/(i 1) is an int. The result is then typecast into a double. So technically, static_cast<double>(1 / (i 1)); returns a double, but the result is lost because 1/(i 1) is integer division

result  = 1 / static_cast<double>(i 1);

Now becuase static_cast<double>(i 1) is a double, 1 / static_cast<double>(i 1); is now floating point divison, thus 1 / static_cast<double>(i 1); is a double

CodePudding user response:

You should be aware of Integer Divison

You can use this code to see, that it actually returns a double. However, due to integer division, it will always be zero (or nan).

#include <iostream>

using std::cout;

int main()
{
    int i = 5;
    cout << typeid(static_cast<double>(1 / (i 1))).name() << "\n"; // d for double
    return 0;
}

You can circumvent integer division, by not dividing two integers. Therefor it is enough if one of them is a double.

int double == double
double int == double
int / double == double
double / int == double

So you can see, it is enough to only cast one summand to double, in order to turn the whole expression into a double, which is not always zero.

  • Related