【问题标题】:Order of commutative mathematical operations交换数学运算的顺序
【发布时间】:2018-09-05 12:04:58
【问题描述】:

我有一个好奇的问题(在阅读一段粗略的代码时自己问)。再来看看表达式:

double a =  c*d*e*2/3*f;

其中 c、d、e、f 是 double 类型的初始化变量。标准是否保证它将被视为c*d*e*2(双重结果)然后除以3并乘以f(或一些类似的行为)。显然,2/3 被计算为 0 是不可取的。

标准的哪一段定义了这一点?

【问题讨论】:

标签: c++ operators language-lawyer type-promotion


【解决方案1】:

基于standard

[intro.abstract] - 注释 7(非规范):

运算符可以根据通常的数学规则重新组合 仅当运算符真正具有关联性或可交换性时。

MDAS 的数学规则是从左到右(考虑到运算符的关联性和优先级)。所以评价如下:

(((((c * d) * e) * 2) / 3) * f)

【讨论】:

  • 您链接到的部分是关于函数对象的。那句话根本不在那儿。
  • 我知道它应该在那里!您的链接指向错误的段落,但它在 p.4.1.1 中。但是知道措辞,我找到了。
  • 现在是不存在的第 1.7 节。只需将 name 部分放入您的答案中,即带有段落编号的[chpater.subchapter.etc]。这不会在修订之间发生太大变化,并将在未来证明您的答案。它也比笼统的“标准”提供更多信息。
  • 这是[intro.abstract]/7,但它是非规范性注释(您应该提及它)。应该有更好的报价。
  • @Swift new 来自哪里?我说的是可读性,而不是动态分配。我在嵌入式系统上工作过,并不是因为你有细节,所以你不能写出易于阅读的代码。
【解决方案2】:

一句话——是的。

您要查找的属性称为运算符关联性。它定义了相同优先级的运算符(例如*/)在不存在括号时如何分组和排序。

在您的情况下,*/ 具有相同的优先级,并且都是左关联的 - 即,它们从左到右进行评估。这意味着c 将乘以d,然后将结果乘以e,然后将结果乘以2(这将通过浮点运算完成,因为您将double 乘以@ 987654331@ 字面量),然后除以 3(同样,使用浮点运算),最后乘以 f

有关更多信息,请参阅this cppreference page

【讨论】:

    【解决方案3】:

    */ 具有相同的优先级,并且是从左到右关联的,这意味着

    a*b*c*d
    

    被解析为

    ((a*b)*c)*d
    

    如果您将任何* 替换为/,情况也是如此。

    来源:http://en.cppreference.com/w/cpp/language/operator_precedence

    【讨论】:

    • @Swift 浮点运算不可交换,因为中间结果的舍入错误。如果你使用 gcc,你可以使用 --ffast-math 忽略它。
    • @mch 我想你的意思是 associative ;) 当然a*b == b*a(a*b)*c != a*(b*c)
    • @mch 我已经纠正了!不,不是 gcc,甚至不是 IEEE-754 二进制文件。十进制版本,192 位。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多