剖析float相加产生精度损失的原因

news2024/12/25 9:20:36

float相加产生精度损失的原因

  • 一、什么是float类型及其特点
    • 1.1、float类型的定义和使用方法
    • 1.2、float类型的特点,包括精度限制
  • 二、为什么会出现float相加精度损失
    • 2.1、计算机二进制存储浮点数的方式
    • 2.2、浮点数运算中的舍入误差
    • 2.3、累加多个小数时的误差累积
  • 三、如何减少float相加精度损失
  • 四、实例说明
    • 4.1、实验数据对比展示float相加精度损失
    • 4.2、减少float相加精度损失的方法的示例
  • 五、总结

一、什么是float类型及其特点

1.1、float类型的定义和使用方法

float(浮点数)是一种在计算机编程中常用的数据类型,它用于表示带小数点的数字。在大多数编程语言中,float类型通常使用32位来表示,也被称为“单精度浮点数”或“单精度实数”。它可以表示的数值范围比整数类型要大得多,并且可以存储小数位数较多的数值。在C++、Java等语言中,float类型的定义通常如下:

C/C++:

float num = 3.14;

Java:

float num = 3.14f;

需要注意的是,在Java中赋值给float类型的数值后面必须加上字母“f”,否则会被默认为double类型。

在这里插入图片描述

其使用方法如下:

(1)声明float类型的变量:用float关键字声明一个变量,并为其赋值。例如:

float num = 3.14;

(2)进行运算:可以对float类型的变量进行数学运算,包括加、减、乘、除等。例如:

float result = num + 2.5;

(3)输出float类型的变量:可以使用printf或者cout函数来输出float类型的变量。例如:

printf("%.2f", num); 

cout << num << endl;

需要注意的是,由于float类型只有32位,所以它的精度有限。在进行高精度计算时,建议使用double类型。

1.2、float类型的特点,包括精度限制

float类型是一种浮点数类型,用于表示带有小数的数字。它的特点是:

  1. 精度有限:float类型在内存中存储时只能精确表示一定范围内的数字,超出这个范围的数字会被舍入成最接近的可表示数字。这个范围通常是-3.4028235E+38到3.4028235E+38之间。
  2. 单精度:float类型只能表示单精度浮点数,即32位(4字节)的浮点数。
  3. 运算速度快:由于占用空间少,所以float类型的运算速度比较快。
  4. 可用科学计数法表示:由于float类型的精度有限,因此可以使用科学计数法来表示超过范围的数字。

float类型是一种精度有限但可以快速运算的浮点数类型。在处理较大或较小的数字时,需要注意其精度限制。

二、为什么会出现float相加精度损失

浮点数在计算机内部是以二进制表示的,但是很多十进制小数无法完全用二进制精确表示,因此在进行浮点数的加减乘除等运算时,可能会出现一定程度的精度损失。这是由于计算机只能使用有限的位数来表示数字,而且在计算过程中会发生舍入误差。如果参与运算的两个浮点数的小数位数比较多或者差异较大,那么可能会导致精度损失更大。

2.1、计算机二进制存储浮点数的方式

计算机通常使用IEEE 754标准来存储浮点数。在该标准中,一个浮点数由三部分组成:符号位、指数和尾数。

首先,第一位用于表示符号位(0表示正数,1表示负数),接下来的几位表示指数,最后的几位表示尾数。

具体来说,IEEE 754标准定义了两种浮点数格式:单精度浮点数和双精度浮点数。

单精度浮点数占用32位,其中1位表示符号位,8位表示指数,23位表示尾数。双精度浮点数占用64位,其中1位表示符号位,11位表示指数,52位表示尾数。

为了提高精度,IEEE 754标准还定义了一些额外的特殊值,包括正无穷大、负无穷大、NaN等。这些特殊值可以帮助计算机处理极端情况,并提高浮点数运算的安全性和可靠性。
在这里插入图片描述

2.2、浮点数运算中的舍入误差

浮点数运算中的舍入误差是指在进行浮点数计算时,由于数字的精度有限,导致计算得到的结果与实际结果存在一定误差。这种误差通常是由于计算机无法表示某些十进制小数或无理数的精确值而产生的。

例如,对于以下两个浮点数:0.1 和 0.2,将它们相加,得到的结果应该是0.3,但实际上计算机可能会返回一个略微不同的结果,如0.30000000000000004。这是因为计算机无法完全表示0.1和0.2的精确值,因此在计算时会存在一定的误差。

