计算机如何存储浮点数

news2024/11/13 9:01:16

浮点数组成

在计算机中浮点数通常由三部分组成:符号位、指数位、尾数位。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)。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

保健品商城小程序模板源码

保健品商城小程序模板源码 简洁通用的保健品&#xff0c;健康生活&#xff0c;零售商品&#xff0c;电子商务微信小程序前端模板下载。包含&#xff1a;主页、购物车、客服、个人中心、我的订单、商品详情、我的钱包、设置等等。 保健品商城小程序模板源码

【系统架构设计师】八、系统工程基础知识(系统工程|系统性能)

目录 一、系统工程 1.1 系统工程的方法 1.1.1 霍尔的三维结构 1.1.2 切克兰德方法 1.1.3 并行工程方法 1.1.4 综合集成法 1.1.5.WSR 系统方法。 二、系统工程生命周期 2.1 系统工程生命周期7阶段 2.2 生命周期方法 三、基于模型的系统工程(MBSE) 四、系统性能 4.1…

介绍一款Java开发的商业开源MES系统

介绍一款Java开发的开源MES系统&#xff0c;万界星空科技开源的MES系统。该系统基于Java开发&#xff0c;具有广泛的适用性和高度的可定制性&#xff0c;能够满足不同行业、不同规模企业的智能制造需求。 一、系统概述 万界星空科技开源的MES系统是一款面向制造企业车间执行层…

高薪程序员必修课-JVM创建对象时如何解决多线程内存抢占问题

前言 在JVM中&#xff0c;堆的内存分配过程涉及到线程安全性的保障&#xff0c;具体来说涉及到对象的内存分配时&#xff0c;并不是简单的抢占式分配&#xff0c;而是通过一些机制来保证线程安全和高效的内存管理。下面解释一下JVM是如何设计来保证线程安全的&#xff1a; 内存…

输入Rviz打不开,显示could not contact Ros master at[..],retrying

直接输入rviz会报错无法打开 解决方法&#xff1a; 先输入roscore&#xff0c;再用ctrlaltt打开新终端&#xff0c;在新终端输入rviz/rosrun rviz rviz即可

密码技术中分组模式解析

目录 1. 概述 2. ECB模式 2.1 概述 2.2 ECB模式的加密 2.3 ECB模式的解密 2.4 优点 2.5 缺点 3. CBC模式【推荐】 3.1 概述 3.2 CBC模式的加密 3.3 CBC模式的解密 3.4 优点 3.5 缺点 4. CFB模式 4.1 概述 4.2 CFB模式的加密 4.3 CFB模式的解密 4.4 优点 4.…

一二三应用开发平台应用开发示例(6)——代码生成、权限配置、运行效果查看

生成代码 完成配置工作&#xff0c;接下来就是见证奇迹的时刻~ 返回到实体列表&#xff0c;选中“文件夹”记录&#xff0c;点击“生成代码”按钮&#xff0c;提示成功后&#xff0c;在项目的output目录下输出了平台基于配置模板产生的各层代码&#xff0c;在原有后端的基础上…

【国产开源可视化引擎Meta2d.js】网格

画布背景网格 在线体验&#xff1a; 乐吾乐2D可视化 示例&#xff1a; // 设置默认缺省网格属性 meta2d.store.options.grid true; // 开启 meta2d.store.options.gridColor eeeeee; // 网格线条颜色 meta2d.store.options.gridSize 10; // 格子大小// 设置单个图纸的网格…

java ReadWriteLock接口

在 Java 中&#xff0c;ReadWriteLock 接口的实现类ReentrantReadWriteLock 类提供了一种允许多个线程同时读取某一资源但只允许一个线程写的锁定机制。这种机制可以提高并发性能&#xff0c;特别是在读操作远多于写操作的场景下。 特性&#xff1a; 可重入&#xff1b;不存…

管理《欧盟数字服务法》交易者要求

《数字服务法》合规性 根据《数字服务法》(DSA) 的要求&#xff0c;对于在欧盟地区 (EU) 通过 App Store 分发 App 的所有交易商&#xff0c;Apple 需要验证并显示其联系信息。请指明你是否将以交易商或非交易商的身份在欧盟地区分发任何内容。进一步了解你是否应为交易商。 …

