一  定点数和浮点数

在计算机中,数值的存储和表示方式分为定点数浮点数,两者的核心区别在于小数点的位置是否固定。这一差异直接影响了它们的表示范围、精度及适用场景。

1、定点数(Fixed-Point Number)

定义:定点数是指小数点位置固定不变的机器数,通过预设小数点的位置来表示整数或小数。
由于计算机中没有实际的 “小数点” 符号,小数点的位置是人为约定的(仅在计算时逻辑上存在)。

定点数的两种约定形式

  • 定点整数:约定小数点在数值的最右端,即所有位均表示整数部分。
    例:8 位定点整数的格式为 符号位 整数位 整数位 ... 整数位 .(小数点隐含在最后)。
    如机器数 01001001 表示真值 +73(1001001₂=73₁₀)。

  • 定点小数:约定小数点在符号位与数值位之间,即所有位均表示小数部分。
    例:8 位定点小数的格式为 符号位 . 小数位 小数位 ... 小数位
    如机器数 10110000 表示真值 -0.375(0110000₂=24/64=0.375,符号位 1 表示负)。

特点

  • 优点:运算规则简单,硬件实现成本低。
  • 缺点:表示范围有限(受字长限制,整数部分位数固定),精度较低(小数部分位数固定)。
  • 适用场景:早期计算机、嵌入式系统等对精度要求不高,且数值范围较固定的场景。

2、浮点数(Floating-Point Number) 

定义:浮点数是指小数点位置不固定的机器数,通过 “科学计数法” 的思想表示数值,可灵活表示极大或极小的数。
其核心是将数值拆分为阶码(表示小数点的偏移量)和尾数(表示有效数字),类似十进制的 N = M × 10^E(如 123.45 = 1.2345 × 10²)。

 浮点数的格式(以 IEEE 754 标准为例)

计算机中浮点数通常遵循IEEE 754 标准,分为单精度(32 位)和双精度(64 位):

  • 单精度(32 位):1 位符号位 + 8 位阶码 + 23 位尾数

  • 双精度(64 位):1 位符号位 + 11 位阶码 + 52 位尾数

    • 符号位:0 表示正,1 表示负(与定点数一致)。
    • 阶码:表示指数部分,通常用移码(偏移量)表示(避免正负阶码的处理问题)。
    • 尾数:表示有效数字,通常为规范化形式(整数位为 1,隐含不存储,节省 1 位精度)。

    例:单精度浮点数 0 10000001 01000000000000000000000 表示:

    • 符号位 0(正),阶码 10000001(对应十进制 129,偏移量 127,实际阶码 = 129-127=2),尾数 010...(隐含整数位 1,即 1.01₂=1.25₁₀),因此真值 = 1.25×2²=5.0。

 特点

  • 优点:表示范围极大(阶码决定范围),精度较高(尾数位数多),能同时表示很大和很小的数。
  • 缺点:运算规则复杂(需对齐阶码),硬件实现成本高,存在精度损失(部分小数无法精确表示,如 0.1)。
  • 适用场景:科学计算、工程模拟等需要处理大范围数值或高精度小数的场景(如 PC、服务器)。

定点数与浮点数的对比

对比维度 定点数 浮点数
小数点位置 固定(整数末尾或符号位后) 不固定(由阶码动态调整)
表示范围 小(受字长和小数点位置限制) 大(阶码扩展了范围)
精度 低(小数位数固定) 高(尾数位数多,支持规范化)
运算复杂度 简单(直接加减乘除) 复杂(需先对齐阶码)
硬件成本
典型应用 嵌入式系统、整数运算 科学计算、图形处理、通用计算机

总结

  • 定点数适合范围固定、精度要求低的场景,实现简单;
  • 浮点数适合范围广、精度要求高的场景,灵活性强但实现复杂;
  • 两者本质是通过不同的小数点处理方式,平衡计算机的存储效率、运算能力和应用需求。

理解定点数与浮点数,是掌握计算机数值运算和存储原理的基础,尤其在底层编程、硬件设计中至关重要。

二 定点数的表示 

1. 无符号数

表示

