为什么
result = static_cast<double>(1 / (i+1))
return
int
以及为什么
result = 1 / (i+static_cast<double>(1))
返回
double
?具体来说,为什么在 +
操作之后进行铸造足以产生 double
。为什么在 +
之前或分子中不需要它? static_cast
是首选的铸造方式吗?
代码:
double harmonic(int n) {
double result = 0;
for (int i = 0; i < n; i++) {
result += 1 / static_cast<double>(i+1);
}
return result;
}
不存在“转换顺序”这样的东西,因为表达式的类型取决于其操作数。简而言之,如果二元算术运算符接受两个不同类型的操作数,则较小的类型将隐式转换为较宽的类型
在
result = static_cast<double>(1 / (i+1))
中它是这样解析的
i + 1
是一个 int
表达式,因为 i
和 1
都是 int
1 / (i + 1)
出于同样的原因返回 int 1 / (i + 1)
的结果(即 int
)被静态转换为 double
OTOH在
result = 1 / (i+static_cast<double>(1))
是这样的
1
被投射到 double
i + static_cast<double>(1)
返回 double
,因为由于另一个操作数的秩较高,i
被上转换为 double
1 / (i+static_cast<double>(1))
是 double
表达式。它也是浮点除法,而不是像其他情况那样的整数除法但是不要那样投射。最好改为
1 / (i + 1.0)
或 1.0 / (i + 1)
完整的规则是这样的
- 如果任一操作数具有作用域枚举类型,则不执行转换:另一个操作数和返回类型必须具有相同的类型
- 否则,如果任一操作数为
,则另一个操作数将转换为long double
long double
- 否则,如果任一操作数为
,则另一个操作数将转换为double
double
- 否则,如果任一操作数为
,则另一个操作数将转换为float
float
- 否则,操作数具有整数类型(因为此时升级了
、bool
、char
、char8_t
、char16_t
、char32_t
和无作用域枚举)并应用积分转换来生成常见类型如下:wchar_t
- 如果两个操作数都是有符号的或都是无符号的,则具有较小转换等级的操作数将转换为具有较大整数转换等级的操作数
- 否则,如果无符号操作数的转换等级大于或等于有符号操作数的转换等级,则有符号操作数将转换为无符号操作数的类型。
- 否则,如果有符号操作数的类型可以表示无符号操作数的所有值,则无符号操作数将转换为有符号操作数的类型
- 否则,两个操作数都将转换为有符号操作数类型的无符号对应项。
上面的转化等级按照
、bool
、signed char
、short
、int
、long
的顺序增加。任何无符号类型的等级都等于相应的有符号类型的等级。long long
的等级等于char
和signed char
的等级。unsigned char
、char8_t
、char16_t
和char32_t
的排名等于其基础类型的排名。wchar_t
static_cast<double>(1 / (i+1));
首先,
1 / (i+1)
进行评估。因为 1 是一个 int
,i+1
是一个 int
,所以这是整数除法,所以 1/(i+1)
是一个 int
。然后将结果类型转换为 double
。所以从技术上讲,static_cast<double>(1 / (i+1));
返回一个double
,但结果丢失了,因为1/(i+1)
是整数除法
result += 1 / static_cast<double>(i+1);
现在因为
static_cast<double>(i+1)
是双精度数,1 / static_cast<double>(i+1);
现在是浮点除法,因此 1 / static_cast<double>(i+1);
是 double
您应该了解整数除法
您可以使用此代码来查看它实际上返回一个双精度值。但是,由于整数除法,它始终为零(或 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;
}
您可以通过不除两个整数来规避整数除法。因此,只要其中一个是双倍就足够了。
int + double == double
double + int == double
int / double == double
double / int == double
因此您可以看到,只需将一个被加数转换为 double 就足够了,以便将整个表达式转换为 double,而 double 并不总是为零。