【问题标题】:What is the casting order of operations in arithmetics in c++?c++中算术运算的转换顺序是什么?
【发布时间】:2021-12-31 09:51:36
【问题描述】:

为什么

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

在 C++ 中返回 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


    【解决方案1】:

    没有“强制转换顺序”之类的东西,因为表达式的类型取决于它的操作数。简单来说,如果一个二元算术运算符接受两个不同类型的操作数,那么较小的类型将隐式转换为较宽的类型

    result = static_cast&lt;double&gt;(1 / (i+1)) 中是这样解析的

    • i + 1int 表达式,因为 i1 都是 int 类型
    • 1 / (i + 1) 出于同样的原因返回 int
    • 然后将1 / (i + 1) 的结果静态转换为double

    OTOH in result = 1 / (i+static_cast&lt;double&gt;(1)) 是这样的

    • 1 被转换为 double
    • i + static_cast&lt;double&gt;(1) 返回 double 因为 i 被转换为 double 由于另一个操作数
    • 1 / (i+static_cast&lt;double&gt;(1))double 表达式,原因相同

    但是没有人会这样。最好改成1 / (i + 1.0)

    完整的规则是这样的

    • 如果任一操作数具有范围枚举类型,则不执行转换:另一个操作数和返回类型必须具有相同的类型
    • 否则,如果任一操作数为long double,则另一操作数转换为long double
    • 否则,如果任一操作数为double,则另一操作数转换为double
    • 否则,如果任一操作数为float,则另一操作数转换为float
    • 否则,操作数为整数类型(因为此时会提升boolcharchar8_tchar16_tchar32_twchar_t 和无作用域枚举)并应用整数转换产生普通类型,如下:
      • 如果两个操作数都带符号或都无符号,则转换等级较低的操作数将转换为整数转换等级较高的操作数
      • 否则,如果无符号操作数的转换等级大于或等于有符号操作数的转换等级,则将有符号操作数转换为无符号操作数的类型。
      • 否则,如果有符号操作数的类型可以表示无符号操作数的所有值,则将无符号操作数转换为有符号操作数的类型
      • 否则,两个操作数都将转换为有符号操作数类型的无符号对应物。

    上述转化排名依次增加boolsigned charshortintlonglong long。任何无符号类型的等级都等于相应有符号类型的等级。 char 的等级等于signed charunsigned char 的等级。 char8_tchar16_tchar32_twchar_t 的秩等于它们底层类型的秩。

    Arithmetic operators

    【讨论】:

    • 太好了,谢谢!这正是我一直在寻找的答案。我发现 1.0 的技巧特别有用!
    【解决方案2】:

    你应该知道Integer Divison

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

    【讨论】:

      【解决方案3】:
      static_cast<double>(1 / (i+1));
      

      首先,1 / (i+1) 进行评估。因为 1 是 inti+1int,所以这是整数除法,所以 1/(i+1)int。然后将结果类型转换为double。所以从技术上讲,static_cast&lt;double&gt;(1 / (i+1)); 返回一个double,但是结果丢失了,因为1/(i+1) 是整数除法

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

      现在因为static_cast&lt;double&gt;(i+1) 是双精度,1 / static_cast&lt;double&gt;(i+1); 现在是浮点除法,因此1 / static_cast&lt;double&gt;(i+1);double

      【讨论】:

      • 当然,1.0 /(i + 1) 更好。
      猜你喜欢
      • 1970-01-01
      • 2015-09-17
      • 2023-01-21
      • 1970-01-01
      • 2014-08-31
      • 1970-01-01
      • 2015-07-19
      • 2014-08-13
      相关资源
      最近更新 更多