有符号整数的三种编码方式:原码、反码和补码
<p>在计算机中,<strong>原码、反码、补码</strong> 是用于表示有符号整数的三种编码方式,主要用于解决二进制数的 <strong>正负表示</strong> 和 <strong>加减运算</strong> 问题。它们的核心区别在于 <strong>符号位的处理</strong> 和 <strong>负数的表示方法</strong>。</p><hr>
<h2 id="原码sign-magnitude">原码(Sign-Magnitude)</h2>
<h3 id="定义">定义</h3>
<ul>
<li>最高位(最左边的一位)表示符号:
<ul>
<li><strong><code>0</code> 表示正数</strong>(如 <code>+5</code>)</li>
<li><strong><code>1</code> 表示负数</strong>(如 <code>-5</code>)</li>
</ul>
</li>
<li>其余位表示数值的绝对值。</li>
</ul>
<h3 id="示例8位二进制">示例(8位二进制)</h3>
<table>
<thead>
<tr>
<th>十进制</th>
<th>原码表示(8位)</th>
</tr>
</thead>
<tbody>
<tr>
<td>+5</td>
<td><code>0000 0101</code></td>
</tr>
<tr>
<td>-5</td>
<td><code>1000 0101</code></td>
</tr>
</tbody>
</table>
<h3 id="特点">特点</h3>
<p>✅ <strong>直观</strong>:和人类书写习惯一致(正负号+数值)。<br>
❌ <strong>问题</strong>:</p>
<ol>
<li><strong><code>+0</code> 和 <code>-0</code> 不唯一</strong>:
<ul>
<li><code>+0</code> = <code>0000 0000</code></li>
<li><code>-0</code> = <code>1000 0000</code>(计算机无法区分)</li>
</ul>
</li>
<li><strong>加减运算复杂</strong>:
<ul>
<li>需要额外判断符号位,硬件实现麻烦。</li>
</ul>
</li>
</ol>
<hr>
<h2 id="反码ones-complement">反码(Ones' Complement)</h2>
<h3 id="定义-1">定义</h3>
<ul>
<li><strong>正数</strong>:和原码相同。</li>
<li><strong>负数</strong>:在原码基础上,<strong>符号位不变,数值位取反</strong>(<code>0</code>→<code>1</code>,<code>1</code>→<code>0</code>)。</li>
</ul>
<h3 id="示例8位二进制-1">示例(8位二进制)</h3>
<table>
<thead>
<tr>
<th>十进制</th>
<th>反码表示(8位)</th>
</tr>
</thead>
<tbody>
<tr>
<td>+5</td>
<td><code>0000 0101</code></td>
</tr>
<tr>
<td>-5</td>
<td><code>1111 1010</code></td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th style="text-align: center">十进制运算</th>
<th style="text-align: center">反码计算</th>
<th style="text-align: center">反码计算结果(十进制)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">1 +(-1)=0</td>
<td style="text-align: center">反 + 反 = 反 = 原</td>
<td style="text-align: center">-0</td>
</tr>
<tr>
<td style="text-align: center">1 +(-2)= -1</td>
<td style="text-align: center">反 + 反 = 反 = 原</td>
<td style="text-align: center">-1</td>
</tr>
<tr>
<td style="text-align: center">-1 +(2)= 1</td>
<td style="text-align: center">反 + 反 = 反<strong>(溢出)</strong> = 原</td>
<td style="text-align: center">0(<strong>溢出归0</strong>)</td>
</tr>
</tbody>
</table>
<p>从上表可以看出,如果用反码直接进行计算,虽然有所改善,但仍有问题,所以计算机中的运算也不能直接用反码。</p>
<h3 id="特点-1">特点</h3>
<p><strong>仍然存在 <code>+0</code> 和 <code>-0</code> 问题</strong></p>
<ul>
<li><code>+0</code> = <code>0000 0000</code></li>
<li><code>-0</code> = <code>1111 1111</code>(仍然无意义)</li>
</ul>
<p><strong>运算仍需调整</strong>:</p>
<ul>
<li>加减法后可能需要 <strong>“循环进位”</strong>(如 <code>1 + (-1)</code> = <code>0000 0001</code> + <code>1111 1110</code> = <code>1111 1111</code>(<code>-0</code>),需要额外加 <code>1</code> 修正)。</li>
</ul>
<hr>
<h2 id="补码twos-complement现代计算机标准">补码(Two's Complement)⭐(现代计算机标准)</h2>
<h3 id="定义-2">定义</h3>
<ul>
<li><strong>正数</strong>:和原码相同。</li>
<li><strong>负数</strong>:在反码基础上 <strong>+1</strong>(即 <code>原码取反 + 1</code>)。</li>
</ul>
<h3 id="示例8位二进制-2">示例(8位二进制)</h3>
<table>
<thead>
<tr>
<th>十进制</th>
<th>补码表示(8位)</th>
</tr>
</thead>
<tbody>
<tr>
<td>+5</td>
<td><code>0000 0101</code></td>
</tr>
<tr>
<td>-5</td>
<td><code>1111 1011</code></td>
</tr>
</tbody>
</table>
<h3 id="计算--5-的补码">计算 <code>-5</code> 的补码</h3>
<ol>
<li><code>+5</code> 原码 = <code>0000 0101</code></li>
<li><strong>取反</strong> = <code>1111 1010</code>(反码)</li>
<li><strong>+1</strong> = <code>1111 1011</code>(补码)</li>
</ol>
<p>举个例子,如果是8位的二进制数:</p>
<blockquote>
<p>[+1] = 原 = 反 = 补</p>
<p>[-1] = 原 =反 = 补</p>
<p>[-2] = 原 = 反 = 补</p>
</blockquote>
<table>
<thead>
<tr>
<th style="text-align: center">十进制运算</th>
<th style="text-align: center">补码计算</th>
<th style="text-align: center">补码计算结果(十进制)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">1 +(-1)=0</td>
<td style="text-align: center">补 + 补 = 补 = 原</td>
<td style="text-align: center">0(<strong>溢出位舍弃</strong>)</td>
</tr>
<tr>
<td style="text-align: center">1 +(-2)= -1</td>
<td style="text-align: center">补 + 补 = 补 = 反 = 原</td>
<td style="text-align: center">-1</td>
</tr>
<tr>
<td style="text-align: center">-1 +(2)= 1</td>
<td style="text-align: center">补 + 补 = 补 = 原</td>
<td style="text-align: center">1(<strong>溢出位舍弃</strong>)</td>
</tr>
</tbody>
</table>
<p>从上表可以看出,如果使用补码进行计算,就可以正常的进行加法算术运算了。</p>
<h3 id="特点-2">特点</h3>
<p>✅ <strong>解决所有问题</strong>:</p>
<ol>
<li>
<p><strong><code>+0</code> 和 <code>-0</code> 统一</strong>:</p>
<ul>
<li><code>+0</code> = <code>0000 0000</code></li>
<li><code>-0</code> :原码 <code>1000 0000</code> → 反码 <code>1111 1111</code> → 补码 <code>0000 0000</code>(和 <code>+0</code> 相同)。</li>
</ul>
</li>
<li>
<p><strong>加减法直接运算</strong>:</p>
<ul>
<li><code>5 + (-3)</code> = <code>0000 0101</code> + <code>1111 1101</code> = <code>0000 0010</code>(<code>2</code>,正确)。</li>
</ul>
</li>
<li>
<p><strong>表示范围更大</strong>:</p>
<ul>
<li>8位补码范围:<code>-128</code>(<code>1000 0000</code>)~ <code>+127</code>(<code>0111 1111</code>),比原码/反码多一个数(<code>-128</code>)。</li>
</ul>
</li>
</ol>
<p>那么至此,总结两个非常重要的结论:</p>
<ol>
<li><strong>正数的原码反码补码是一致的,负数的反码是原码除符号位取反,补码是反码+1。</strong></li>
<li><strong>计算机中有符号整数的存储方式都是以补码的形式存储的,运算也是以补码的形式计算的。</strong></li>
</ol>
<hr>
<h2 id="三种编码对比8位二进制">三种编码对比(8位二进制)</h2>
<table>
<thead>
<tr>
<th>十进制</th>
<th>原码</th>
<th>反码</th>
<th>补码</th>
</tr>
</thead>
<tbody>
<tr>
<td>+5</td>
<td><code>0000 0101</code></td>
<td><code>0000 0101</code></td>
<td><code>0000 0101</code></td>
</tr>
<tr>
<td>-5</td>
<td><code>1000 0101</code></td>
<td><code>1111 1010</code></td>
<td><code>1111 1011</code></td>
</tr>
<tr>
<td>+0</td>
<td><code>0000 0000</code></td>
<td><code>0000 0000</code></td>
<td><code>0000 0000</code></td>
</tr>
<tr>
<td>-0</td>
<td><code>1000 0000</code></td>
<td><code>1111 1111</code></td>
<td><code>0000 0000</code></td>
</tr>
<tr>
<td>-128</td>
<td>无法表示</td>
<td>无法表示</td>
<td><code>1000 0000</code></td>
</tr>
</tbody>
</table>
<hr>
<h2 id="为什么计算机使用补码">为什么计算机使用补码</h2>
<blockquote>
<ol>
<li><strong>统一 <code>+0</code> 和 <code>-0</code></strong>,避免歧义。</li>
<li><strong>加减法可以直接运算</strong>,无需额外判断符号。</li>
<li><strong>硬件实现简单</strong>,CPU 只需加法器,无需额外电路。</li>
<li><strong>表示范围更大</strong>(如 8 位补码可表示 <code>-128</code>~<code>127</code>,而原码/反码只能 <code>-127</code>~<code>127</code>)。</li>
</ol>
</blockquote>
<hr>
<h2 id="常见问题">常见问题</h2>
<h3 id="补码-1000-0000-代表多少">补码 <code>1000 0000</code> 代表多少</h3>
<ul>
<li>在 8 位补码中,<code>1000 0000</code> 表示 <code>-128</code>(没有对应的原码/反码)。</li>
</ul>
<h3 id="补码的运算溢出怎么办">补码的运算溢出怎么办</h3>
<ul>
<li>例如 <code>127 + 1</code> = <code>0111 1111</code> + <code>0000 0001</code> = <code>1000 0000</code>(<code>-128</code>,溢出)。</li>
<li>CPU 会设置 <strong>溢出标志位(OF)</strong>,由程序员处理。</li>
</ul>
<hr>
<h2 id="总结"><strong>总结</strong></h2>
<table>
<thead>
<tr>
<th>编码</th>
<th>优点</th>
<th>缺点</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>原码</strong></td>
<td>直观</td>
<td><code>±0</code> 问题,运算复杂</td>
<td>早期计算机(已淘汰)</td>
</tr>
<tr>
<td><strong>反码</strong></td>
<td>改进负数表示</td>
<td><code>±0</code> 仍存在,运算需调整</td>
<td>过渡方案(基本不用)</td>
</tr>
<tr>
<td><strong>补码</strong></td>
<td>无 <code>±0</code> 问题,运算简单</td>
<td>负数计算稍复杂</td>
<td><strong>现代计算机标准</strong></td>
</tr>
</tbody>
</table>
<p>补码是计算机存储和处理有符号整数的 <strong>最优方案</strong>,理解它对于学习 <strong>计算机组成原理、编程(如整数溢出)、逆向工程</strong> 都至关重要!</p><br><br>
来源:https://www.cnblogs.com/neozhuang/p/19057994/code-original-inverse-complement
頁:
[1]