类似地,当进行多次浮点数运算时,每次运算都可能会使误差累积,从而导致最终结果与实际结果之间的误差变得更大。因此,程序员在进行浮点数计算时需要特别注意处理舍入误差的问题,以免影响程序的正确性和稳定性。

2.3、累加多个小数时的误差累积

在计算机中,浮点数的精度是有限的,因此在进行多个小数的累加时,会出现误差累积的问题。这是因为每次累加都会产生一些舍入误差,而这些误差会随着累加次数的增加而逐渐累积。

假设要计算一系列小数的和,例如0.1、0.2、0.3、0.4、0.5等等。如果使用单精度浮点数进行累加,那么最终得到的结果可能会与预期结果存在较大的误差。例如,在累加前四个数时,得到的结果可能为0.9999999999999999,而不是1.0。这是因为每次累加都会产生一些舍入误差,导致结果与实际值之间存在一定的误差。

为了避免误差累积的问题,可以使用高精度的数值类型或者采用一些特殊的算法来处理。例如,可以使用BigDecimal类来处理小数的加法运算,该类提供了高精度的计算功能,可以保证结果的精度和准确性。同时,在实际应用中,还需要合理设计算法,尽量减少累加次数,以降低误差累积的风险。

三、如何减少float相加精度损失

在进行浮点数相加时,精度损失是不可避免的,但可以通过一些方法来尽可能地减少精度损失。

  • 尽量避免使用float类型进行累加操作。
  • 将相近的数值合并。例如,在计算0.1 + 0.2 + 0.3时,可以先将0.1和0.2相加得到0.3,再加上0.3,这样可以减少误差的累计。
  • 使用double类型或者BigDecimal类型进行数值计算。double类型具有更高的精度,可以减少精度损失;使用BigDecimal类型可以获得更高的精度和更好的控制。
  • 按照从小到大的顺序进行相加。这样可以保证较小的数字先被相加,减少误差的传递。
  • 避免多次重复相加相减。如果需要对同一组数进行多次相加或相减运算,可以先将它们全部相加或相减,然后再进行其它计算,以减少误差的产生。
  • 对于需要高精度计算的场景,采用相关算法优化。

四、实例说明

4.1、实验数据对比展示float相加精度损失

由于浮点数的精度有限,相加时可能会出现精度损失。示例:

a = 0.1
b = 0.2
c = a + b

print(c)

期望输出结果为0.3,但实际结果为:

0.30000000000000004

这是由于0.1和0.2在内存中以二进制表示时,无法完全精确地表示。因此,在计算机内部,它们实际上被存储为最接近的二进制分数。当它们相加时,结果也被存储为最接近的二进制分数。

以下是进行多次浮点数相加的结果对比:

# 测试数据
a = 0.1
b = 0.2
c = 0.3

# 相加100次
sum_1 = sum_2 = sum_3 = 0
for i in range(100):
    sum_1 += a
    sum_2 += b
    sum_3 += c

# 输出结果
print("sum_1: ", sum_1)
print("sum_2: ", sum_2)
print("sum_3: ", sum_3)

输出结果为:

sum_1:  9.99999999999998
sum_2:  19.999999999999986
sum_3:  30.000000000000004

可以看到,进行多次浮点数相加后,结果出现了精度损失,与期望值有一定的偏差。这也说明了在进行浮点数计算时需要注意精度损失的问题。

4.2、减少float相加精度损失的方法的示例

使用double类型来减少float相加精度损失的影响:

#include <iostream>
using namespace std;

int main() {
    float a = 3.14159265358979;
    float b = 0.00000000000001;
    
    double c = 3.14159265358979;
    double d = 0.00000000000001;
    
    float sum1 = a + b;
    double sum2 = c + d;
    
    cout << "Sum1: " << sum1 << endl; // 输出:Sum1: 3.14159
    cout << "Sum2: " << sum2 << endl; // 输出:Sum2: 3.1415926535998
    return 0;
}

从上面的代码可以看出,当使用float类型进行相加运算时,得到的结果只保留了小数点后5位,而使用double类型进行相加运算时,得到的结果保留了小数点后13位,这是因为double类型具有更高的精度所导致的。

