06. 小数和小数精度丢失

news2024/11/26 0:46:26

1. 将0.1累加100次也得不到10

#include <stdio.h>

int main()
{
    float sum = 0;    
	// 0.1相加100次
    for (int i = 1;  i <= 100; i++) {
		sum += 0.1;    
	}   
	// 显示结果
    printf("%f\n", sum); 
}

打印结果:

10.000002

以上代码没有错,计算机也没有故障,为什么会出现这样的情况?

2. 用二进制表示小数

二进制数:1011.0011 如何换算为十进制?

如下:

1*23 + 0*22 + 1*21 + 1*20 + 0*2-1 + 0*2-2 + 1*2-3 + 1*2-4
= 1*8 + 0*4 + 1*2 + 1*1 + 1*0.5 + 0*0.25 + 1*0.125 + 1*0.0625
= 11.1875

3. 计算机出错的原因

小数点后4位能够用二进制数表示的数值二进制数是连续的,十进制数是非连贯的

二进制数十进制数
0.00000
0.00010.0625
0.00100.125
0.00110.1875
0.01000.25
0.01010.3125
0.01100.375
0.01110.4375

上面发现通过二进制数无法表示0.1,0.0625直接就跳到了0.125,根本就没有0.1这个数,实际上十进制数0.1转换成二进制后,会变成0.00011001100…(1100循环)这样的循环小数。

这和无法用十进制数来表示1/3是一样的道理。1/3就是0.3333…,同样是循环小数。

计算机就会根据变量数据类型所对应的长度将数值从中间截断或者四舍五入,就像0.3333… 从中间截断会变成0.333333,它的三倍是无法得出1的,结果是0.999999。 所以0.1的100倍的结果是10.000002。

4. 什么是浮点数

实际上像1011.0011这样带小数点的表现形式在计算机中并非上述的表现形式,那么在计算机内部机是以什么样的表现形式来处理小数的呢?

浮点数分为单精度浮点数和双精度浮点数。双精度浮点数类型用64位、单精度浮点数类型用32位来表示。分别是double和float。

那么浮点数究竟是什么样子的?浮点数是通过尾数和指数来表示的,也就是科学记数法

± m * 2n

  • ±:符号
  • m:尾数
  • 2:基数
  • n:指数

那么具体是怎么存储浮点数据的,这里的指数位和尾数位又是怎么表现的。

我们先看看10进制的数用尾数和指数的表现形式。比如:

  • 314.15 = 314.15 * 100
  • 314.15 = 31.415 * 101
  • 314.15 = 3.1415 * 102
  • 314.15 = 0.31415 * 103

可以看出通过尾数和指数有多种表现形式。

再来看看314.15的二进制100111010.0010011001100110011(无限循环)数用尾数和指数的表现形式

  • 100111010.0010011001100110011 * 20
  • 10011101.00010011001100110011 * 21
  • 1001110.100010011001100110011 * 22
  • 100111.0100010011001100110011 * 23
  • 10011.10100010011001100110011 * 24
  • 1001.110100010011001100110011 * 25
  • 100.1110100010011001100110011 * 26
  • 10.01110100010011001100110011 * 27
  • 1.001110100010011001100110011 * 28
  • 0.1001110100010011001100110011 * 29

通过尾数和指数有多种表现形式,实际上浮点数尾数部分用的是“将小数点前面的值固定为1的表达式”,并且只保留小数点后面的部分。如上就是:314.15的尾数部分就是 1.001110100010011001100110011 * 28 中的 001110100010011001100110011(去掉小数点前面的1),保留23位就是00111010001001100110011,

再来看指数部分,指数部分中使用的EXCESS系统,使用这种方法主要是为了表示负数时不使用符号位。EXCESS系统表现是指,通过将指数部分表示范围的中间值设为0,使得负数不需要用符号来表示。也就是说,当指数部分是8位单精度浮点数时,最大值11111111 = 255的1/2,即01111111 = 127(小数部分舍弃)表示的是0,指数部分是11位双精度浮点数时,11111111111= 2047的1/2,即01111111111 = 1023(小数部分舍弃)表示的是0。

二进制十进制EXCESS表现形式
000000000-127(0 - 127)
000000011-126(1 - 127)
01111110126-1(126 - 127)
011111111270(127 - 127)
11111111255128(255 - 127)
  • 指数位的存储是在原有数值上+127。
  • 指数位在使用的时候再在存储的值上-127。

