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 1
is anint
expression since bothi
and1
are of typeint
1 / (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
1
is cast todouble
i static_cast<double>(1)
returnsdouble
becausei
is cast todouble
due to the other operand1 / (i static_cast<double>(1))
is adouble
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 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 ofchar
is equal to the rank ofsigned char
andunsigned char
. The ranks ofchar8_t
,char16_t
,char32_t
, andwchar_t
are 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.