简介:计算机编程中的随机数生成、补码编码以及浮点数表示方法。随机数的生成原理,包括其数学基础和实际应用中的讨论过程。接着讲解了补码编码的概念及其在正负数表示中的应用,并通过具体例子说明了补码编码的工作原理。最后,介绍了浮点数的二进制表示方法,包括小数点的位置记录和小数部分的转换过程,强调了浮点数精度问题的重要性。整个讲解旨在帮助学习者理解计算机内部数据表示和处理的基础知识。

伪随机与真随机

伪随机数生成器(PRNG)

计算机通常使用伪随机数生成器(PRNG)来生成随机数。PRNG 使用确定性算法基于初始种子值生成一个看起来随机的数列。这些数虽然对于很多应用来说“足够随机”,但从数学上讲,它们是可预测的,只要知道初始种子和生成算法。

硬件随机数生成器(HRNG)

为了生成更高质量的随机数,有些计算机系统使用硬件随机数生成器(HRNG)。HRNG 基于物理现象来生成随机数,例如:

  1. 热噪声:利用电阻中的热噪声(Johnson-Nyquist noise)。

  2. 光电效应:通过测量光电效应中的随机光子到达时间。

  3. 量子现象:基于量子力学的原理,如量子隧道效应。

真随机数与伪随机数

  • 真随机数:来源于不可预测的物理现象,如上所述的HRNG。这些现象被认为是本质上的随机,因此可以提供真正的随机性。

  • 伪随机数:由确定性算法生成的数列,看起来随机但实际上是可预测的。

现实应用

在实践中,计算机通常会结合使用 PRNG 和 HRNG 来生成随机数。常见的方法是:

  1. 混合方法:使用HRNG产生高质量的种子,然后将其输入到PRNG中生成大规模的随机数。

  2. 定期重新种子:PRNG定期从HRNG中获取新的种子以保持随机数的质量。

限制与挑战

尽管HRNG能够生成真随机数,但它们也面临一些挑战:

  1. 硬件故障:物理硬件可能会出现故障或受到环境影响,从而影响随机数的质量。

  2. 速度和成本:HRNG通常比PRNG慢且成本更高,因此在大规模应用中会更依赖于PRNG。

总结

计算机可以生成真随机数,但通常需要依赖物理现象和专门的硬件(HRNG)。而在大多数应用中,结合使用HRNG和PRNG的方法能够在保持高随机性的同时满足性能和成本的要求。

伪随机数的实现与应用

1.微软的C运行时库(CRT)中的srandrand函数用于生成随机数序列。 【CRT是c run time】

2.rand函数通过一个全局静态变量(种子)和特定的算法来生成随机数序列。

3.该随机数生成方法存在倾向性,不适合需要高度随机性的应用,如密码学。

4.勒索软件作者使用高精度随机数生成器来增强软件的复杂性,增加破解难度。

cpp随机数函数

#include <iostream>
#include <random>

int main() {
    // 使用随机设备生成种子
    std::random_device rd;
    // 使用Mersenne Twister算法生成随机数
    std::mt19937 gen(rd());
    // 生成均匀分布的整数随机数,范围在1到100之间
    std::uniform_int_distribution<> dis(1, 100);

    // 生成并打印10个随机数
    for (int n = 0; n < 10; ++n) {
        std::cout << dis(gen) << ' ';
    }
    std::cout << '\n';

    return 0;
}

cpp的库 cstdlibrand(): 生成一个随机数srand(unsigned int seed): 设置随机数生成器的种子。

补码与编码

计算机只能做到加法和移运算,乘法通过位运算实现