图解 RocketMQ 架构

写在前面 Kafka、RocketMQ都是很出名的中间件&#xff0c;上次我们讲解了Kafka&#xff0c;这次我们来讲讲RocketMQ的原理。 基本架构图 解析 RocketMQ 总共可以分成四个模块 NameServer&#xff1a;提供服务发现和路由功能&#xff0c;管理各种元数据信息。Broker&#xf…

Golang | Leetcode Golang题解之第222题完全二叉树的节点个数

题目&#xff1a; 题解&#xff1a; func countNodes(root *TreeNode) int {if root nil {return 0}level : 0for node : root; node.Left ! nil; node node.Left {level}return sort.Search(1<<(level1), func(k int) bool {if k < 1<<level {return false}…

tomcat原理、结构、设计模式

1 what 一种web服务器&#xff0c;运行java servlet、jsp技术&#xff0c;能为java web提供运行环境并通过http协议处理客户端请求。即tomcat http服务器 servlet容器。同类产品有jetty Web应用&#xff1a;Web应用是指通过Web浏览器访问的应用程序&#xff0c;它使用Web技术…

ctfshow-web入门-文件上传(web151-web160)

目录 1、web151 2、web152 3、web153 4、web154 5、web155 6、web156 7、web157 8、web158 9、web159 10、web160 1、web151 试了下前端只能传 png 后缀的 将一句话木马改成 png 后缀&#xff0c;上传后用 burpsuite 抓包 绕过前端检测后&#xff0c;改回 php 后缀&am…

Python28-9 XGBoost算法

XGBoost&#xff08;eXtreme Gradient Boosting&#xff0c;其正确拼写应该是 "Extreme Gradient Boosting"&#xff0c;而XGBoost 的作者在命名时故意使用了不规范的拼写&#xff0c;将“eXtreme”中的“X”大写&#xff0c;以突出其极限性能和效率&#xff09;是一…

【测试】系统压力测试报告模板(Word原件)

系统压力测试&#xff0c;简而言之&#xff0c;是在模拟高负载、高并发的环境下&#xff0c;对系统进行全面测试的过程。它旨在评估系统在面对极端使用条件时的性能表现&#xff0c;包括处理能力、响应时间、资源消耗及稳定性等关键指标。通过压力测试&#xff0c;开发团队能够…

【OJ】运行时错误(Runtime Error)导致递归爆栈问题

在进行OJ赛时&#xff0c; 题目&#xff1a;给你一个整数n&#xff0c;问最多能将其分解为多少质数的和。在第一行输出最多的质数数量k,下一行输出k个整数&#xff0c;为这些质数。 出现运行时错误 代码如下&#xff1a; def main():# code heren int(eval(input()))list …

力扣-双指针1

何为双指针 双指针指向同一数组&#xff0c;然后配合着进行搜索等活动。 滑动窗口的时候很好使用。 167.两数之和Ⅱ-输入有序数组 167. 两数之和 II - 输入有序数组 题目 给你一个下标从 1 开始的整数数组 numbers &#xff0c;该数组已按 非递减顺序排列 &#xff0c;请你从…

2024年 春秋杯 网络安全联赛夏季赛 Web方向 题解WirteUp 部分

brother 题目描述&#xff1a;web哥&#xff0c;打点容易提权难。 打点就是最简单的SSTI。 执行下find / -user root -perm -4000 -print 2>/dev/null找一下具备suid权限的命令 /usr/lib/dbus-1.0/dbus-daemon-launch-helper /usr/bin/chsh /usr/bin/gpasswd /usr/bin/n…

WPF UI InkCanvas 导师演示画板 演示 笔记 画笔 识别

<Grid><InkCanvas Name"inkCanvas"/><Button Content"识别" Click"Button_Click" VerticalAlignment"Bottom"/></Grid> 引用内库 Ink ink new Ink(); private void Button_Click(object sender, RoutedEvent…