C++20 是否为"overflow"的有符号整数很好地定义了左移?



在当前的C++标准草案中,左移运算符定义如下[expr.shift]:

E1 << E2的值是与模2^N全等E1×2^E2的唯一值,其中N是结果类型的宽度。

考虑int E1 = 2^31-1 = 2'147'483'647E2 = 1int有32位。然后有无限多个数全等到E1×2^E2 = 4'294'967'2942^N = 2^32,即所有数4'294'967'294 + k×2^32其中k是任意整数。例如4'294'967'294(k=0)或-2(k=-1)。

我不明白这些数字中的唯一值是什么意思。它是否表示可以由生成的数据类型表示的唯一值?然后,我想结果定义为-2.这种解释正确吗?

在C++20之前,定义是不同的,这种情况会导致未定义的行为。我想这种变化与负有符号整数的强制性 2's 补码表示有关。

事实上,现在不再要求E1是非负数。因此,似乎-1 << 1被定义为-2。也对吗?

它是否意味着可以由结果表示的唯一值 数据类型

是的。全等于E1×2^E22^N的数集是无穷大的,但是在任何大小2^N区间中只有一个值,因此在宽度N的整数类型中只有一个值可表示。

如果我们查看"p0907R1 有符号整数是 Two's Complement"提案,我们会发现一个类似的短语,其中包含"唯一表示",这使其更加清晰:

从有符号到无符号的转换始终是明确定义的:结果 是源整数模 2N

然后,我想结果定义为-2.这是解释吗 正确?

是的

在 x64 上,等效的 asm 指令shlx(逻辑左移)

我想这个变化与强制性的 2 补码有关 负有符号整数的表示形式。

正确。与无符号类型的情况一样,现在也有符号类型,它们在数学上表示等价类(好吧,我不清楚这有多真实,因为看起来他们仍然希望将一些 UB 案例保留在溢出上)。

所以我们知道:

E1 = 2147483647
E2 = 1
N = sizeof(int) * CHAR_BIT = 4 * 8 = 32

让我们计算E1×2^E2 modulo 2^N(模是除法的余数):

x = E1×2^E2 mod 2^N = 2147483647 * 2 ^ 1 mod 4294967296 = 4294967294 mod 4294967296 = 4294967294

然后我们去这里:

对于有符号整数类型的每个值 x,值 对应于 x 模 2 N 全等的无符号整数类型具有 其值表示形式中相应位的相同值。

我认为我们还需要:

有符号整数类型的值的 base-2 表示形式是 相应全等值的基数为 2 的表示 无符号整数类型。

这意味着,x = 4294967294等于x = -2signed int。所以结果将是-2.

因此,似乎 -1 <<1 被定义为 -2。也对吗?

(signed)-1 << 1 = 
4294967295 << 1 = 
4294967295 * 2 ^ 1 mod 4294967296 = 
8589934590 mod 4294967296 = 
4294967294 = 
(signed)-2

相关内容

最新更新