计算机如何存储浮点数

浮点数组成

在计算机中浮点数通常由三部分组成:符号位、指数位、尾数位。IEEE-754中32位浮点数如下:
32bit浮点数组成
上图32bit浮点数包含1bit的符号位,8比特的指数位和23bit的尾数位。对于一个常规浮点数,我们来看看它是如何存储和计算的。这里以浮点数25.125为例。这个浮点数分为整数(25(d))和小数部分(0.125(d)),(下面25(d)中d表示十进制,后续b表示二进制)
于是:
25 ( d ) = 11001 ( b ) 0.125 ( d ) = 0.001 ( b ) 25.125 ( d ) = 11001.001 ( b ) = 1.1001001 E 4 ( b ) \begin{align*} 25(d)&=11001(b)\\ 0.125(d)&=0.001(b)\\ 25.125(d)&=11001.001(b)=1.1001001E^{4}(b) \end{align*} 25(d)0.125(d)25.125(d)=11001(b)=0.001(b)=11001.001(b)=1.1001001E4(b)
明显这个数是一个正数,所以我们可以得知符号位S=0。指数位的计算和我们想象的稍微有点区别,这里我们的2禁止指数位是4。在十几种考虑的指数位可能是负数,为了避免负数情况,我们可以将指数表达范围移动一个偏置到正数区域。因为我们的指数位位8bit,有符号整数最高能表示 2 7 − 1 = 127 2^7-1=127 271=127,所以对指数位偏移一个127即可得到正数。所以我们的指数位部分为: 4 ( d ) + 127 ( d ) = 131 ( d ) = 10000011 ( b ) 4(d)+127(d)=131(d)=10000011(b) 4(d)+127(d)=131(d)=10000011(b)。接下来是尾数,因为 25.125 ( d ) = 11001.001 ( b ) 可以为 1.1001001 E 4 ( b ) 也可以为 . 11001001 E 5 ( b ) 25.125(d)=11001.001(b)可以为1.1001001E^{4}(b)也可以为.11001001E^{5}(b) 25.125(d)=11001.001(b)可以为1.1001001E4(b)也可以为.11001001E5(b)这样我们就得到了不同的表示方法。为了确保总是用相同的方法表示浮点数,IEEE-754中要求了表示尾数的部分总是为1.xxx。正因如此,我们这里的指数部分才是4而不是5。也正是因为如此,所以我们只需要保存.xxx即可,因为小数点前一定是1,这样能节省一个bit。尾数部分为1001001,这样我们的浮点数在内存中表示为:01000001110010010000000000000000。这个值如果是32有符号的定点数int32他应该表示的为:1103691776。
0 10000011 10010010000000000000000

代码验证

#include <cstdint>
#include <iomanip>
#include <iostream>
#include <limits>

using namespace std;
// 定义一个联合体用于访问浮点数的内存表示
union FloatBits {
    float f;
    uint32_t bits;
};

// 打印浮点数的二进制表示
void printFloatBits(float value) {
    FloatBits fb;
    fb.f = value;

    std::cout << "Float value: " << std::fixed << std::setprecision(6) << value
              << std::endl;
    std::cout << "Binary representation: ";

    // 从最高位开始逐位打印
    for (int i = 31; i >= 0; --i) {
        // 通过位掩码检查每一位的值
        uint32_t mask = 1 << i;
        std::cout << ((fb.bits & mask) ? '1' : '0');

        // 在输出中添加空格分组
        if (i % 8 == 0)
            std::cout << ' ';
    }

    std::cout << std::endl;
}

int main() {
    float number = 25.125f;
    int a = 1103691776;
    float *b = reinterpret_cast<float *>(&a);
    int zp = 0;            // 00000000000000000000000000000000
    int zn = -2147483648;  // 10000000000000000000000000000000
    int infn = -8388608;   // 11111111100000000000000000000000
    int infp = 2139095040; // 01111111100000000000000000000000
    int nan = 2139095041;  // 01111111100000000000000000000001
    float inf_float = -std::numeric_limits<float>::infinity();
    std::cout << "-inf float for int  " << *reinterpret_cast<int *>(&inf_float)
              << " -inf float = " << inf_float << "\n";
    float *zero_pos = reinterpret_cast<float *>(&zp);
    float *zero_neg = reinterpret_cast<float *>(&zn);

    float *infn_f = reinterpret_cast<float *>(&infn);
    float *infp_f = reinterpret_cast<float *>(&infp);
    float *nan_f = reinterpret_cast<float *>(&nan);

    printFloatBits(number);
    std::cout << "a = " << a << " *b = " << *b << " number = " << number
              << " +0 => " << *zero_pos << " -0 =>" << *zero_neg << " +inf => "
              << *infp_f << " -inf => " << *infn_f << " nan => " << *nan_f
              << "\n";

    return 0;
}