补码(Two's Complement)

补码是一种用于表示带符号整数的二进制编码方法,广泛应用于计算机系统中。它的主要优点是简化了加减法运算的实现。以下是补码的详细说明:

原理

补码表示法通过将正数和负数统一在同一种编码格式下,使得计算加法和减法变得更加简便。对于一个 n 位二进制数:

  • 正数:与原码(binary representation)相同。

  • 负数:取反码(invert all bits)后加 1。

例如,对于一个 8 位二进制数:

  • 正数 5 的二进制表示为 0000 0101

  • 负数 -5 的二进制表示为 1111 1011

特点

  • 零的唯一表示:在补码中,零只有一种表示形式(全零)。

  • 对称性:补码表示法使得正负数的表示是对称的,简化了硬件电路的设计。

示例

以 4 位二进制数为例:

|十进制|原码|反码|补码| |-|-|-|-| |5|0101|0101|0101| |-5|1101|1010|1011|

优点

  • 简化运算:补码的加法和减法运算与无符号数的运算相同,简化了硬件实现。

  • 统一符号处理:统一了正数和负数的处理方式,避免了额外的符号处理步骤。

编码(Encoding)

编码是将信息转换为特定格式的过程,广泛应用于数据传输、存储和处理。不同的编码方式适用于不同的应用场景。以下是几种常见的编码方法:

1. 字符编码

字符编码用于将字符集(如文字、符号)转换为计算机可处理的二进制数据。

  • ASCII:American Standard Code for Information Interchange,用于表示基本的英文字母和控制字符。

  • UTF-8:Unicode Transformation Format, 8-bit,用于表示全球各种语言的字符,是互联网使用最广泛的编码方式。

  • UTF-16UTF-32:同样用于Unicode字符集,但使用不同的位宽。

2. 数据编码

数据编码用于将数据转换为特定格式以便传输和存储。

  • Base64:将二进制数据编码为ASCII字符串,用于电子邮件和网络传输。

  • URL 编码:将URL中的特殊字符编码为%加上两位十六进制数。

3. 压缩编码

压缩编码用于减少数据的存储空间和传输时间。

  • Huffman编码:基于字符出现频率的压缩编码,常用于文本压缩。

  • LZW:Lempel-Ziv-Welch算法,用于图像压缩(如GIF格式)。

补码与编码的联系

  • 计算机系统:补码是计算机系统中处理带符号整数的基础,而各种编码方法则用于处理和传输不同类型的数据。

  • 数据表示与传输:补码主要用于数据的内部表示和计算,而编码更多地用于数据的存储和传输。

参考资料

求补运算是一种运算,而补码是一种编码,补码规定了数据的读写双方必须做到以下几点:

  1. 最高有效位是符号位,0表示正数,1表示负数(0正1负)

  2. 当数据是正数的时候,其余的各位直接存储其数值

  3. 反之当数据是负数的时候,其余的各位直接存储其求补之后的数值

计算机减法

A - B = A + (100 - B) - 100

B + ~B = ff

B + ~B + 1 = 100

~B + 1 = 100 - B //求补运算

所以 A - B = A + neg(B) -100 //进位丢失

例如 85 - 23 = 85 + (100 - 23)= 85 + 77 = 162 //进位丢失 = 62

浮点数的精度问题可能导致数学上相等的值在计算机中不相等,因为它们可能无法精确表示为二进制形式。

浮点数的编码与运算

  1. .浮点数的编码需要考虑符号位、指数位和尾数位的存储和计算。

  2. 指数位的计算涉及到对数的底数和偏移量的选择,以适应不同大小的数值范围。

  3. 尾数位的存储采用科学计数法,通过调整小数点的位置来适应不同的数值大小。

浮点数是一种用于表示非常大或非常小的数的方法,广泛应用于科学计算、工程应用和计算机图形学中。IEEE 754标准定义了浮点数的表示和运算规则,这是目前最常用的浮点数标准。

浮点数的编码

IEEE 754 标准

根据 IEEE 754 标准,浮点数表示包括以下几部分:

  1. 符号位(S):1 位,表示数的符号,0 表示正数,1 表示负数。

  2. 指数位(E):对于单精度浮点数(32 位),有 8 位;对于双精度浮点数(64 位),有 11 位。

  3. 尾数位(M)或有效数字(Significand):对于单精度浮点数,有 23 位;对于双精度浮点数,有 52 位。

单精度浮点数(32 位)

  • 符号位(S):1 位

  • 指数位(E):8 位

  • 尾数位(M):23 位

表示形式:(-1)^S * 1.M * 2^(E-127)

例如,浮点数 32-bit 的二进制表示:

S   EEEEEEEE   MMMMMMMMMMMMMMMMMMMMMMM
0   10000011   00000000000000000000000

这个浮点数表示的是:(-1)^0 * 1.0 * 2^(131-127) = 1.0 * 2^4 = 16.0

双精度浮点数(64 位)

  • 符号位(S):1 位

  • 指数位(E):11 位

  • 尾数位(M):52 位

表示形式:(-1)^S * 1.M * 2^(E-1023)

例如,浮点数 64-bit 的二进制表示:

S    EEEEEEEEEEE    MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
0    10000000011    0000000000000000000000000000000000000000000000000000

这个浮点数表示的是:(-1)^0 * 1.0 * 2^(1027-1023) = 1.0 * 2^4 = 16.0

浮点数的运算

浮点数的基本运算包括加法、减法、乘法和除法。下面简要介绍一下这些运算的基本步骤。

加法和减法

  1. 对阶:将两个浮点数的指数对齐,即使得两个数的指数相同,通过调整尾数实现。

  2. 尾数相加/相减:对齐指数后,进行尾数的加法或减法。

  3. 规格化:结果可能需要规格化,即调整尾数使其符合规范化形式,同时调整指数。

  4. 舍入:根据需要对结果进行舍入处理。

  5. 检测溢出和下溢:检查结果是否超过了表示范围。

乘法和除法

  1. 符号计算:确定结果的符号。

  2. 指数计算:指数相加(乘法)或相减(除法)。

  3. 尾数计算:尾数相乘或相除。

  4. 规格化:结果可能需要规格化。

  5. 舍入:根据需要对结果进行舍入处理。

  6. 检测溢出和下溢:检查结果是否超过了表示范围。

特殊值

IEEE 754 还定义了一些特殊值:

  • :分为正零和负零。

  • 无穷大:正无穷大和负无穷大,用于表示溢出结果。

  • NaN(Not a Number):用于表示未定义或无法表示的结果,如 0/0 或 sqrt(-1)。