【问题标题】:C: What does x = !y mean?C: x = !y 是什么意思?
【发布时间】:2014-10-13 20:40:51
【问题描述】:

我正在阅读 C 语言中的加泰罗尼亚数字算法的代码,但我发现了我不太理解的短语。这是(递归):

typedef unsigned long long ull;

ull catalan2(int n) {
int i;
ull r = !n;

for (i = 0; i < n; i++)
    r += catalan2(i) * catalan2(n - 1 - i);
return r;
}

谁能告诉我这句话是什么 r = !n 负责这里?

提前谢谢你!

【问题讨论】:

标签: c algorithm recursion numbers


【解决方案1】:

这个:

ull r = !n;

相当于这个:

ull r;
if (n == 0)
    r = 1;
else
    r = 0;

没有分支的棘手方法:

#include <limits.h>
...
ull r = 1-((unsigned)(n|(-n))>>(sizeof(n)*CHAR_BIT-1));

【讨论】:

  • 一个好的编译器很可能会为原始公式生成比“无分支”版本更好的代码。除了关于可读性的任何问题。 (尝试使用 gcc:3 个非分支指令与 5 个。)
  • 虽然棘手的方法似乎对 -INT_MIN 有问题,但可能取决于 2 的补码、无填充、yadda、yadda、+1 以增加答案的乐趣。 IAC 1st 2/3rds 的答案清晰正确。
  • @rici:与按位操作技巧相比,这种“分支方式”可能会降低性能。这实际上取决于底层硬件架构以及手头指定的编译器。但它肯定会导致性能不一致,具体取决于n 的值和分支预测启发式。 “棘手的方式”的运行时间保证在每次执行时都相同。
  • @chux:谢谢。我看不出这会产生什么问题,就像INT_MIN|(-INT_MIN) == INT_MIN
  • @barakmanos:需要明确的是,由 gcc 为 intel 架构生成的代码没有分支。它甚至不使用 CMOV;相反,它会进行测试,然后从适当的条件位设置已清除寄存器的低位。 (但是,CMOV 也不是一个分支,并且不会导致失败的分支预测惩罚。)因此它还将具有一致的执行时间,大约是您解决方案的一半。
【解决方案2】:

x = !y 表示“将 y 评估为布尔值并返回相反的布尔值”

所以如果 y 为零,那么它是假的,我们返回一个真值(即 1)。否则,y 为真,我们返回零。

【讨论】:

    【解决方案3】:

    ull r = !n; 等价于ull r = n == 0 ? 1 : 0;n == 0 时占空树; for 循环计算非空树。

    【讨论】:

      【解决方案4】:

      r != n 表示:如果n 不为零,则分配0,否则将1 分配给r

      【讨论】:

        猜你喜欢
        • 2014-10-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-18
        • 1970-01-01
        • 1970-01-01
        • 2014-11-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多