为什么 C++20 的 `std::popcount` 仅限于无符号类型?

He3*_*xxx 41 c++ language-design language-lawyer c++20

P0553R4中的功能:位运算仅限于无符号整数。该提案没有给出这一限制的理由。我可以看到,如果没有定义有符号整数的位表示,这是有意义的,但使用 C++20,我们可以保证有符号整数使用二进制补码。

对我来说,允许使用有符号整数类型调用eg似乎是合理的std::popcount,因为实现可以简单地转换为相应的无符号类型以在无符号域中执行位操作。

P0553R4添加这个约束的原因是什么?(只是 P0553R4 和 P0907R4 之间缺少同步吗?)

Ben*_*igt 71

非常简单:无符号类型的隐式扩大转换不会改变结果。有符号类型(包括提升)的隐式扩展转换会执行符号扩展,如果输入为负数,这会更改结果。

由于整数提升而导致结果不正确的操作肯定属于“脚炮”类别。

您仍然可以将负值(表示的位模式)提供给popcount,但您必须控制转换顺序,这有助于您获得预期的结果。

  • @TedLyngmo:[标签:语言律师]根本不适合“为什么?” 问题所以我忽略了它。我还没有去查看提案,因为 OP 表示他已经这样做了。 (6认同)
  • @Artyer:“countl_zero(int)”不是有效的重载意味着“countl_zero(x+1)”对于窄无符号“x”来说是一个错误,它会提升为“+”的有符号“int”(https:// godbolt.org/z/WGvx644h5),所以你意识到你需要 `static_cast<unsigned char>`。顺便说一句,即使使用有符号类型,在扩大非负整数时,前导零计数仍然会发生变化。此外,源类型而不是目标类型决定是否发生零扩展或符号扩展,因此对于 `int x`、`popcount(x | 1uLL)` 或 `countl_zero(x | 1uLL)` 将符号扩展为 64 -bit(或任何 unsigned long long )。 (6认同)
  • 对于无符号类型的“std::countl_zero”也可以使用相同的参数 (5认同)
  • @supercat:我并不是说你应该调用“log(x)/log(2.0)`来查找最高非零位的位置,我是说你提出的函数已经被命名了——你有一个有效的整数“log2()” (4认同)
  • @supercat:俗称“log2()”如无特殊说明,请参见https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog (3认同)
  • @BenVoigt:或者,定义一个报告最高非零位索引的函数(例如,对于 64 到 127 范围内的值(包括 64 到 127),该索引为 6,无论涉及的类型的大小如何)。 (2认同)
  • @supercat:最高设置位的索引是 x86 的“bsr”指令产生的。要将其用于“__builtin_clz(unsigned int)”,GCC 会执行“xor eax, 31”。https://godbolt.org/z/vqsKWsjfx (由于内置函数(如指令),当输入为零时不会产生正常结果,因此它不必像 C 那样生成“32” ++20 `countl_zero`。)但是,是的,如果您自己想要 MSB 索引又名 ilog2,则需要自己撤消 `31-clz` 或 `31^clz`,并依赖编译器优化回仅 ` bsr` 指令(或 `31-lzcnt` 如果可用,因为在 AMD 上速度更快。) (2认同)
  • 不管怎样,有时 MSB 索引是你真正想要的,如果没有一个函数是不方便的,而是必须想出一种在任何地方都是正确的方法来做到这一点,但编译器可以优化到单个指令。`bsr`/`bsf` 的内在特性比新的 `lzcnt` / `tzcnt` 的可移植性要差,而且你不一定想限制自己,而是让编译器在优化时选择 `lzcnt` AMD。 (2认同)

ein*_*ica 25

popcount对位进行计数,因此采用旨在​​用作“位容器”的类型。

  • 无符号整数类型旨在用作位容器(或模 2^n 值)。
  • 有符号整数类型旨在用作数字,更抽象一些。

是的,确实,从 C++20 开始,有符号整数就保证了二进制补码语义,但这是一个非必要的细节 - 这正是为什么直到 C++20 才保证二进制补码的原因。如果您不是语言律师,您可能甚至都没有意识到这种变化。

因此,与其试图成为语言律师/人类百科全书,不如对可能以其他方式定义的类型的确切语义做出更少的假设。如果你做出这样的假设 - 你可能会很幸运并正确地进行popcount;但你可能会被@BenVoigt 的回答所困扰。

另请参阅我对此问题的回答中同一原则的应用。