无符号数是计算机中数值表示的一种基础形式,其核心特点是没有符号位,所有位均用于表示数值的大小,因此只能表示非负整数(0 及正整数)。这种表示方式简单直接,广泛应用于计数、地址编码、数据存储等场景。

  • 定义:无符号数仅包含数值部分,不区分正负,所有二进制位均为 “数值位”,用于表示数值的绝对值。

  • 格式:假设机器字长为 n 位(如 8 位、16 位、32 位等),则无符号数的每一位(从最低位 b₀ 到最高位 bₙ₋₁)均参与数值计算,遵循二进制计数规则(每位的权值为 2ⁱi 为位序号,从 0 开始)。

    例如,8 位无符号数的格式为:b₇ b₆ b₅ b₄ b₃ b₂ b₁ b₀,其中每一位 bᵢ 的权值为 2ⁱb₀ 权值为 2⁰=1b₇ 权值为 2⁷=128)。

表示范围

无符号数的表示范围由机器字长 n 决定,其最小值为 0(所有位均为 0),最大值为 2ⁿ - 1(所有位均为 1)。

机器字长指的是计算机 CPU 一次能直接处理的二进制数据的位数,单位为 “位(bit)”。它由 CPU 内部寄存器(如通用寄存器、累加器)的位数、运算器(ALU)的运算位数决定,是 CPU 硬件设计时固定的参数。

例如:

  • 8 位微处理器(如早期的 Intel 8080)的机器字长为 8 位;
  • 32 位 CPU(如 Intel Pentium III)的机器字长为 32 位;
  • 现代主流 CPU(如 Intel Core i7、AMD Ryzen)多为 64 位机器字长。

不同字长的无符号数表示范围如下表:

机器字长(n 位) 最小值 最大值(2ⁿ - 1 可表示的数值总数
8 位 0 255 256
16 位 0 65535 65536
32 位 0 4294967295 4294967296
64 位 0 18446744073709551615 18446744073709551616

 2. 有符号数

在计算机中,有符号数是指需要表示正负的数据(如整数、定点小数等)。由于计算机只能处理二进制,需要通过特定的编码规则将符号(正 / 负)与数值部分结合,形成有符号数的机器表示。常见的编码方式包括原码、反码、补码、移码 其中补码是现代计算机中最常用的形式。

一、有符号数的符号表示

无论采用哪种编码,有符号数的最高位(最左边的位)均被规定为符号位

  • 符号位为 0 时,表示正数;
  • 符号位为 1 时,表示负数。

符号位之外的其他位称为数值位,用于表示数据的绝对值大小。
例如,在 8 位有符号数中:

  • 最高位(第 7 位)为符号位,第 0-6 位为数值位;
  • 32 位有符号数中,第 31 位为符号位,第 0-30 位为数值位。

二、三种编码方式的规则(以 n 位有符号数为例)

1. 原码(True Form)

原码是最直观的编码方式,直接将符号位与数值的二进制绝对值结合。

  • 正数原码:符号位为 0,数值位为该数绝对值的二进制表示;
  • 负数原码:符号位为 1,数值位为该数绝对值的二进制表示。

示例(8 位有符号数)

十进制数 二进制真值 原码表示
+5 +0000101 00000101
-5 -0000101 10000101
+0 +0000000 00000000
-0 -0000000 10000000

 特点

  • 直观易懂,与人类对正负的认知一致;
  • 存在缺陷:+0 和 -0 有两种不同表示(浪费一个编码),且直接进行减法运算时需额外处理符号(如比较大小、确定结果符号),运算电路复杂。
2. 反码(One's Complement)

反码是原码的一种 “变形”,主要用于辅助补码的计算,实际应用较少。

  • 正数反码:与原码相同(符号位为 0,数值位不变);
  • 负数反码:符号位不变(仍为 1),数值位按位取反(0 变 1,1 变 0)。

示例(8 位有符号数)

十进制数 原码 反码
+5 00000101 00000101
-5 10000101 11111010
+0 00000000 00000000
-0 10000000 11111111

特点

  • 解决了原码减法运算的部分问题(可通过 “负数反码” 将减法转为加法),但仍存在 +0 和 -0 两种表示,且运算后可能需要 “循环进位” 修正结果,效率较低。
3. 补码(Two's Complement)

补码是现代计算机中表示有符号数的标准方式,彻底解决了原码和反码的缺陷,能统一处理加法和减法运算。

  • 正数补码:与原码、反码相同(符号位为 0,数值位不变);
  • 负数补码:符号位为 1,数值位为其绝对值的原码 “按位取反后加 1”(即 “反码 + 1”)。

示例(8 位有符号数): 

十进制数 原码 反码 补码
+5 00000101 00000101 00000101
-5 10000101 11111010 11111011
+0 00000000 00000000 00000000
-0 10000000 11111111 00000000 (补码中 + 0 和 - 0 统一为 00000000)

补码的核心优势

  1. 统一 0 的表示:补码中 +0 和 -0 只有一种表示(全 0),节省了一个编码空间(如 8 位补码中,10000000 可表示 -128,扩大了表示范围)。
  2. 减法转加法:对于任意两个数 a 和 ba - b 可等价为 a + (-b) 的补码运算,无需额外设计减法电路,简化了 CPU 硬件。
    例如:5 - 3 = 5 + (-3),用补码计算:
    • 5 的补码:00000101
    • -3 的补码:11111101(计算过程:3 的原码 00000011 → 反码 11111100 → 加 1 得 11111101
    • 相加:00000101 + 11111101 = 100000010(8 位截断后为 00000010,即 2,结果正确)。

三 编码的演变过程

大家可能疑惑,为什么会有这么多码,这也是随着时代的发展,逐步演变进化来的,这一发展路径与早期计算机硬件技术的限制、运算需求的提升密切相关,反映了工程师对 “如何用最简单的硬件实现高效符号数运算” 的持续探索。

一、早期:原码的天然选择(1940-1950 年代)

计算机诞生初期(如 1946 年的 ENIAC),符号数的表示直接采用了原码,原因有二:

  1. 直观性:原码的逻辑与人类对 “正负” 的认知一致(符号位 + 绝对值),早期程序员和硬件设计师更容易理解和实现。
  2. 硬件限制:早期计算机的运算器(ALU)非常简单,主要针对无符号数设计。若要处理有符号数,原码的实现最直接 —— 只需在无符号数的基础上增加一个符号位,运算时单独处理符号即可。

但原码的缺陷很快暴露:减法运算需要复杂的逻辑(判断符号、比较绝对值、单独处理结果符号),导致硬件电路庞大且运算速度慢。例如,ENIAC 处理一次减法的时间是加法的数倍,严重影响效率。

二、过渡:反码的尝试(1950 年代中期)

为解决原码减法的复杂性,工程师提出了反码(也称为 “对 1 的补码”)。其核心思路是:

  • 负数的反码是 “原码符号位不变,数值位取反”,通过这种转换,可将减法运算转化为加法(a - b = a + (-b的反码))。

这在一定程度上简化了硬件设计(无需单独的减法电路),但反码的缺陷依然明显:

  1. 0 的双重表示+0 和 -0)导致编码浪费,且可能引发运算歧义;
  2. 循环进位问题:反码加法可能产生最高位进位,这个进位必须 “循环” 加到结果的最低位才能得到正确值,增加了硬件逻辑和运算延迟。

因此,反码仅在部分早期计算机(如 1950 年代的 UNIVAC I)中短暂使用,未成为主流。

三、成熟:补码的最终确立(1950 年代末至今)

补码(也称为 “对 2 的补码”)的概念并非凭空出现,其数学原理(模运算)早已存在,但直到 1950 年代末才被广泛应用于计算机设计。

关键转折点是 1955 年 IBM 工程师Andrew Donald Booth提出的 “补码乘法算法”,以及 1959 年 IBM 7090 计算机的成功应用 —— 这是第一台大规模采用补码的商用计算机。补码的优势彻底解决了前两种编码的痛点:

  1. 0 的唯一表示:消除了编码浪费,扩大了表示范围;
  2. 减法完全转化为加法:无需循环进位,硬件逻辑极简;
  3. 符号位自然参与运算:结果的符号位自动生成,无需额外处理。

这些优势使得补码在 1960 年代后逐渐成为行业标准,至今所有主流计算机(从微型机到超级计算机)均采用补码表示有符号数。

四、总结:演进的核心驱动力

从原码到反码再到补码的演进,本质是 **“硬件简化” 与 “运算效率” 的平衡过程 **:

  • 原码:最直观,但硬件复杂、效率低;
  • 反码:尝试简化减法,但仍有缺陷;
  • 补码:牺牲了部分直观性,却实现了 “硬件最简单、运算最高效”,最终成为最优解。

这一过程也体现了计算机技术的发展逻辑 —— 不是 “最直观的方案” 获胜,而是 “最适合硬件实现、最高效” 的方案最终被广泛采用。补码的普及,为后续计算机运算能力的飞跃奠定了基础。

在实际计算机运算中,有符号数的确是以补码形式参与运算的,这是由计算机的硬件设计决定的。而负责 “转换” 和 “运算” 的核心部件,是 CPU 内部的运算器(ALU,算术逻辑单元) 以及相关的电路逻辑。下面详细解释这个过程:

五、计算机中 “补码运算” 的实际流程

当你在程序中写下类似 a + b 或 a - b 的运算时(其中 ab 是有符号数),计算机的处理步骤大致如下:

  1. 数据的存储形式:补码
    首先,程序中的有符号数(如 int 类型的 -35 等)在内存中存储时,就已经是补码形式了。

    • 例如,32 位 int 类型的 5 在内存中是 00000000 00000000 00000000 00000101(补码,与原码相同);
    • -3 的补码是 11111111 11111111 11111111 11111101(通过原码取反加 1 得到)。
  2. 运算时的处理:补码直接参与计算
    当 CPU 执行运算时,会从内存中读取这些补码形式的数据,送入运算器(ALU)。

    • 对于加法:直接将两个数的补码相加(符号位也参与运算);
    • 对于减法:将 “减数的补码” 转换为 “其相反数的补码”(即取反加 1),然后与被减数的补码相加(本质是 a - b = a + (-b) 的补码运算)。

    运算完成后,ALU 输出的结果依然是补码形式,再存入寄存器或内存。

  3. 结果的 “还原”:仅在需要人类阅读时
    补码的结果对计算机而言可以直接使用(如继续参与下一次运算),但当需要将结果展示给人类(如打印到屏幕)时,程序会将补码转换为十进制(或其他人类可读形式)。这个转换由软件(如编程语言的运行时库)完成,而非硬件。

六、谁负责 “补码的转换与运算”?

核心角色是硬件电路,具体包括:

  1. CPU 的运算器(ALU)
    ALU 是执行算术运算(加减乘除)和逻辑运算(与或非)的核心部件,其内部电路直接设计为对补码进行运算

    • 加法电路:接收两个补码,输出它们的和(补码形式);
    • 减法电路:本质是 “加法电路 + 取反加 1 电路”—— 先将减数的补码取反加 1(得到 -b 的补码),再送入加法电路与被减数相加。

    这些电路是硬件层面固化的逻辑,不需要 “软件干预”,速度极快(纳秒级)。

  2. 数据通路与寄存器
    寄存器是 CPU 内部的高速存储单元,用于临时存放运算数据。有符号数在寄存器中也以补码形式存储,确保送入 ALU 的数据始终是补码。

  3. 编译器的辅助
    当你用高级语言(如 C、Python)编写代码时,不需要手动处理补码 —— 编译器会自动将源代码中的有符号数(如 -5)转换为补码形式的机器码,存入内存。例如:

    • 写 int a = -3; 时,编译器会生成指令,将 -3 的补码写入内存的 a 地址。

七、为什么我们感知不到补码的存在?

因为补码的转换和运算完全由硬件和编译器在底层完成,对程序员和用户是 “透明” 的:

  • 你输入的是十进制数(如 -3 + 5),编译器负责转为补码;
  • CPU 用补码运算,得到的结果仍是补码;
  • 当需要输出时(如 printf("%d", result)),运行时库会将补码转回十进制,展示给你。

整个过程中,补码就像 “计算机的秘密语言”,默默完成运算,却不需要你直接打交道。

 

 

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