C++ 中算术运算的转换顺序是什么?

问题描述 投票:0回答:3

为什么

  1. result = static_cast<double>(1 / (i+1))
C++ 中的

return

int
以及为什么

  1. 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;
}
c++ types casting arithmetic-expressions
3个回答
2
投票

不存在“转换顺序”这样的东西,因为表达式的类型取决于其操作数。简而言之,如果二元算术运算符接受两个不同类型的操作数,则较小的类型将隐式转换为较宽的类型

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
的排名等于其基础类型的排名。

算术运算符


1
投票
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


1
投票

您应该了解整数除法

您可以使用此代码来查看它实际上返回一个双精度值。但是,由于整数除法,它始终为零(或 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 并不总是为零。

© www.soinside.com 2019 - 2024. All rights reserved.