Files
hello-algo/ru/docs/chapter_data_structure/number_encoding.md
T
2026-01-20 15:08:42 +08:00

72 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Кодирование чисел *
!!! tip
В этой книге разделы, отмеченные символом *, являются необязательными для чтения. Если у вас ограничено время или возникают трудности с пониманием, вы можете пропустить их и вернуться к ним после изучения обязательных разделов.
## Прямой, обратный и дополнительный коды
В таблице из предыдущего раздела можно заметить, что во всех целочисленных типах отрицательных чисел на одно больше, чем положительных. Например, диапазон значений `byte` составляет $[-128, 127]$. Этот факт кажется не совсем интуитивным, и его внутренняя причина связана с концепциями прямого, обратного и дополнительного кодов.
Прежде всего необходимо отметить, что **числа хранятся в компьютере в виде дополнительного кода**. Прежде чем проанализировать причины этого, сначала дадим определения всем трем кодам.
- **Прямой код**: старший бит двоичного представления числа рассматривается как знак, где $0$ обозначает положительное число, $1$ -- отрицательное, остальные биты представляют значение числа.
- **Обратный код**: обратный код положительного числа совпадает с его прямым кодом, обратный код отрицательного числа получается инверсией всех битов прямого кода, кроме знакового.
- **Дополнительный код**: дополнительный код положительного числа совпадает с его прямым кодом, дополнительный код отрицательного числа получается добавлением $1$ к его обратному коду.
На рис. 3.4 изображены методы преобразования прямого, обратного и дополнительного кодов между собой.
![Взаимное преобразование прямого, обратного и дополнительного кодов](../assets/1s_2s_complement.png)
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:<u>原码(sign-magnitude</u>虽然最直观,但存在一些局限性。一方面,**负数的原码不能直接用于运算**。例如在原码下计算 $1 + (-2)$ ,得到的结果是 $-3$ ,这显然是不对的... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:$$\begin{aligned}& 1 + (-2) \newline& \rightarrow 0000 \; 0001 + 1000 \; 0010 \newline& = 1000 \; 0011 \newline& \rightarrow -3\end{aligned}$$... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:为了解决此问题,计算机引入了<u>反码(1's complement</u>。如果我们先将原码转换为反码,并在反码下计算 $1 + (-2)$ ,最后将结果从反码转换回原码,则可得到正确结果 $-1$... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:$$\begin{aligned}& 1 + (-2) \newline& \rightarrow 0000 \; 0001 \; \text{(原码)} + 1000 \; 0010 \; \text{(原码)} \newline& = 0000 \; 0001 \; \text{(反码)} + 1111 \; 1101 \; \text{(反码)}... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:另一方面,**数字零的原码有 $+0$ 和 $-0$ 两种表示方式**。这意味着数字零对应两个不同的二进制编码,这可能会带来歧义... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:$$\begin{aligned}+0 & \rightarrow 0000 \; 0000 \newline-0 & \rightarrow 1000 \; 0000\end{aligned}$$... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:与原码一样,反码也存在正负零歧义问题,因此计算机进一步引入了<u>补码(2's complement</u>。我们先来观察一下负零的原码、反码、补码的转换过程... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:$$\begin{aligned}-0 \rightarrow \; & 1000 \; 0000 \; \text{(原码)} \newline= \; & 1111 \; 1111 \; \text{(反码)} \newline= 1 \; & 0000 \; 0000 \; \text{(补码)} \newline\end{aligned}$$... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:在负零的反码基础上加 $1$ 会产生进位,但 `byte` 类型的长度只有 8 位,因此溢出到第 9 位的 $1$ 会被舍弃。也就是说,**负零的补码为 $0000 \; 0000$ ,与正零的补码相同**... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:还剩最后一个疑惑:`byte` 类型的取值范围是 $[-128, 127]$ ,多出来的一个负数 $-128$ 是如何得到的呢?我们注意到,区间 $[-127, +127]$ 内的所有整数都有对应的原码、反码和补码... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:然而,**补码 $1000 \; 0000$ 是一个例外,它并没有对应的原码**。根据转换方法,我们得到该补码的原码为 $0000 \; 0000$... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:$$\begin{aligned}& (-127) + (-1) \newline& \rightarrow 1111 \; 1111 \; \text{(原码)} + 1000 \; 0001 \; \text{(原码)}... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:你可能已经发现了,上述所有计算都是加法运算。这暗示着一个重要事实:**计算机内部的硬件电路主要是基于加法运算设计的**... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:请注意,这并不意味着计算机只能做加法。**通过将加法与一些基本逻辑运算结合,计算机能够实现各种其他的数学运算**... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:现在我们可以总结出计算机使用补码的原因:基于补码表示,计算机可以用同样的电路和操作来处理正数和负数的加法... -->
<!-- 🔴 俄文版缺失此段落 -->
<!-- 中文原文:补码的设计非常精妙,因篇幅关系我们就先介绍到这里,建议有兴趣的读者进一步深入了解。 -->
## Кодирование чисел с плавающей запятой
<!-- 🔴 俄文版缺失整个"浮点数编码"章节 -->
<!-- 中文原文:细心的你可能会发现:`int``float` 长度相同,都是 4 字节 ,但为什么 `float` 的取值范围远大于 `int`... -->