上述 1.001110100010011001100110011 * 28 的指数部分的值是8,转为二进制就是1000,加上127就等于135,转为二进制数就是10000111。即314.15的指数部分是10000111

所以单精度浮点数314.15在计算机的存储是
0 10000111 00111010001001100110011

  • 符号位:0
  • 指数位:10000111
  • 尾数位:00111010001001100110011

再来逆向算一遍:

  • 指数位:10000111 转为 10进制就是 135,减去127就等于 8。
  • 尾数位:00111010001001100110011前面加1.就是 1.00111010001001100110011 转为十进制就是 1.227148413658142。
  • 结果就是 1.227148413658142 * 28 = 1.227148413658142 * 256 ≈ 314.15

5. 总结

浮点数是计算机内部用尾数和指数来表示的,采用科学记数法的形式,即 ±m * 2^n,其中符号位、指数位和尾数位占据不同的位数,分别存储不同的数据。浮点数在表示小数时会产生精度误差,因为某些十进制数在二进制下是无限循环小数,而计算机二进制又有精度限制,无法精确存储和表示这些无限循环小数,所以在进行浮点数运算时可能会出现误差。如果需要高精度运算,需要使用专门的高精度库。

关注微信公众号:“小虎哥的技术博客”,让我们一起成为更优秀的程序员❤️!

文章和代码仓库:

gitee(推荐):https://gitee.com/cunzaizhe/xiaohuge-blog

github:https://github.com/tigerleeli/xiaohuge-blog

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

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

相关文章

【owt-server】AudioSendAdapter分析

owt-server/source/core/rtc_adapter/AudioSendAdapter.cc使用其他线程运行rtprtcpmodule taskrunner分配线程:因此,对rtprtcp的使用都是加了mutex的:首先为音频发送者生成一个随机的ssrc并注册 // SSRCs of this type.std::vector<uint32_t> ssrcs_;发送还要向rtprtc…

【Unity3D赛车游戏优化篇】【九】Unity中如何让汽车丝滑漂移?

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;Uni…

P3074 [USACO13FEB] Milk Scheduling S(拓扑排序)

思路&#xff1a; 核心&#xff1a;拓扑排序 ans[x]max(ans[x],ans[t]f[x]); 注意比当前大才更新&#xff01;&#xff01;&#xff01; 接下来几乎就是拓扑排序模板啦~ ACcode: #include<bits/stdc.h> using namespace std; #define int long long const int N5e41…

在windows 安装JDK17 指南

一、下载jdk 去oracle官网下载jdk压缩包&#xff0c; 下载地址&#xff1a;https://www.oracle.com/java/technologies/downloads/#java17 二、解压jdk 将下载好的jdk压缩包&#xff0c;解压到要安装jdk的路径&#xff08;不要有中文&#xff09;&#xff0c; 三、配置环…

2023年7月婴幼儿辅食市场数据分析(京东商品数据)

随着人们对婴幼儿饮食健康的关注不断增加&#xff0c;市场对高品质、安全、营养丰富的辅食需求也日益旺盛。婴幼儿辅食市场增长放缓&#xff0c;但整体仍保持上升态势。鲸参谋数据显示&#xff0c;今年7月份&#xff0c;京东平台婴幼儿辅食市场的销量为1000万&#xff0c;同比增…

高级IO 1

1.IO 等 数据拷贝 等好了 -> IO事件就绪 &#xff08;“等”是做了条件检测&#xff09; 2. IO的五种模型 1.阻塞IO 2.非阻塞IO 如果内核还未将数据准备好 , 系统调用仍然会直接返回 , 并且返回 EWOULDBLOCK 错误码 非阻塞 IO 往往需要程序员循环的方式反复尝试读写文…

Java“牵手”京东商品价格数据,京东商品历史价格数据接口,京东API接口申请指南

京东平台商品历史价格接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片&#xff0c;历史价格&#xff0c;现在的价格等详细信息 。 获取商品价格接口API是一种用于获…

配置markdown图片粘贴地址

背景 由于最近需要写较多文档&#xff0c;涉及到大量的图片存储&#xff0c;但又不想买图床&#xff0c;所以选择最简单的图片存储方式&#xff1a;将图片存储在文档所在目录下的另一个文件夹中。那么要实现这个功能就需要借助VScode的插件了&#xff0c;插件名&#xff1a;Pa…

嵌入式学习笔记(12)汇编写启动代码之设置栈和调用C语言

