【CSAPP/计组】#1 数的存储与表示方法、机器中浮点数加减法详解

文章目录

  • 前言
  • 一、定点格式
    • 定点整数
  • 二、浮点数的表示方法
    • 2.1 浮点数存储
    • 2.2 浮点数加减法
      • a. 操作数检查
      • b. 对阶
      • c. 尾数相加与检查溢出
      • d. 结果规格化与溢出处理
      • e.舍入处理
    • Some tips: 为什么进位/双符号判断法有效的通俗解释?
    • Some tips:符号位拓展


前言

计算机中常用的数据表示格式有两种,一是定点格式,二是浮点格式。一般来说,定点格式容许的数值范围有限,要求的处理硬件比较简单。而浮点格式容许的数值范围很大,要求的处理硬件比较复杂。


一、定点格式

所谓定点格式,即约定机器中所有数据的小数点位置是固定不变的。由于约定在固定的位置,小数点就不再使用记号“.”来表示。原理上讲,小数点位置固定在哪一位都可以,但是通常将数据表示成纯小数纯整数

目前计算机中多采用定点纯整数表示,因此将定点数表示的运算简称为整数运算

定点整数

  • 一个正整数,当用原码、反码、补码表示时,符号位都固定为 0,用二进制表示的数位值都相同,即三种表示方法完全一样。
  • 一个负整数,当用原码、反码、补码表示时,符号位都固定为 1,用二进制表示的数位值都不相同。此时由原码表示法变成补码表示法的规则如下:
    (1)原码符号位为 1 不变,整数的每一位二进制数位求反得到反码;
    (2)反码符号位为 1 不变,反码数值位最低位加 1,得到补码。

该种表示方法优点:

  • 很好地使得+0与-0都为唯一格式存储
  • 使得相同的的硬件用同样的方式可以同时处理加减法(减法看做正负数相加)
    eg:
    在这里插入图片描述

具体数学原理不在此赘述。

二、浮点数的表示方法

计算机中,把一个数的有效数字数的范围在计算机的一个存储单元中分别予以表示。这种把数的范围和精度分别表示的方法,相当于数的小数点位置随比例因子的不同而在一定范围内可以自由浮动,所以称为浮点表示法。

规定:任意一个十进制数 N 可以写成 N = 10^E . M
同样,在计算机中一个任意二进制数 N 可以写成 N = 2^e . MM 称为浮点数的尾数,是一个纯小数。e 是比例因子的指数,称为浮点数的指数,是一个整数。

2.1 浮点数存储

IEEE754标准规定的 32 位短浮点数和 64 位长浮点数的标准格式,同时规定移码的偏置值是 2^(n-1)-1

在这里插入图片描述

  • 由于基数 2 是固定常数,对每一个浮点数都一样,所以不必用显示表达(存储)它。
  • 32 位的浮点数中,S 是浮点数的符号位,占 1 位,安排在最高位,S=0 表示正数,S=1表示负数。M 是尾数,放在低位部分,占用 23 位,小数点位置放在尾数域最左(最高)有效位的右边。E 是阶码,占用 8 位,阶符采用隐含方式,即采用移码方法来表示正负指数。采用这种方式时,将浮点数的指数真值 e 变成阶码 E 时,应将指数 e 加上一个固定的偏置常数 127,即 E=e+127这种表示方法的好处是E可表示的数恒大于0(可看做为无符号数),便于比较不同数字之间的阶码大小
  • 64 位的浮点数中符号位 1 位,阶码域 11 位,尾数域 52 位,指数偏移值是 1023。
  • 为了提高数据的表示精度,当尾数的值不为 0 时,尾数域的最高有效位应为 1,这称为浮点数的规格化表示

所以在 IEEE754 标准中,一个规格化的 32 位浮点数 x 的真值表示为
x=(–1)S×(1.M)×2E–127, e=E–127
规格化的 64 位浮点数 x 的真值为 x=(–1)S×(1.M)×2E–1023, e=E–1023

对于单精度,最大的指数为127(0+127),最小的指数为-126(-255+127);

规格化的浮点数的尾数域最左位(最高有效位)总是 1,故这一位无需存储,而认为隐藏在小数点的左边。于是用 23/52 位字段可以存储 24/53 位有效数