因此,在实际开发中,如果需要进行浮点数计算并且要求高精度的结果,建议使用double类型来代替float类型。

五、总结

  1. float类型虽然有精度限制,但在某些场景下仍具有有效性。例如,在计算机图形学中,使用浮点数可以表示3D空间中的坐标和向量。在科学计算、金融分析等领域中,也常常需要对小数进行精确计算,此时使用高精度的浮点数类型也是很有用的。另外,浮点数还可以用于近似计算,例如在机器学习中,通常使用浮点数来表示神经网络的权重和偏置,通过迭代优化这些参数,可以让模型逼近最优解。因此,在实际应用中,浮点数依然是一种非常重要的数据类型。
  2. 减少float相加精度损失的方法可以提高计算结果的准确性。
  3. 在实际工作中要根据具体情况选择合适的数值计算方法。
    在这里插入图片描述

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

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

相关文章

kali中Metasploit基本使用方法

1.kali启动postgresql并设置开机自启动 systemctl start postgresql.servicesystemctl enable postgresql.service2.kali启动Metasploit 方式一:应用程序 -> 漏洞利用工具集 -> Metasploit framework 方式二: msfconsole 3. Metasploit常用命令 connect 命令 连接远程主…

Qt信号槽之connect介绍(上)

关于Qt信号槽中connect与disconnect介绍 首先我们要知道&#xff0c;如果想要使用Qt中的信号槽机制&#xff0c; 那么必须继承QObject类&#xff0c;因为QObject类中包含了信号槽的一系列操作&#xff0c;今天我们来讲解的是信号与槽怎么建立连接以及断开连接。 一、connect …

在windows server上用Mosquitto软件创建MQTT服务器

今天下午捣鼓了半天&#xff0c;在云服务器上面创建了个MQTT服务器&#xff0c;然后用MQTTX软件进行了测试。过程记录如下&#xff1a; 1、下载mosquitto软件&#xff0c;链接如下图&#xff1a; 2、下载完成后安装&#xff0c;一直点下一步下一步就好了。 3、在安装路径下&am…

快速捡回使用workbench控制mysql创建数据库的基本步凑

首先如果&#xff0c;不想要在原来已经建好的数据库下建立数据表&#xff0c;可以新建数据库。 具体操作步凑如下&#xff1a; 选择后如下所示&#xff1a; 有现成的创建代码的话&#xff0c;就直接复制执行现成的创建代码即可&#xff0c;如果没有现成的创建代码的话&#xff…

Java设计模式之单例模式-【懒汉式与饿汉式】

1、单例&#xff0c;模式 单例模式属于创建型模式的一种&#xff0c;应用于保证一个类仅有一个实例的场景下&#xff0c;并且提供了一个访问它的全局方法 单例模式的特点&#xff1a;从系统启动到终止&#xff0c;整个过程只会产生一个实例。单例模式常用写法&#xff1a;懒汉…

STM32设置为I2C从机模式

STM32设置为I2C从机模式 目录 STM32设置为I2C从机模式前言1 硬件连接2 软件编程3 运行测试3.1 I2C连续写入3.1 I2C连续读取3.1 I2C单次读写测试 4 总结 前言 STM32的I2C作为主机的情况相信很多同学都用过&#xff0c;网上也有很多教程&#xff0c;但是作为从设备使用的例子应该…

【C++ 程序设计】第 9 章:函数模板与类模板

目录 一、函数模板 &#xff08;1&#xff09;函数模板的概念 &#xff08;2&#xff09;函数模板的示例 &#xff08;3&#xff09;函数或函数模板调用语句的匹配顺序 二、类模板 &#xff08;1&#xff09;类模板概念 &#xff08;2&#xff09;类模板示例 &…

阵列模式综合第三部分:深度学习(附源码)

一、前言 这个例子展示了如何设计和训练卷积神经网络&#xff08;CNN&#xff09;来计算产生所需模式的元素权重。 二、介绍 模式合成是阵列处理中的一个重要课题。阵列权重有助于塑造传感器阵列的波束图案&#xff0c;以匹配所需图案。传统上&#xff0c;由于空间信号处理和频…

SSL工作原理

SSL 是一个安全协议&#xff0c;它提供使用 TCP/IP 的通信应用程序间的隐私与完整性。因特网的 超文本传输协议&#xff08;HTTP&#xff09;使用 SSL 来实现安全的通信。 在客户端与服务器间传输的数据是通过使用对称算法&#xff08;如 DES 或 RC4&#xff09;进行加密的。公…

