Sha*_*ble 6 c# binary integer-overflow twos-complement
我目前正在阅读一本关于C#编程的书,它简要介绍了溢出和下溢,并且作者总结了当你超越特定类型的允许范围时会发生什么.
例
short a = 30000;
short b = 30000;
short sum = (short)(a + b); // Explicitly cast back into short
Console.WriteLine(sum); // This would output the value -5536
Run Code Online (Sandbox Code Playgroud)
所以short类型只有-32768到32767的范围,书中给出的解释是"对于整数类型(byte,short,int和long),最高位(溢出)被丢弃这是特别奇怪的,因为计算机然后将其解释为环绕.这就是我们在示例中最终得到负值的原因.如果从特定类型的最大值开始,您可以很容易地看到这种情况发生(例如,short.MaxValue)并添加一个." C#Players Guide第二版,第9章,第58页
你最终会达到最低限度(-32768).
我有一个问题理解这一点当作家谈到"计算机将其解释为环绕"时我感到困惑
我尝试理解这个的方式是短类型使用2个字节(16位)
所以数字32767 = 0111111111111111,如果我要+1到二进制字符串我最终得到32768 = 1000000000000000(不能用短类型表示为最大值是32767)所以编译器给出-32768.为什么它最终成为负面?
我理解使用二元恭维来表示负数的概念,有人可以在这里纠正我的想法或详细说明因为我不完全理解为什么我们只使用16位的15位来表示正范围和最重要的位负范围
Eri*_*ert 17
忽略所有告诉你顶部位是符号位的人.这是错误的思考方式.
正确的思考方式是:
对于无符号短路,我们分配位模式如下:
0000000000000000 --> 0
0000000000000001 --> 1
...
0111111111111111 --> 32767
1000000000000000 --> 32768
1000000000000001 --> 32769
...
1111111111111111 --> 65535
Run Code Online (Sandbox Code Playgroud)
对于签名短裤,我们使用以下约定:
0000000000000000 --> 0
0000000000000001 --> 1
...
0111111111111111 --> 32767
1000000000000000 --> -32768
1000000000000001 --> -32767
...
1111111111111111 --> -1
Run Code Online (Sandbox Code Playgroud)
就那么简单.
为什么我们使用这个约定?
三个原因:
(1)无论您是签名还是未签名,前32K值都是相同的.这很方便.
(2)在两种惯例中,"所有零位"表示零.
(3)因为加法在两个约定中完全相同!
我们有
0000000000000000 --> 0
Run Code Online (Sandbox Code Playgroud)
我们想要添加一个.我们使用二进制规则添加一个,我们得到:
0000000000000001 --> 1
Run Code Online (Sandbox Code Playgroud)
无论短签是签名还是未签名,这都有效.
我们有未签名的短信:
1000000000000000 --> 32768
Run Code Online (Sandbox Code Playgroud)
我们希望补充一个.我们使用二进制规则,我们得到了正确的答案:
1000000000000001 --> 32769
Run Code Online (Sandbox Code Playgroud)
签名短裤相同.我们有
1000000000000000 --> -32768
Run Code Online (Sandbox Code Playgroud)
我们希望补充一个.我们使用二进制规则,我们得到:
1000000000000001 --> -32767
Run Code Online (Sandbox Code Playgroud)
类似地,您可以通过添加1111111111111111到任何二进制数来验证"少一个",因此减去一个可以工作,也可以添加一个.然后,您可以继续显示通常,加法和减法在有符号和无符号算术中的工作方式相同,这意味着处理器不必知道编译器是认为值是有符号还是无符号.
这就是为什么我们使用二进制补码:因为无论你是使用有符号算术还是无符号算术,底层数学都是完全相同的.
请注意,我在那里没有说任何关于"符号位"的内容.将高位设置为负数这一事实只是一个很好的奖励.我们想要的不动产只需要构建硬件来做一次数学运算.
二进制补码仅仅是基于与保持该位模式的变量相关联的类型将两种可能含义之一分配给位模式的约定.作为一个行业,我们选择了这个惯例,因为制作使用这种约定的高性能硬件很便宜.
我们可以选择许多其他惯例.例如,我们可以说,对于带符号的数字,我们使用地图:
0000000000000000 --> -32768
0000000000000001 --> -32767
...
0111111111111111 --> -1
1000000000000000 --> 0
1000000000000001 --> 1
...
1111111111111111 --> 32767
Run Code Online (Sandbox Code Playgroud)
注意,这是完全相同一样,除了最高位之前!
在此解释中,添加仍然按预期工作.但是这个映射不具有short和ushort之间的前32K值相同的属性,并且它没有所有零位表示零的属性.所以我们不使用这个约定,因为它不太方便.在这个约定中,从short转换为ushort需要进行添加.将short设置为零需要将字节设置为零以外的值.我们可以使用签名数字"按顺序"的约定,我们只是不这样做,因为这样做很痛苦.