使用GDB验证存储变量:
在这里插入图片描述

x/4tb:

  • 4 :表示4个后面的元素
  • t:表示打印为二进制
  • b:打印单位为byte(8bit)。

你可能会感到疑惑为什么这个值看起来和我们的结果不太一样,这是因为我们的机器使用小端存储法。show endian可以打印当前运行机器上是大端存储还是小端存储法。实际的二进制按照高位字节存储在低位的方式存储。所以这个值作为二进制,我们应该反向理解为:0100000 111001001 00000000 00000000。同理你可以试一试打印变量a,你就会发现两着结果完全相同。尽管二进制上完全相同,但是因为用了不同的类型符修饰运算的时候依然能知道这个数是表示浮点数的25.125还是无符号整数的1103691776。

浮点数的特殊值

  1. E不全为0或不全为1。这时,浮点数就采用偏置表示,即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
  2. E全为0。这时,浮点数的指数E等于1-127(或者1-1023(64bit)),有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于0的很小的数字。
  3. E全为1。这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);如果有效数字M不全为0,表示这个数不是一个数(NaN)(111111111000000000000000000000000(b))

如何计算负数的二进制

  1. 找到对应的正数(8388608),计算二进制(00000000100000000000000000000000)。
  2. 反转所有位,得到二进制的反码(11111111011111111111111111111111)。
  3. 反码+1得到二进制的补码(111111111000000000000000000000000)。

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

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

相关文章

FPGA的理解,个人的见解,不一定对

类似于面包板上搭建电路&#xff0c;但是使用的是逻辑单元模块&#xff1b;如加法器&#xff0c;减法器&#xff0c;寄存器等 没有模拟电路的电容&#xff0c;电阻&#xff1b;但是逻辑单元的底层实现&#xff0c;使用MOS管等电路实现电路的开关&#xff1b;从而表示0&#xf…

1002-15SF 同轴连接器

型号简介 1002-15SF是Southwest Microwave的29.2 mm (V) DC 至 67 GHz 连接器。该连接器用于连接电缆和设备的组件&#xff0c;它可以提供电气连接和机械支撑。广泛应用于通信、电子、航空航天、军事等领域。 型号特点 电缆的中心导体插入连接器后部的母插座内置应力释放装置可…

SpringMVC系列十三: SpringMVC执行流程 - 源码分析

