【问题标题】:The largest n-bit integer最大的 n 位整数
【发布时间】:2021-04-11 13:41:17
【问题描述】:

我认为通过使用位移来计算最大的n-bit 整数将是微不足道的。具体来说,我的想法是将所有位设置为 1,然后将它们向右移动:

template <typename T = uint16_t>
auto largest(uint8_t n){
    constexpr auto bits = 8*sizeof(T);
    assert(n <= bits);
    return static_cast<T>(-1) >> (bits - n);
}

一般来说,这个想法似乎可行。如果我打印出0, 1, ... 的结果,我会得到0, 1, 3,..., 65535(如预期的那样)。

然而,这就是事情变得奇怪的地方......

如果我使用uint32_tuint64_t 而不是uint16_t,那么我发现

largest<uint16_t>(1) = 1
largest<uint32_t>(1) = 1
largest<uint64_t>(1) = 1

这就是说,“最大的 1 位整数是 1”(正如预期的那样)。不过……

largest<uint16_t>(0) = 0
largest<uint32_t>(0) = 4294967295
largest<uint64_t>(0) = 18446744073709551615

所以如果我使用uint32_tuint64_t 来保存整数类型,0 的值似乎是一个边缘情况。

为了进一步诊断,我对这些边缘情况进行了硬编码,以便编译器可以更好地看到它:

static_cast<uint16_t>(-1) >> 16;
static_cast<uint32_t>(-1) >> 32;
static_cast<uint64_t>(-1) >> 64;

现在对于 32 位和 64 位情况,GCC 和 Clang 头都会抛出警告

prog.cc:22:31: warning: right shift count >= width of type [-Wshift-count-overflow]
   22 |     static_cast<uint64_t>(-1) >> 64;

我找不到任何文档说明为什么不允许这样做,以及为什么这只发生在 32 位和 64 位的情况下。我理解为什么它可能会抱怨 count &gt; width,但 count == width 的案例对我来说似乎是有效的。

有人知道发生了什么吗?

另外,我想听听关于如何计算最大 n 位整数而不必放入分支的建议(显然我可以专门处理 n==0 的情况)。

这是一个代码链接,这样您就不必重新输入所有内容:https://wandbox.org/permlink/3oqxqQR9ypP5q7yw

【问题讨论】:

  • 我找不到任何关于为什么不允许这样做的文档 -- See this 并找到按位移位运算符。如链接所述——在任何情况下,如果右操作数的值为负数或大于或等于提升的左操作数中的位数,行为未定义
  • “最大 0 位值”在您的域中是否有意义?你能排除它(如果使用它就断言)吗?
  • @PaulMcKenzie 提到的位移位限制(小于位数)可能看起来很奇怪,但这是由于 CPU 限制,否则需要发出额外的代码来覆盖这些更大的位移大小。
  • 如果您使用unsigneds 处理所有事情,为什么还要使用-1?您是否阅读过~ 运算符(要获得所有运算符,您可以使用~0U,它不会是未定义的,或实现定义的行为,因为在一个补码实现中-1 不是全部,而只是bit0 和符号位)
  • 老实说,我可能应该在这里使用 numeric_limits。 -1 只是我想到的第一件事。你有一个有效的点

标签: c++ gcc g++ clang


【解决方案1】:

您可以使用查找表来避免分支。

【讨论】:

    猜你喜欢
    • 2023-01-17
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 2019-11-09
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    相关资源
    最近更新 更多