Replace ":" with "。"

This commit is contained in:
krahets
2023-08-27 22:49:47 +08:00
parent 71692af8c4
commit c5a7323817
47 changed files with 159 additions and 165 deletions

View File

@@ -2,7 +2,7 @@
谈及计算机中的数据我们会想到文本、图片、视频、语音、3D 模型等各种形式。尽管这些数据的组织形式各异,但它们都由各种基本数据类型构成。
**基本数据类型是 CPU 可以直接进行运算的类型**,在算法中直接被使用。它包括:
**基本数据类型是 CPU 可以直接进行运算的类型**,在算法中直接被使用,主要包括以下几种类型
- 整数类型 `byte` , `short` , `int` , `long`
- 浮点数类型 `float` , `double` ,用于表示小数。
@@ -11,7 +11,7 @@
**基本数据类型以二进制的形式存储在计算机中**。一个二进制位即为 $1$ 比特。在绝大多数现代系统中,$1$ 字节byte由 $8$ 比特bits组成。
基本数据类型的取值范围取决于其占用的空间大小,例如 Java 规定:
基本数据类型的取值范围取决于其占用的空间大小。下面以 Java 为例。
- 整数类型 `byte` 占用 $1$ byte = $8$ bits ,可以表示 $2^{8}$ 个数字。
- 整数类型 `int` 占用 $4$ bytes = $32$ bits ,可以表示 $2^{32}$ 个数字。
@@ -31,7 +31,7 @@
| 字符 | `char` | 2 bytes / 1 byte | $0$ | $2^{16} - 1$ | $0$ |
| 布尔 | `bool` | 1 byte | $\text{false}$ | $\text{true}$ | $\text{false}$ |
对于上表,需要注意以下几点
对于上表,需要注意以下几点
- C, C++ 未明确规定基本数据类型大小,而因实现和平台各异。上表遵循 LP64 [数据模型](https://en.cppreference.com/w/cpp/language/types#Properties),其用于 Unix 64 位操作系统(例如 Linux , macOS
- 字符 `char` 的大小在 C, C++ 中为 1 字节,在大多数编程语言中取决于特定的字符编码方法,详见“字符编码”章节。

View File

@@ -40,10 +40,10 @@ Unicode 是一种字符集标准,本质上是给每个字符分配一个编号
目前UTF-8 已成为国际上使用最广泛的 Unicode 编码方法。**它是一种可变长的编码**,使用 1 到 4 个字节来表示一个字符根据字符的复杂性而变。ASCII 字符只需要 1 个字节,拉丁字母和希腊字母需要 2 个字节,常用的中文字符需要 3 个字节,其他的一些生僻字符需要 4 个字节。
UTF-8 的编码规则并不复杂,分为两种情况
UTF-8 的编码规则并不复杂,分为以下两种情况
1. 对于长度为 1 字节的字符,将最高位设置为 $0$ 、其余 7 位设置为 Unicode 码点。值得注意的是ASCII 字符在 Unicode 字符集中占据了前 128 个码点。也就是说,**UTF-8 编码可以向下兼容 ASCII 码**。这意味着我们可以使用 UTF-8 来解析年代久远的 ASCII 码文本。
2. 对于长度为 $n$ 字节的字符(其中 $n > 1$),将首个字节的高 $n$ 位都设置为 $1$ 、第 $n + 1$ 位设置为 $0$ ;从第二个字节开始,将每个字节的高 2 位都设置为 $10$ ;其余所有位用于填充字符的 Unicode 码点。
- 对于长度为 1 字节的字符,将最高位设置为 $0$ 、其余 7 位设置为 Unicode 码点。值得注意的是ASCII 字符在 Unicode 字符集中占据了前 128 个码点。也就是说,**UTF-8 编码可以向下兼容 ASCII 码**。这意味着我们可以使用 UTF-8 来解析年代久远的 ASCII 码文本。
- 对于长度为 $n$ 字节的字符(其中 $n > 1$),将首个字节的高 $n$ 位都设置为 $1$ 、第 $n + 1$ 位设置为 $0$ ;从第二个字节开始,将每个字节的高 2 位都设置为 $10$ ;其余所有位用于填充字符的 Unicode 码点。
下图展示了“Hello算法”对应的 UTF-8 编码。观察发现,由于最高 $n$ 位都被设置为 $1$ ,因此系统可以通过读取最高位 $1$ 的个数来解析出字符的长度为 $n$ 。
@@ -53,7 +53,7 @@ UTF-8 的编码规则并不复杂,分为两种情况:
![UTF-8 编码示例](character_encoding.assets/utf-8_hello_algo.png)
除了 UTF-8 之外,常见的编码方式还包括
除了 UTF-8 之外,常见的编码方式还包括以下两种。
- **UTF-16 编码**:使用 2 或 4 个字节来表示一个字符。所有的 ASCII 字符和常用的非英文字符,都用 2 个字节表示;少数字符需要用到 4 个字节表示。对于 2 字节的字符UTF-16 编码与 Unicode 码点相等。
- **UTF-32 编码**:每个字符都使用 4 个字节。这意味着 UTF-32 会比 UTF-8 和 UTF-16 更占用空间,特别是对于 ASCII 字符占比较高的文本。
@@ -64,13 +64,13 @@ UTF-8 的编码规则并不复杂,分为两种情况:
## 编程语言的字符编码
对于以往的大多数编程语言,程序运行中的字符串都采用 UTF-16 或 UTF-32 这类等长的编码。这是因为在等长编码下,我们可以将字符串看作数组来处理,其优点包括:
对于以往的大多数编程语言,程序运行中的字符串都采用 UTF-16 或 UTF-32 这类等长的编码。在等长编码下,我们可以将字符串看作数组来处理,这种做法具有以下优点。
- **随机访问**: UTF-16 编码的字符串可以很容易地进行随机访问。UTF-8 是一种变长编码,要找到第 $i$ 个字符,我们需要从字符串的开始处遍历到第 $i$ 个字符,这需要 $O(n)$ 的时间。
- **字符计数**: 与随机访问类似,计算 UTF-16 字符串的长度也是 $O(1)$ 的操作。但是,计算 UTF-8 编码的字符串的长度需要遍历整个字符串。
- **字符串操作**: 在 UTF-16 编码的字符串中,很多字符串操作(如分割、连接、插入、删除等)都更容易进行。在 UTF-8 编码的字符串上进行这些操作通常需要额外的计算,以确保不会产生无效的 UTF-8 编码。
实际上,编程语言的字符编码方案设计是一个很有趣的话题,其涉及到许多因素
实际上,编程语言的字符编码方案设计是一个很有趣的话题,其涉及到许多因素
- Java 的 `String` 类型使用 UTF-16 编码,每个字符占用 2 字节。这是因为 Java 语言设计之初,人们认为 16 位足以表示所有可能的字符。然而,这是一个不正确的判断。后来 Unicode 规范扩展到了超过 16 位,所以 Java 中的字符现在可能由一对 16 位的值(称为“代理对”)表示。
- JavaScript 和 TypeScript 的字符串使用 UTF-16 编码的原因与 Java 类似。当 JavaScript 语言在 1995 年被 Netscape 公司首次引入时Unicode 还处于相对早期的阶段,那时候使用 16 位的编码就足够表示所有的 Unicode 字符了。
@@ -78,7 +78,7 @@ UTF-8 的编码规则并不复杂,分为两种情况:
由于以上编程语言对字符数量的低估,它们不得不采取“代理对”的方式来表示超过 16 位长度的 Unicode 字符。这是一个不得已为之的无奈之举。一方面,包含代理对的字符串中,一个字符可能占用 2 字节或 4 字节,从而丧失了等长编码的优势。另一方面,处理代理对需要增加额外代码,这增加了编程的复杂性和 Debug 难度。
出于以上原因,部分编程语言提出了不同的编码方案
出于以上原因,部分编程语言提出了一些不同的编码方案
- Python 3 使用一种灵活的字符串表示,存储的字符长度取决于字符串中最大的 Unicode 码点。对于全部是 ASCII 字符的字符串,每个字符占用 1 个字节;如果字符串中包含的字符超出了 ASCII 范围但全部在基本多语言平面BMP每个字符占用 2 个字节;如果字符串中有超出 BMP 的字符,那么每个字符占用 4 个字节。
- Go 语言的 `string` 类型在内部使用 UTF-8 编码。Go 语言还提供了 `rune` 类型,它用于表示单个 Unicode 码点。

View File

@@ -8,7 +8,7 @@
在上一节的表格中我们发现,所有整数类型能够表示的负数都比正数多一个,例如 `byte` 的取值范围是 $[-128, 127]$ 。这个现象比较反直觉,它的内在原因涉及到原码、反码、补码的相关知识。
首先需要指出,**数字是以“补码”的形式存储在计算机中的**。在分析这样做的原因之前,我们首先给出三者的定义
首先需要指出,**数字是以“补码”的形式存储在计算机中的**。在分析这样做的原因之前,我们首先给出三者的定义
- **原码**:我们将数字的二进制表示的最高位视为符号位,其中 $0$ 表示正数,$1$ 表示负数,其余位表示数字的值。
- **反码**:正数的反码与其原码相同,负数的反码是对其原码除符号位外的所有位取反。
@@ -96,7 +96,7 @@ $$
b_{31} b_{30} b_{29} \ldots b_2 b_1 b_0
$$
根据 IEEE 754 标准32-bit 长度的 `float` 由以下部分构成
根据 IEEE 754 标准32-bit 长度的 `float` 由以下三个部分构成
- 符号位 $\mathrm{S}$ :占 1 bit ,对应 $b_{31}$ 。
- 指数位 $\mathrm{E}$ :占 8 bits ,对应 $b_{30} b_{29} \ldots b_{23}$ 。
@@ -145,9 +145,6 @@ $$
| $1, 2, \dots, 254$ | 正规数 | 正规数 | $(-1)^{\mathrm{S}} \times 2^{(\mathrm{E} -127)} \times (1.\mathrm{N})$ |
| $255$ | $\pm \infty$ | $\mathrm{NaN}$ | |
特别地,次正规数显著提升了浮点数的精度,这是因为:
值得说明的是,次正规数显著提升了浮点数的精度。最小正正规数为 $2^{-126}$ ,最小正次正规数为 $2^{-126} \times 2^{-23}$ 。
- 最小正正规数为 $2^{-126} \approx 1.18 \times 10^{-38}$
- 最小正次正规数为 $2^{-126} \times 2^{-23} \approx 1.4 \times 10^{-45}$ 。
双精度 `double` 也采用类似 `float` 的表示方法,此处不再详述。
双精度 `double` 也采用类似 `float` 的表示方法,在此不做赘述