对 32 位浮点数 N,IEEE754 定义一些特殊情况(N为真值):

  • 若 E=255 且 M!=0,则 N=NaN符号 NaN (Not a Number)表示无定义数据,采用这个标志的目的是让程序员能够推迟进行测试及判断的时间,以便在方便的时候进行。
  • 若 E=255 且 M=0,则 N=(–1)S。当阶码 E 为全 1 且尾数 M 为全 0 时,表示的真值 N 为无穷大,结合符号位 S 为 0 或 1,也有+∞和–∞之分。
  • 若 0<E<255,则 N=(–1)S×(1.M)×2E–127(规格化数)。偏移值不选27=128(10000000),而选 27–1= 127(01111111)。阶码 E 的范围变为 1~254,指数值 e 则为–126~+127。因此 32 位浮点数表示的绝对值的范围是 10–38~1038。
  • 若 E=0 且 M=0,则 N=(–1)S0。当阶码 E 为全 0 且尾数 M 也为全 0 时,表示的真值N 为零(称为机器 0),结合符号位 S 为 0 或 1,有正零和负零之分。
  • 若 E=0 且 M!=0,则 N=(–1)S×(0.M)×2–126(非规格化数)。对于规格化无法表示的数据,可以用非规格化形式表示。(下图符号表述与本文有些不同,注意区分)在这里插入图片描述

2.2 浮点数加减法

a. 操作数检查

  • 若有一个操作数为NaN则直接返回NaN
  • 若有一个操作数为0则直接返回另一个操作数
  • 若有一个操作数为Infinity:
    • 若另一个操作数也是Infinity且符号相同则返回第一个操作数
    • 若另一个操作数也是Infinity且符号不同则返回NaN
    • 若其他情况则返回Infinity

b. 对阶

两操作数可直接进行加减操作的前提是两者同阶。因此需要对不同阶的操作数进行小数点对齐,由于存储的尾数在右移的过程中损失精度的概率比左移要小(因为尾数的存储时未使用的位数是在有效位右边补0),所以我们采取小阶向大阶对齐
注意这里的阶码e指的是该数字在规格化二进制下的阶码,或者无法规格化时的阶码

For example:
0.65的32位存储 其阶码e实际为Exp-127=126-127=-1
在这里插入图片描述
-0.425的32位存储 其阶码e实际为Exp-127=125-127=-2
在这里插入图片描述
此时我们如果要对两者进行操作,就需要将-0.425二进制存储的尾数右移一位,阶码存储变为与0.65相同。

不必担心无法规格化的数,其阶数e规定为1-127=-126,已经为最小阶数,所以必然由其向另一操作数对齐。


c. 尾数相加与检查溢出

当我们对两个操作数完成上述操作,自然可以对其尾数进行相加。如果没有溢出,那么皆大欢喜。可惜世事不可尽如人意v_v
尤其需要强调的一点是:计算机中加减法实际都是采用加法硬件来进行计算,所以当出现负浮点数时,虽然负浮点数存储的二进制尾数依然是原码,但在计算时需要将其转化为补码来实现用加法的硬件完成操作

对于浮点数而言,当两个正操作数相加超过表示范围,称为上溢出;当两个负操作数相加超过表示范围,称为下溢出;(若溢出后的情况与定义的特殊情况相同,则按照特殊情况处理)

通常来说有两种方式判断溢出,分别是 进位判断法双符号判断法

  • 进位判断法(采用单符号位:在计算数值前面补上符号位)
    • 无溢出:符号位 和 最高位 一起进位或一起不发生进位。
    • 溢出:符号位 或 最高位 其中一个发生进位。
  • 双符号判断法(采用双符号位:在计算数值前面补两个符号位)
    • 无溢出:计算后两符号位相同。
    • 上溢出:计算后两符号位为01。
    • 下溢出:计算后两符号位为10。

这里的计算数值是在尾数之前补上对阶之后的隐藏位,以上述为例

在这里插入图片描述

此时进行0.65+(-0.425)操作,必须强调的是,用于计算的负数尾数需要化为补码

~(11011001100110011001101)+1->00100110011001100110011

进位判断法(单符号位)
  0-1-01001100110011001100110 单符号位-隐藏位-尾数 0.65
+ 1-0-00100110011001100110011 单符号位-隐藏位-尾数 -0.425
->0-0-01110011001100110011001 符号位与计算最高位都产生进位 无溢出
所以两操作数计算结果的隐藏位为0,符号数为0,
阶码为01111110(与操作数保持一致)
尾数为01110011001100110011001

双符号判断法
  00-1-01001100110011001100110 单符号位-隐藏位-尾数 0.65
+ 11-0-00100110011001100110011 单符号位-隐藏位-尾数 -0.425
->00-0-01110011001100110011001 两个符号位都相同 无溢出
同上