C语言运行时需求和栈的意义 “C语言运行时&#xff08;runtime&#xff09;”需要一定的条件&#xff0c;这些条件由汇编来提供。C语言运行时主要是需要栈。 C语言和栈的关系&#xff1a;C语言中的局部变量都是用栈来实现的。如果我们汇编部分没有给C部分预先设置合理合法的栈…

windows从0搭建python3开发环境与开发工具

文章目录 一、python3下载安装1、下载2、安装3、测试 二、安装VS Code1、安装2、安装python插件3、测试 三、pip命令的使用1、基本命令2、修改pip下载源 一、python3下载安装 1、下载 打开 WEB 浏览器访问 https://www.python.org/downloads/windows/ &#xff0c;一般就下载…

机器视觉工程,如何快速摸清即将面试公司的基本情况

1.公司背景调查 企业查&#xff0c;天眼查&#xff0c;对一家公司的股东信息&#xff0c;知识产权&#xff0c;经营范围&#xff0c;是否有诉讼&#xff0c;经营范围等等信息&#xff0c;以及网上对其的整体评价&#xff0c;薪资整体水平等等。 2.公司官方网站 有些公司的网…

Navicat连接mysql报错2003(10060)的解决方法

1、MySQL的服务没有启动&#xff0c;这个是最常见的问题原因 WINR&#xff0c;输入services.msc打开服务管理器&#xff0c;找到mysql 如果显示mysql为禁用状态&#xff0c;可以右键启动服务&#xff0c;然后在Navicat重新测试连接

mFast解析FAST行情内容

目录 一、准备 二、mFast功能 三、解码 四、结果 mFAST FAST协议解析&#xff08;五&#xff09;开源解析库mFAST的使用 - nil - xuanyu.li FAST是将明文内容通过一定规则编码为二进制内容&#xff0c;目的是压缩数据&#xff0c;减小传输压力。解码的时候&#xff0c;可…

vue antv X6流程图

第一 下载2.0插件 第二 引入代码 <!-- --> <template><div id"container" style"min-width: 400px; min-height: 600px"></div> </template><script > //这里可以导入其他文件&#xff08;比如&#xff1a;组件&am…

视频号如何做视频任务进行变现

上节给大家分享了在视频号中的视频如何挂橱窗商品链接进行变现 如果有不清楚的&#xff0c;可以看我上一条视频 以防失联&#xff0c;建议点赞&#xff0c;收藏&#xff0c;加关注 今天跟大家分享的是视频号如何做任务进行变现 只要参与视频号平台变现任务&#xff0c;一条视频…

嵌入式学习笔记(13)汇编写启动代码之开关iCache

什么是cache&#xff0c;有什么用 cache是一种内存&#xff0c;叫高速缓存。 从容量来说&#xff1a;CPU < 寄存器 < cache < DDR 从速度来说&#xff1a;CPU > 寄存器 > cache > DDR cache的存在&#xff0c;是因为寄存器和DDR之间速度差异太大了&#x…

源码角度解析SpringBoot 自动配置

文章目录 前言一、了解相关注解1.Condition注解2.Enable注解 二、SpringBoot自动配置1.SpringBootApplication注解2.SpringBootConfiguration注解3.EnableAutoConfiguration注解4.Conditional注解 总结 前言 Spring Boot 自动配置是 Spring Boot 的核心特性之一&#xff0c;它…

无人化在线静电监控系统的组成

无人化在线静电监控系统是一种用于检测和监控静电情况的系统&#xff0c;它可以自动地实时监测各个区域的静电水平&#xff0c;并在出现异常情况时发出报警信号。静电监控报警器则是该系统中的一个重要组成部分&#xff0c;用于接收和传达报警信号。 无人化在线静电监控系统通…

【人工智能】—局部搜索算法、爬山法、模拟退火、局部剪枝、遗传算法

文章目录 局部搜索算法内存限制局部搜索算法示例&#xff1a;n-皇后爬山算法随机重启爬山模拟退火算法局部剪枝搜索遗传算法小结 局部搜索算法 在某些规模太大的问题状态空间内&#xff0c;A*往往不够用 问题空间太大了无法访问 f 小于最优的所有状态通常&#xff0c;甚至无法储…

SpringMVC入门篇

目录 1.SpringMVC工作流程 2.SpringMVC核心组件 2.1 DispatcherServlet 2.2 HandlerMapping 2.3 Handler 2.4 HandlerAdapter 2.5 ViewResolver 2.6 View 3.SpringMVC的入门 3.1 添加相关依赖 3.2 创建Spring-mvc.xml 3.3 配置web.xml 3.4 效果演示 4.静态资源处…