Why does
result = static_cast<double>(1 / (i 1))
return int in C and why does
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 1is anintexpression since bothiand1are of typeint1 / (i 1)returns int for the same reason- Then the result of
1 / (i 1)is statically cast todouble
OTOH in result = 1 / (i static_cast<double>(1)) it's like this
1is cast todoublei static_cast<double>(1)returnsdoublebecauseiis cast todoubledue to the other operand1 / (i static_cast<double>(1))is adoubleexpression 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 tolong double- Otherwise, if either operand is
double, the other operand is converted todouble- Otherwise, if either operand is
float, the other operand is converted tofloat- 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 ofcharis equal to the rank ofsigned charandunsigned char. The ranks ofchar8_t,char16_t,char32_t, andwchar_tare equal to the ranks of their underlying types.
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.