但是我们并不将结果直接存储为0-01111110-01110011001100110011001,因为此时隐藏位为0未规格化,而且还可能需要舍入操作
对结果进行规格化 结果为0-01111100-11001100110011001100100 约等于0.225


d. 结果规格化与溢出处理

在尾数相加的过程中,尾数最高位可能产生进位,称为尾数上溢
对阶的过程中,尾数最低有效位可能被舍去,为尾数下溢

  • 尾数上溢 两个同符号尾数相加产生了最高位向上的进位,要将尾数右移,阶码增 1
    来重新对齐。
  • 尾数下溢 在将尾数右移时,尾数的最低有效位从尾数域右端流出,要进行舍入处理(在步骤e中说)。

当出现尾数上溢时,需要向右规格化则尾数右移1位,阶码+1,因此浮点数相加时尾数的溢出也被称为可补救的
若无溢出,则按照最基本的规格化方式,即规格化为1.xxx的形式(不考虑非规格化数)——1依然是隐藏位,xxx为存储的尾数二进制,阶码同步变化。(即所谓的左规,实际就是最普通的规格化过程)

在规格化时,阶码往往也会产生变化

  • 阶码上溢 超过了阶码可能表示的最大值的正指数值,一般将其认为是+∞和–∞。
  • 阶码下溢 超过了阶码可能表示的最小值的负指数值,一般将其认为是 0。

e.舍入处理

IEEE754 标准中,对舍入处理提供了四种可选办法。

  • 朝 0 舍入 即朝数轴原点方向舍入,就是简单的截尾。无论尾数是正数还是负数,截
    尾都使取值的绝对值比原值的绝对值小。这种方法容易导致误差累积。
  • 朝+∞舍入 对正数来说,只要多余位不全为 0 则向最低有效位进 1;对负数来说,则
    是简单的截尾。
  • 朝–∞舍入 处理方法正好与朝+∞舍入情况相反。对正数来说,则是简单截尾;对负
    数来说,只要多余位不全为 0,则向最低有效位进 1
  • 向偶数舍入(就近舍入)(default)

这里着重说一下为什么这是默认的方法,以及具体使用方法:
如果我们总是把两个可表示值中间的数字向上舍入,采用这种方式舍入得到的一组数的平均值将比这些数本身的平均值略高一些。相反,那么舍入后的一组数的平均值将比这些数本身的平均值略低一些。这些方法会在计算这些值的平均数中引入统计偏差。向偶数舍入在大多数现实情况中避免了这种统计偏差

因此假设我们想将十进制数舍入到最接近的百分位。不管用那种舍入方式,我们都将把1.2349999舍入到1.23,而将1.2350001舍入到1.24,因为它们不是在1.23和1.24的正中间。另一方面我们将把两个数1.2350000和1.2450000都舍入到1.24,因为4是偶数。
而在二进制中,每一位的权重都是前一位权重的二分之一,因此当一位为1(设其为第n位)时,实际我们知道n位及之后的尾数和一定大于等于第n-1位权重的一半,如下图例。因此我们说——在尾数右移时,被移去的最高数值位为0,则舍去。被移去的最高数值位为1,则在尾数末尾加1(舍0入1法);这样做可能使尾数又溢出,此时需要再做一次右规。,实际就是向偶数舍入。(如果你理解成简单的四舍五入是绝对错误的)

在这里插入图片描述
还有一种恒置1法,不在此赘述。


Some tips: 为什么进位/双符号判断法有效的通俗解释?

  • 首先我们回忆一下补码转化为十进制的快捷方式:最高位取负值 其余位取正值 相加可得十进制。
    如11001->转化为十进制-16+8+1=-7。所以实际上补码越大,实际值越靠近0(实际值的绝对值越小)
    在这里插入图片描述

  • 对于单符号位(进位)判断法:

    • 正数加正数的情况下,由于符号位都是0,所以符号位不可能向前产生进位,所以溢出也就意味着数值最高位向前进位,最终导致结果符号位是1,计算结果出错。此时符号位没有进位,数值最高位进位。
    • 负数加负数的情况,因为两个符号位均为1 ,所以必定会在符号位产生进位。当补码比较大时候,此时若数值最高位产生进位,实际两者之和绝对值很小,同时将符号位重新置1;只有当补码很小,实际值的绝对值很大时,剩下的数值位的最高位相加之后才有可能不向前进位,这时候符号位变成了0,也就是两个负数相加得到了正数,计算结果错误。
    • 正负数相加情况此时也很容易理解了。所以该种方法判断溢出是符号位或最高位其中一个发生进位。
  • 对于双符号判断法:

    • 正数加正数,符号位相加为00,若数值位最高位产生进位,溢出时符号必然为01
    • 负数加负数,符号位相加为10,若数值位最高位产生进位,则说明操作数的的补码很大,实际值很小,必然不会溢出,产生进位后符号位为11。
    • 正数加负数,符号位相加为11,若数值位最高位产生进位,则说明正数很大,负数很小,结果也不会溢出,产生进位后符号位为00;若不产生进位,符号位依然为11。都不溢出

