This commit is contained in:
krahets
2026-08-18 03:09:26 +08:00
parent 0375f25b66
commit fde23f369e
158 changed files with 312 additions and 282 deletions
@@ -4672,8 +4672,8 @@
<div class="arithmatex">\[
\begin{aligned}
&amp; 1 + (-2) \newline
&amp; \rightarrow 0000 \. 0001 + 1000 \. 0010 \newline
&amp; = 1000 \. 0011 \newline
&amp; \rightarrow 0000 \; 0001 + 1000 \; 0010 \newline
&amp; = 1000 \; 0011 \newline
&amp; \rightarrow -3
\end{aligned}
\]</div>
@@ -4681,38 +4681,38 @@
<div class="arithmatex">\[
\begin{aligned}
&amp; 1 + (-2) \newline
&amp; \rightarrow 0000 \. 0001 \. \text{(прямой код)} + 1000 \. 0010 \. \text{(прямой код)} \newline
&amp; = 0000 \. 0001 \. \text{(обратный код)} + 1111 \. 1101 \. \text{(обратный код)} \newline
&amp; = 1111 \. 1110 \. \text{(обратный код)} \newline
&amp; = 1000 \. 0001 \. \text{(прямой код)} \newline
&amp; \rightarrow 0000 \; 0001 \; \text{(прямой код)} + 1000 \; 0010 \; \text{(прямой код)} \newline
&amp; = 0000 \; 0001 \; \text{(обратный код)} + 1111 \; 1101 \; \text{(обратный код)} \newline
&amp; = 1111 \; 1110 \; \text{(обратный код)} \newline
&amp; = 1000 \; 0001 \; \text{(прямой код)} \newline
&amp; \rightarrow -1
\end{aligned}
\]</div>
<p>С другой стороны, **в прямом коде у нуля есть два представления: <span class="arithmatex">\(+0\)</span> и <span class="arithmatex">\(-0\)</span> **. Это означает, что числу ноль соответствуют два разных двоичных кода, что может приводить к неоднозначности. Например, если в условном выражении не различать положительный и отрицательный ноль, можно получить ошибочный результат. А если специально обрабатывать такую неоднозначность, придется вводить дополнительные проверки, что может снизить вычислительную эффективность компьютера.</p>
<div class="arithmatex">\[
\begin{aligned}
+0 &amp; \rightarrow 0000 \. 0000 \newline
-0 &amp; \rightarrow 1000 \. 0000
+0 &amp; \rightarrow 0000 \; 0000 \newline
-0 &amp; \rightarrow 1000 \; 0000
\end{aligned}
\]</div>
<p>Как и прямой код, обратный код тоже страдает от неоднозначности положительного и отрицательного нуля, поэтому компьютеры ввели <u>дополнительный код (2's complement)</u>. Сначала посмотрим на процесс преобразования отрицательного нуля из прямого кода в обратный, а затем в дополнительный:</p>
<div class="arithmatex">\[
\begin{aligned}
-0 \rightarrow \. &amp; 1000 \. 0000 \. \text{(прямой код)} \newline
= \. &amp; 1111 \. 1111 \. \text{(обратный код)} \newline
= 1 \. &amp; 0000 \. 0000 \. \text{(дополнительный код)} \newline
-0 \rightarrow \; &amp; 1000 \; 0000 \; \text{(прямой код)} \newline
= \; &amp; 1111 \; 1111 \; \text{(обратный код)} \newline
= 1 \; &amp; 0000 \; 0000 \; \text{(дополнительный код)} \newline
\end{aligned}
\]</div>
<p>При добавлении <span class="arithmatex">\(1\)</span> к обратному коду отрицательного нуля возникает перенос, но длина типа <code>byte</code> составляет всего 8 бит, поэтому переполнившаяся в 9-й бит единица отбрасывается. Иными словами, <strong>дополнительный код отрицательного нуля равен <span class="arithmatex">\(0000 \. 0000\)</span> и совпадает с дополнительным кодом положительного нуля</strong>. Значит, в представлении дополнительного кода существует только один ноль, и проблема неоднозначности положительного и отрицательного нуля тем самым устраняется.</p>
<p>При добавлении <span class="arithmatex">\(1\)</span> к обратному коду отрицательного нуля возникает перенос, но длина типа <code>byte</code> составляет всего 8 бит, поэтому переполнившаяся в 9-й бит единица отбрасывается. Иными словами, <strong>дополнительный код отрицательного нуля равен <span class="arithmatex">\(0000 \; 0000\)</span> и совпадает с дополнительным кодом положительного нуля</strong>. Значит, в представлении дополнительного кода существует только один ноль, и проблема неоднозначности положительного и отрицательного нуля тем самым устраняется.</p>
<p>Остается последний вопрос: диапазон типа <code>byte</code> равен <span class="arithmatex">\([-128, 127]\)</span> , откуда берется лишнее отрицательное число <span class="arithmatex">\(-128\)</span> ? Мы замечаем, что у всех целых чисел из интервала <span class="arithmatex">\([-127, +127]\)</span> есть соответствующие прямой, обратный и дополнительный коды, а прямой и дополнительный коды можно преобразовывать друг в друга.</p>
<p>Однако <strong>дополнительный код <span class="arithmatex">\(1000 \. 0000\)</span> является исключением: у него нет соответствующего прямого кода</strong>. Согласно правилу преобразования, прямой код для этого дополнительного кода должен быть равен <span class="arithmatex">\(0000 \. 0000\)</span> . Это очевидное противоречие, потому что такой прямой код обозначает число <span class="arithmatex">\(0\)</span> , а его дополнительный код должен совпадать с ним самим. Компьютер просто определяет, что этот особый дополнительный код <span class="arithmatex">\(1000 \. 0000\)</span> представляет число <span class="arithmatex">\(-128\)</span> . На самом деле результат вычисления <span class="arithmatex">\((-1) + (-127)\)</span> в дополнительном коде как раз и равен <span class="arithmatex">\(-128\)</span> .</p>
<p>Однако <strong>дополнительный код <span class="arithmatex">\(1000 \; 0000\)</span> является исключением: у него нет соответствующего прямого кода</strong>. Согласно правилу преобразования, прямой код для этого дополнительного кода должен быть равен <span class="arithmatex">\(0000 \; 0000\)</span> . Это очевидное противоречие, потому что такой прямой код обозначает число <span class="arithmatex">\(0\)</span> , а его дополнительный код должен совпадать с ним самим. Компьютер просто определяет, что этот особый дополнительный код <span class="arithmatex">\(1000 \; 0000\)</span> представляет число <span class="arithmatex">\(-128\)</span> . На самом деле результат вычисления <span class="arithmatex">\((-1) + (-127)\)</span> в дополнительном коде как раз и равен <span class="arithmatex">\(-128\)</span> .</p>
<div class="arithmatex">\[
\begin{aligned}
&amp; (-127) + (-1) \newline
&amp; \rightarrow 1111 \. 1111 \. \text{(прямой код)} + 1000 \. 0001 \. \text{(прямой код)} \newline
&amp; = 1000 \. 0000 \. \text{(обратный код)} + 1111 \. 1110 \. \text{(обратный код)} \newline
&amp; = 1000 \. 0001 \. \text{(дополнительный код)} + 1111 \. 1111 \. \text{(дополнительный код)} \newline
&amp; = 1000 \. 0000 \. \text{(дополнительный код)} \newline
&amp; \rightarrow 1111 \; 1111 \; \text{(прямой код)} + 1000 \; 0001 \; \text{(прямой код)} \newline
&amp; = 1000 \; 0000 \; \text{(обратный код)} + 1111 \; 1110 \; \text{(обратный код)} \newline
&amp; = 1000 \; 0001 \; \text{(дополнительный код)} + 1111 \; 1111 \; \text{(дополнительный код)} \newline
&amp; = 1000 \; 0000 \; \text{(дополнительный код)} \newline
&amp; \rightarrow -128
\end{aligned}
\]</div>