源码分析 执行流程图实验设计前端控制器分发请求处理器映射器处理器适配器调用目标方法调用视图解析器渲染视图作业布置 执行流程图 实验设计 1.新建com.zzw.web.debug.HelloHandler Controller public class HelloHandler {//编写方法, 响应请求, 返回ModelAndViewRequestMa…

GD 32点亮流水灯

1. 0 软件架构设置 2.0 API 接口以及数据结构定义 3.0 程序代码实现 程序项目的结构如下所示&#xff1a; 第一步&#xff1a;编写LED驱动&#xff0c;初始化驱动程序 创建结构体&#xff1a;第一个参数表示GPIO使能&#xff0c;第二个参数表示单片机的IO口&#xff0c;第三个…

html+css+js贪吃蛇游戏

贪吃蛇游戏&#x1f579;四个按钮控制方向&#x1f3ae; 源代码在图片后面 点赞❤️关注&#x1f64f;收藏⭐️ 互粉必回&#x1f64f;&#x1f64f;&#x1f60d;&#x1f60d;&#x1f60d; 源代码&#x1f4df; <!DOCTYPE html> <html lang"en"&…

idea删除分支并同步到gitLab以及gitLab上的分支删除

目录 idea删除分支并同步到gitLab 方法一&#xff08;推荐&#xff09; 方法二&#xff08;命令行&#xff09; gitLab上的分支删除 前言-与正文无关 ​ 生活远不止眼前的苦劳与奔波&#xff0c;它还充满了无数值得我们去体验和珍惜的美好事物。在这个快节奏的世界中&…

Tell Me Why:利用大型语言模型进行可解释的公共健康事实核查

Tell Me Why: Explainable Public Health Fact-Checking with Large Language Models 论文地址:https://arxiv.org/abs/2405.09454https://arxiv.org/abs/2405.09454 1.概述 最近的COVID-19大流行突显了公共健康领域事实核查的关键需求。在信息通过社交媒体平台迅速传播的时…

GPU 张量核心(Tensor Core)技术解读

一文理解 GPU 张量核心&#xff08;Tensor Core&#xff09; 引言 最新一代Nvidia GPU搭载Tensor Core技术&#xff0c;本指南深度解读其卓越性能&#xff0c;为您带来极致体验。 Nvidia最新GPU微架构中的核心技术——Tensor Core&#xff0c;自Volta起每代均获突破&#xf…

【漏洞复现】Emlog Pro 2.3.4——任意用户登入、会话持久化(CVE-2024-5044)

声明&#xff1a;本文档或演示材料仅供教育和教学目的使用&#xff0c;任何个人或组织使用本文档中的信息进行非法活动&#xff0c;均与本文档的作者或发布者无关。 文章目录 漏洞描述漏洞复现 漏洞描述 漏洞编号&#xff1a;CVE-2024-5044 漏洞成因&#xff1a; 在Emlog Pro …

加密与安全_ 解读非对称密钥解决密钥配送问题的四个方案

文章目录 Pre对称密钥的死穴 - 经典的密钥配送问题什么是非对称密钥非对称密钥解决密钥配送问题的四个方案共享密钥密钥分配中心&#xff08;KDC&#xff09;Diffie-Hellman 密钥交换体系公钥密码体系RSA算法 Pre 对称密钥的死穴 - 经典的密钥配送问题 假设 Alice 和 Bob 两个人…

阻塞赋值与非阻塞赋值

文章目录 一、何为“阻塞”&#xff1f;二、阻塞赋值与非阻塞赋值1. 阻塞式赋值“”2.非阻塞式赋值“<” 三、什么时候用阻塞赋值或非阻塞赋值&#xff1f; 一、何为“阻塞”&#xff1f; 所谓“阻塞”&#xff0c;可以理解为阻止顺序语句块中其他语句的执行。例如&#xf…

ASP.NET Core----基础学习04----Model模型的创建 服务的注入

文章目录 1. 创建Models文件夹&#xff0c;3个文件的内容如下&#xff1a;&#xff08;1&#xff09;模型的创建&#xff08;2&#xff09;服务的注入 1. 创建Models文件夹&#xff0c;3个文件的内容如下&#xff1a; &#xff08;1&#xff09;模型的创建 模型的基础类Student…

阿里云 Ubuntu 开启允许 ssh 密码方式登录

以前用的 centos&#xff0c;重置系统为 ubuntu 后在ssh 远程连接时遇到了点问题&#xff1a; 在阿里云控制台重置实例密码后无法使用密码进行 SSH 连接登录 原因&#xff1a;阿里云 Ubuntu 默认禁用密码登录方式 解决办法&#xff1a; 先使用其他用户登录到服务器 这里进来…

Java中多线程经典案例

案例一单例模式 只有一个对象,只实例化一个对象 饿汉模式 在程序开始初期的实例化一个对象 static成员初始化时机是在类加载的时候,static修饰的instance只有唯一一个,初始化也是只执行一次,static修饰的是类属性,就是在类对象上的,每个类对象在JVM中只有一份,里面的静态成员…

下载安装JavaFX及解决报错:缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序|Eclipse

目录 1.下载并解压 2.Eclipse配置 3.报错问题 解决方法1&#xff1a;将javaSE更改到9以下 解决方法2&#xff1a; 使用module-info.java配置解决 1.下载并解压 JavaFX下载地址&#xff1a;JavaFX - Gluon 选择合适自己电脑配置的sdk版本下载 打不开网页的参考这个博客&…

Demeditec Diagnostics — AMH ELISA试剂盒

抗缪勒氏管激素(AMH)&#xff0c;是一种二聚体分子量为140 KDa的糖蛋白&#xff0c;是转化生长因子-β (TGF-β)细胞因子家族&#xff0c;在生殖结构正常分化中起重要作用。AMH已被被确定为卵巢储备的可靠标志&#xff0c;有助于预测早期卵泡丢失和更年期开始。AMH水平也反映了…

【Python画图-seaborn驯化】一文学会seaborn画因子变量图catplot函数使用技巧

【Python画图-seaborn驯化】一文学会seaborn画因子变量图catplot函数使用技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获取相关内…

【运营版】公众号接口回调出租用出售微信公众号多域名无限回调授权系统+接口文档

此系统用于微信无限回调单个用户授权&#xff0c;如你的无限回调借给他人使用&#xff0c;怕他人泛滥您的无限回调&#xff0c;导致您的域名或者公众号经常封&#xff0c;那么你们可以用此系统给他们设置一个授权使用权限&#xff0c;如给指定域名添加授权登录&#xff0c;那么…

【Linux】目录的相关命令——cd,pwd,mkdir,rmdir

1.相对路径与绝对路径 在开始目录的切换之前&#xff0c;你必须要先了解一下所谓的路径&#xff08;PATH)&#xff0c;有趣的是&#xff1a;什么是相对路 与绝对路径&#xff1f; 绝对路径&#xff1a;路径的写法“一定由根目录/写起”&#xff0c;例如&#xff1a;/usr/shar…

间接平差——以水准网平差为例 (matlab详细过程版)

目录 一、原理概述二、案例分析三、代码实现四、结果展示本文由CSDN点云侠原创,间接平差——以水准网平差为例 (matlab详细过程版),爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT生成的文章。 一、原理概述 间接平差的函数模型和随机模型…