浮点数加减的基本结构示意图
在这里插入图片描述


Some tips:符号位拓展

  • 对于有符号整数,例如如何将32位数据正确的拷贝到64位机器?我们只需要将它的符号位不断拷贝即可。对于正数,符号位为0,左边补0自然不影响大小。
  • 对于负数,符号位为1,假设原符号位权重为2n,向左拷贝一位后新符号位权重为2n+1,但此时转换十进制时原符号位权重已经取正数,实际各位权重之和对数值本身并无影响
    在这里插入图片描述
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/562019.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【图论 单源最短路】100276. 最短路径中的边

本文时间知识点 单源最短路 图论知识汇总 LeetCode100276. 最短路径中的边 给你一个 n 个节点的无向带权图&#xff0c;节点编号为 0 到 n - 1 。图中总共有 m 条边&#xff0c;用二维数组 edges 表示&#xff0c;其中 edges[i] [ai, bi, wi] 表示节点 ai 和 bi 之间有一条…

Java 初学者必看 最全详细入门指南(一)

--------------------------------------------------------------------- 1.AIGC未来发展前景 未完持续… 1.1 人工智能相关科研重要性 拥有一篇人工智能科研论文及专利软著竞赛是保研考研留学深造以及找工作的关键门票&#xff01;&#xff01;&#xff01; 拥有一篇人工…

C++ 程序的内存分配

C 程序的内存分配 C 程序的内存分配栈堆数据区程序代码区参考 C 程序的内存分配 一个 C 编译的程序占用内存分为以下几个部分&#xff08;从高地址到低地址&#xff09;&#xff1a; 内核空间&#xff1a;由操作系统创建并控制&#xff0c;用户代码不能读写。栈&#xff1a;由…

文件系统和软硬链接

文章目录 文件系统磁盘磁盘逻辑抽象inode 软硬链接软链接硬链接 文件系统 文件分为打开的文件和没有被打开的文件&#xff0c;而只有打开的文件是在内存的&#xff0c;也就是我们之前讲的&#xff0c;然而大部分文件都不是被打开的(当前不需要被访问的)&#xff0c;它们都在磁…

arping命令详解

arping – send ARP REQUEST to a neighbour host. arping 是一个在网络中发送 ARP 请求以查找特定 IP 地址对应的 MAC 地址的命令行工具。它的功能类似于 ping 命令&#xff0c;基于ARP协议报文的交互机制&#xff0c;只能测试同一网段或子网的网络主机的连通性。 ARP 是 Add…

中国人的谦逊与生俱来

中国人的谦逊是与生俱来的&#xff0c;我们从老子的《道德经》就能探知一二&#xff1a; 一、不自夸、不自傲 《道德经》原文&#xff1a;自见者不明&#xff1b;自是者不彰&#xff1b;自伐者无功&#xff1b;自矜者不长。&#xff08;第二十四章&#xff09; 译文&#xff…

就业班 第三阶段(ansible) 2401--4.16 day2 ansible2 剧本+角色

六、Ansible playbook 简介 playbook 是 ansible 用于配置&#xff0c;部署&#xff0c;和管理被控节点的剧本。   通过 playbook 的详细描述&#xff0c;执行其中的一系列 tasks &#xff0c;可以让远端主机达到预期的状态。playbook 就像 Ansible 控制器给被控节点列出的的…

AI助力科研创新与效率双提升:ChatGPT深度科研应用、数据分析及机器学习、AI绘图与高效论文撰写

2022年11月30日&#xff0c;可能将成为一个改变人类历史的日子——美国人工智能开发机构OpenAI推出了聊天机器人ChatGPT3.5&#xff0c;将人工智能的发展推向了一个新的高度。2023年4月&#xff0c;更强版本的ChatGPT4.0上线&#xff0c;文本、语音、图像等多模态交互方式使其在…

Virtualenv:Python项目管理的救星

