C++20 是否为 "overflow" 的有符号整数很好地定义了左移?
Does C++20 well-define left shift for signed integers that "overflow"?
在目前的C++标准草案中,左移运算符定义如下[expr.shift]:
The value of E1 << E2
is the unique value congruent to E1×2^E2
modulo 2^N
, where N
is the width of the type of the result.
考虑具有 32 位的 int E1 = 2^31-1 = 2'147'483'647
、E2 = 1
和 int
。则有无限个数与E1×2^E2 = 4'294'967'294
模2^N = 2^32
同余,即所有数4'294'967'294 + k×2^32
其中k
是一个任意整数。例如 4'294'967'294
(k=0
) 或 -2
(k=-1
).
我不明白标准中这些数字中的唯一值是什么意思。是指可以用结果数据类型表示的唯一值吗?然后,我假设结果定义为 -2
。这个解释正确吗?
在 C++20 之前,定义有所不同,这种情况会导致未定义的行为。我想这个变化与负符号整数的强制性 2 的补码表示有关。
事实上,现在不再要求E1
为非负数。因此,似乎 -1 << 1
被定义为 -2
。是吗?
所以我们知道:
E1 = 2147483647
E2 = 1
N = sizeof(int) * CHAR_BIT = 4 * 8 = 32
让我们计算 E1×2^E2 modulo 2^N
(modulo 是除法的余数):
x = E1×2^E2 mod 2^N = 2147483647 * 2 ^ 1 mod 4294967296 = 4294967294 mod 4294967296 = 4294967294
然后我们去here:
For each value x of a signed integer type, the value of the
corresponding unsigned integer type congruent to x modulo 2 N has
the same value of corresponding bits in its value representation.
而且我认为我们还需要:
The base-2 representation of a value of signed integer type is the
base-2 representation of the congruent value of the corresponding
unsigned integer type.
这意味着,对于 signed int
,x = 4294967294
等于 x = -2
。所以结果将是 -2
.
It therefore seems that -1 << 1 is defined as -2. Is it right as well?
(signed)-1 << 1 =
4294967295 << 1 =
4294967295 * 2 ^ 1 mod 4294967296 =
8589934590 mod 4294967296 =
4294967294 =
(signed)-2
Does it mean the unique value that can be represented by the resulting
data type
是的。与 E1×2^E2
模 2^N
一致的一组数是无限的,但在任何大小 2^N
的区间中只有一个值,因此只有一个值可以表示为宽度的整数类型N
.
如果我们查看 "p0907R1 Signed Integers are Two’s Complement" proposal,我们会发现一个与 "unique representation" 相似的短语,这使这一点更加清楚:
Conversion from signed to unsigned is always well-defined: the result
is the unique value of the destination type that is congruent to the
source integer modulo 2N.
Then, I suppose the result is defined as -2
. Is this interpretation
correct?
是
在 x64 上等效的 asm 指令是 shlx
(逻辑左移)
I suppose the change is related to the mandatory 2-complement
representation of negative signed integers.
正确。与无符号类型的情况一样,现在也有符号类型,它们在数学上表示等价 类(好吧,我不清楚这在多大程度上是正确的,因为看起来他们仍然希望在溢出时保留一些 UB 案例)。
在目前的C++标准草案中,左移运算符定义如下[expr.shift]:
The value of
E1 << E2
is the unique value congruent toE1×2^E2
modulo2^N
, whereN
is the width of the type of the result.
考虑具有 32 位的 int E1 = 2^31-1 = 2'147'483'647
、E2 = 1
和 int
。则有无限个数与E1×2^E2 = 4'294'967'294
模2^N = 2^32
同余,即所有数4'294'967'294 + k×2^32
其中k
是一个任意整数。例如 4'294'967'294
(k=0
) 或 -2
(k=-1
).
我不明白标准中这些数字中的唯一值是什么意思。是指可以用结果数据类型表示的唯一值吗?然后,我假设结果定义为 -2
。这个解释正确吗?
在 C++20 之前,定义有所不同,这种情况会导致未定义的行为。我想这个变化与负符号整数的强制性 2 的补码表示有关。
事实上,现在不再要求E1
为非负数。因此,似乎 -1 << 1
被定义为 -2
。是吗?
所以我们知道:
E1 = 2147483647
E2 = 1
N = sizeof(int) * CHAR_BIT = 4 * 8 = 32
让我们计算 E1×2^E2 modulo 2^N
(modulo 是除法的余数):
x = E1×2^E2 mod 2^N = 2147483647 * 2 ^ 1 mod 4294967296 = 4294967294 mod 4294967296 = 4294967294
然后我们去here:
For each value x of a signed integer type, the value of the corresponding unsigned integer type congruent to x modulo 2 N has the same value of corresponding bits in its value representation.
而且我认为我们还需要:
The base-2 representation of a value of signed integer type is the base-2 representation of the congruent value of the corresponding unsigned integer type.
这意味着,对于 signed int
,x = 4294967294
等于 x = -2
。所以结果将是 -2
.
It therefore seems that -1 << 1 is defined as -2. Is it right as well?
(signed)-1 << 1 =
4294967295 << 1 =
4294967295 * 2 ^ 1 mod 4294967296 =
8589934590 mod 4294967296 =
4294967294 =
(signed)-2
Does it mean the unique value that can be represented by the resulting data type
是的。与 E1×2^E2
模 2^N
一致的一组数是无限的,但在任何大小 2^N
的区间中只有一个值,因此只有一个值可以表示为宽度的整数类型N
.
如果我们查看 "p0907R1 Signed Integers are Two’s Complement" proposal,我们会发现一个与 "unique representation" 相似的短语,这使这一点更加清楚:
Conversion from signed to unsigned is always well-defined: the result is the unique value of the destination type that is congruent to the source integer modulo 2N.
Then, I suppose the result is defined as
-2
. Is this interpretation correct?
是
在 x64 上等效的 asm 指令是 shlx
(逻辑左移)
I suppose the change is related to the mandatory 2-complement representation of negative signed integers.
正确。与无符号类型的情况一样,现在也有符号类型,它们在数学上表示等价 类(好吧,我不清楚这在多大程度上是正确的,因为看起来他们仍然希望在溢出时保留一些 UB 案例)。