使用ZenDAS进行Gompertz趋势分析

某项目做了18次测试&#xff0c;每次测试发现的缺陷个数如下表所示&#xff1a; 测试序号 发现缺陷数 1 60 2 96 3 157 4 191 5 155 6 106 7 64 8 335 9 92 10 196 11 109 12 133 13 166 14 129 15 16 16 30 17 19 18 5 对上述的数据在Z…

IPv6手工隧道配置与验证实验

IPv6手工隧道配置与验证实验 【实验目的】 熟悉IPv6手工隧道的概念。 掌握IPv6和IPv4共存的实现方法。 掌握IPv6手工隧道的配置。 验证配置。 【实验拓扑】 实验拓扑如下图所示。 实验拓扑 设备参数如表所示。 设备参数表 设备 接口 IPv6地址 子网掩码位数 默认网…

中间件-netty(1)

netty 前言篇 文章目录 一、IO基础篇1.概念1.1 阻塞(Block)和非阻塞(Non-Block)1.2 同步(Synchronization)和异步(Asynchronous)1.3 BIO 与 NIO 对比1.3.1 面向流与面向缓冲1.3.2 阻塞与非阻塞1.3.3 选择器的问世 2.NIO 和 BIO 如何影响应用程序的设计2.1 API调用2.2 数据处理2…

蓝桥杯专题-试题版-【操作格子】【查找整数】【分解质因数】【高精度加法】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (二)

开始用上一篇文章讲到的Spring依赖注入的步骤&#xff0c;用两个例子来推导一下整个过程&#xff0c;举例子有助于了解真相。 先用一个最简单的例子&#xff1a;没有依赖的单例bean的创建。 推导过程是需要上一篇文章的步骤的&#xff0c;要参照步骤一步一步来。 无依赖的单…

Linux内核代码60%都是驱动?驱动代码不会造成内核臃肿吗?

为什么内核中驱动占比最高 一、前言二、Linux中避免内核臃肿的措施2.1 交叉编译及SDK包的裁剪2.2 设备树2.3 模块化2.4 硬件抽象层 三、嵌入式Linux的裁剪四、总结 一、前言 今天逛知乎看到这么一个问题&#xff1a;为什么Linux内核代码60%都是驱动? 如果每支持新的设备就加入…

【设计模式】Java设计模式——模板方法模式(Template Pattern)

文章目录 1. 介绍1.1 定义1.2 作用 2. 模式结构2.1 UML类图2.2 模式组成 3. 代码实例3.1 背景3.2 应用 4. 优点5. 缺点6. 应用场景 1. 介绍 1.1 定义 模板方法模式(Template Pattern)&#xff0c;又叫模板模式&#xff0c;它属于行为型模式模板方法模式定义一个模板结构&…

Apikit 自学日记:版本管理

功能入口&#xff1a;API管理应用 / 选中某个项目 / 项目管理菜单 / 项目版本管理 项目版本管理功能模块提供对项目级别的版本管理&#xff0c;可新增、删除、对比项目级版本。在创建项目版本号的时候会对整个项目的部分模块数据进行快照保存。可用于每次迭代发布打全局版本号…

ESP32设备驱动-TMF8801激光测距传感器驱动

TMF8801激光测距传感器驱动 文章目录 TMF8801激光测距传感器驱动1、TMF8801介绍2、硬件准备3、软件准备4、驱动实现1、TMF8801介绍 TMF8801 是一款真正的直接飞行时间 (ToF) 传感器系统,采用单一模块化封装,通过亚纳秒光脉冲和抗锯齿“秒表”方法测量往返时间,提供高精度深度…

流量分析工具wireshark-学习笔记

&#xff08;一&#xff09;wireshark工具 1、wireshark工具简介 Wireshark是一种开源网络分析工具&#xff0c;它可以让你在计算机网络上捕获和查看数据包&#xff0c;并能帮助你深入了解网络的运行和协议的实现。它可以捕获不同类型的流量&#xff0c;包括以太网、Wi-Fi、TC…

【面试题】面试官问:如果有100个请求,你如何使用Promise控制并发?

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 开篇 在现代Web开发中&#xff0c;异步请求已经成为了必不可少的一部分。然而&#xff0c;…