Skip to content

Great Reality

约 873 个字 10 行代码 预计阅读时间 4 分钟 共被读过

1. Ints are not Integers, Floats are not Reals

整数(Int)范围有限

  • 有限范围:整数在计算机中的表示是有范围的,这个范围取决于数据类型的位数(如 int 通常是 32 位或 16 位)。超出范围时会导致 溢出,出现意想不到的结果。
    • 补码的作用:溢出后数值会按照补码规则变成负数。例如:对于 16 位有符号整数,32767 + 1 会变成 -32768
    • 注意事项:在进行整数运算时需考虑溢出的可能性,特别是循环计数器或涉及极大数值的操作。

浮点数(Float)不等于实数

  • 舍入误差:浮点数采用二进制近似表示,导致无法精确表示某些实数。例如,0.1 在浮点数中不能被精确存储,会产生微小误差。
  • 注意事项:计算时避免直接比较两个浮点数,使用误差范围进行比较更可靠。

2. 你必须了解汇编语言(Assembly)

  • 重要性
    • 即使不直接编写汇编语言,理解其原理可以帮助我们更好地理解程序的底层运行机制。
    • 编译器生成的机器码和 CPU 指令优化都与汇编语言密切相关。
  • 用途
    • 分析性能瓶颈:通过反汇编代码可以了解编译器的优化。
    • 调试复杂问题:有时需要通过汇编级别分析程序行为。
    • 理解内存布局和指针操作:这些都在汇编级别体现得更直观。

3. Memory 很重要

  • 内存管理与保护
    • C 和 C++ 缺乏内置的内存保护机制,容易出现 缓冲区溢出(Buffer Overflow)悬挂指针(Dangling Pointer) 等问题。
    • 编写 C/C++ 程序时需特别小心内存分配和释放。
  • 现代语言的改进:许多现代语言(如 Java 和 Python)通过垃圾回收(Garbage Collection)和内存安全检查避免了这些问题,但了解底层内存原理依然非常重要。

4. 性能不仅仅是渐近复杂性

渐近复杂性(Asymptotic Complexity):

  • 常用大 O 表示法评估算法的性能,但在实际场景中,性能不仅仅由渐近复杂性决定。

示例:数组的访问模式

以下两段代码功能相同,但性能差异显著:

C
for(int i = 0; i < 1000; i++) {
    for (int j = 0; j < 1000; j++) {
        arr[i][j] = 1;
    }
}
C
for(int j = 0; j < 1000; j++) {
    for (int i = 0; i < 1000; i++) {
        arr[i][j] = 1;
    }
}
  • 前者的效率更高:因为前者按照内存的连续地址访问(行优先),符合 CPU 缓存的读取特性。
  • 后者效率低下:列优先访问会导致频繁的缓存未命中(Cache Miss)。

性能优化注意点:

  • 数据的局部性(Locality)对性能的影响很大。
  • 除了算法本身,硬件特性(如缓存层次结构和内存对齐)也需要关注。

5. 计算机不仅仅执行程序

  • 多功能性:计算机不仅仅是执行程序的机器,它们还支持:

    • 并行处理:同时处理多个任务或程序,充分利用多核架构。
    • 虚拟化:通过虚拟机实现资源隔离和多操作系统共存。
    • 硬件加速:利用 GPU、FPGA 等硬件单元提升特定任务的效率。
    • 网络交互:处理大量数据交互和通信任务,例如服务器运行 HTTP 请求。
    • 启发

    • 编程时不仅要关注代码逻辑,还需考虑计算机硬件的特性。

    • 学习了解硬件和系统层面知识,有助于设计更高效的程序。