在Python的世界里&#xff0c;依赖包冲突是开发者的噩梦&#xff0c;但也是成长的催化剂。最近在写Python项目中就碰到了这样的问题&#xff0c;明明代码在自己的电脑上表现都是正常的&#xff0c;在另外一台电脑上却始终有些小问题&#xff0c;两台电脑安装的Python版本都是一…

(1)认识人工智能

第一章 认识人工智能 引言 本人目前大三&#xff0c;双非一本的人工智能专业&#xff0c;代码能力不算太差&#xff0c;做过项目&#xff0c;也打了比赛&#xff0c;获了奖&#xff0c;但是走技术路线总会有否定自己的感觉&#xff0c;可能是感觉自己的才能没有在搞技术方面实…

java-Spring-入门学习-第二天(单例模式和多例模式)

目录 Bean作用域 单例模式(默认可以不写) Spring下的 AutoWired 依赖注入 JaveEE下的 Resource 依赖注入 多例模式 Bean作用域 ​在Spring框架中&#xff0c;Bean是按照作用域来创建的&#xff0c;常见的作用域有两种&#xff1a;Singleton 和 Prototype。Singleton (单例…

数据结构----顺序表

在学习顺序表之前&#xff0c;我们先来了解一下数据结构。 数据是什么呢&#xff1f; 我们在生活中常见的名字&#xff0c;数字&#xff0c;性别等都属于数据。 结构又是什么呢&#xff1f; 在计算机中&#xff0c;结构就是用来保存数据的方式。 总的来说&#xff0c;数据…

anaconda配置的环境对应的地址查看,环境安装位置

打开conda指令窗口 这个和上面的都一样&#xff0c;哪个都行 点开后&#xff0c;输入 conda env list 这里显示的就是自己的每个环境对应的地址了

OpenCV杂记(1):绘制OSD(cv::getTextSize, cv::putText)

1. 简述 我们使用OpenCV时&#xff0c;有时会在图像的某个位置绘制OSD信息&#xff0c;如绘制一些字符串作为指示信息。 本文将简要介绍在图像&#xff08;cv::Mat&#xff09;上绘制固定的字符串信息。 2. 使用的API &#xff08;1&#xff09;cv::getTextSize() CV_EXPORT…

C++模板template(二十一)

在C的模板体现了一种泛型编程的思想&#xff0c;当我们不确定要传入的参数是何种数据类型时我们可以写一个模板类型来代替&#xff0c;当传入参数时才将类型告诉它。模板也是属于一种静态多态&#xff0c;&#xff0c;模板的不同类型发生在编译时。泛型编程&#xff1a;不是针对…

react中useState的值没有改变,而是旧的数值

问题背景 想实现点击按钮就改变数据的效果&#xff0c;但是在控制台的打印结果&#xff0c;总是上一次的修改情况&#xff0c;并不是最新的修改后的数据 代码&#xff1a; import { useState, useRef } from "react";// 实现sonA的数据传递给sonB const SonA () …

排序之插入排序:从斗地主到插入排序

目录 1.斗地主如何摸牌 2.从摸牌想到插入排序 3.完成插入排序 4.结束语 1.斗地主如何摸牌 不知道各位是否玩过几乎人人都玩过的斗地主游戏呢&#xff1f;相必各位或多或少都玩过一点&#xff0c;再没玩过也看别人打过。今天博主就将从这个游戏为大家讲解我们的插入排序。 在…

Zabbix监控Oracle归档日志空间

1、oracle查看归档日志空间的sql语句 select sum(PERCENT_SPACE_USED) from v$recovery_area_usage; 2、交互式查看oracle归档日志空间的命令&#xff0c;可以手动执行一下&#xff0c;注意要用oracle用户 sqlplus -S "/ as sysdba" << EOF select sum(PER…

攻防世界---misc---[中等] QR1

1.下载附件&#xff0c;是一张空白图片&#xff0c;打开看看&#xff0c;仔细看会发现有黑色小点点 2.图片太大了&#xff0c;我们缩小图片的宽高比例 3.将修改后的图片&#xff0c;用Stegsolve打开&#xff0c;切换图层&#xff0c;得到二维码 4.用QR进行二维码扫描 5.得到fla…

Spring之CGLIB和JDK动态代理底层实现

目录 CGLIB 使用示例-支持创建代理对象&#xff0c;执行代理逻辑 使用示例-多个方法&#xff0c;走不同的代理逻辑 JDK动态代理 使用示例-支持创建代理对象&#xff0c;执行代理逻辑 ProxyFactory 如何自动在CGLIB和JDK动态代理转换 使用示例-使用CGLIB代理方式 使用示…