当前位置: 首页 > news >正文

float为什么会丢失精度?

基于我们之前讨论的IEEE 754浮点数格式数据类型float是在计算机中是如何存储的,现在我来详细解释float的最大值以及精度丢失的原因。

Float的最大值

在IEEE 754单精度浮点数中,最大值由以下因素决定:

1. 正规数的最大值

指数部分

  • 指数位:8位,最大不能是11111111(这个保留给无穷大和NaN)
  • 最大指数值:11111110 = 254
  • 真实指数 E = 254 - 127 = 127

尾数部分

  • 尾数位:23位,全部为1
  • 实际尾数 M = 1.11111111111111111111111₂
  • 这个值等于 2 - 2⁻²³

组合后的最大值

Max_float = (2 - 2⁻²³) × 2¹²⁷≈ 3.4028235 × 10³⁸

2. 实际表示

在代码中,这个值通常定义为 FLT_MAX

#include <float.h>
printf("FLT_MAX = %e\n", FLT_MAX);  // 输出:3.402823e+38

3. 为什么不是更大的值?

  • 如果指数再大(11111111),就变成了无穷大
  • 尾数已经达到了23位的最大表示能力
  • 这是正规数范围内能够表示的最大有限数

精度丢失的原因

精度丢失的根本原因是:用有限的、离散的二进制位来近似连续的实数

1. 二进制与十进制的转换问题

经典例子:0.1

0.1 + 0.2 == 0.3  # 结果是 False

为什么?

  • 0.1₁₀ 在二进制中是无限循环小数:0.000110011001100110011001100…
  • 就像 1/3 在十进制中无法精确表示一样(0.33333…)
  • float只有23位尾数位,必须进行舍入

转换过程

0.1₁₀ → 二进制:0.000110011001100110011001100110011001100...
规范化:1.10011001100110011001100... × 2⁻⁴
存储时只能保留前23位小数:1.10011001100110011001101

这个舍入误差在多次运算中会累积放大。

2. 精度分布不均匀

浮点数的精度不是固定的,而是随着数值大小变化

#include <stdio.h>int main() {float a = 16777216.0f;  // 2²⁴float b = 1.0f;printf("%f + %f = %f\n", a, b, a + b);// 输出:16777216.000000 + 1.000000 = 16777216.000000// 1被"吃掉"了!
}

为什么会出现这种情况?

  • 16777216.0 (2²⁴) 时,相邻两个可表示的float相差 2.0
  • 因为此时指数 E = 24,尾数的最小变化单位是 2²⁴ × 2⁻²³ = 2¹ = 2
  • 1.0 < 2.0,所以无法被分辨

精度与数值大小的关系

数值范围        精度(相邻数的差值)
[2⁻¹²⁶, 2⁻¹²⁵]  约 10⁻⁴⁵
[1, 2)          2⁻²³ ≈ 1.2 × 10⁻⁷
[2, 4)          2⁻²² ≈ 2.4 × 10⁻⁷
[2²³, 2²⁴)      2⁰ = 1

3. 尾数位的有限精度

23位尾数只能表示 2²³ = 8,388,608 个不同的分数值。

精度极限

  • float大约有 6-7位 有效的十进制精度
  • double大约有 15-16位 有效的十进制精度

验证代码:

#include <stdio.h>int main() {float f = 123.456789f;printf("存储的值: %.15f\n", f);// 可能输出:123.456787109375000// 可以看到第7位之后就开始不准确了
}

4. 运算中的误差累积

灾难性抵消

#include <stdio.h>
#include <math.h>int main() {float a = 1.234567f;float b = 1.234566f;float c = 0.000001f;float result1 = (a - b) - c;  // 理论上应该是0float result2 = a - (b + c);  // 另一种计算顺序printf("(a - b) - c = %.10f\n", result1);printf("a - (b + c) = %.10f\n", result2);// 两个结果可能不同,都不精确
}

5. 特殊数值的表示限制

次正规数区域

  • 当指数位全0时,隐藏位变成0而不是1
  • 这个区域的数值精度极低,运算速度也很慢
  • 很多GPU甚至不支持次正规数的正确处理

实际编程建议

1. 避免直接比较浮点数

// 错误的方式
if (a == b) { ... }// 正确的方式
if (fabs(a - b) < 1e-6) { ... }  // 使用容差

2. 注意运算顺序

// 不好的顺序:大数吃小数
float sum = large_number + small_number1 + small_number2;// 好的顺序:先加小数,再加大数
float sum = small_number1 + small_number2 + large_number;

3. 选择合适的数值类型

  • 金融计算:使用定点数或十进制浮点数
  • 科学计算:根据精度需求选择float或double
  • 整数运算:对于可以整数化的问题,尽量用整数

4. 了解你的数值范围

在开始计算前,预估数值的可能范围,避免在精度很差的区域进行计算。

总结

Float精度丢失的本质是用有限的离散表示无限的连续,具体表现为:

  1. 进制转换损失:十进制有限小数可能是二进制无限小数
  2. 精度不均匀:数值越大,精度越低
  3. 位数限制:只有24位有效二进制位
  4. 运算累积:舍入误差在多次运算中放大
http://www.dtcms.com/a/553504.html

相关文章:

  • 网站产品后台界面怎么做微信朋友圈广告推广
  • 香港科技大学广州|可持续能源与环境学域博士招生宣讲会—吉林大学专场
  • LaTeX 重点表格文字对不齐(有些列文字和其他列差一行才显示)的原因和解决办法
  • 网站推广必做百度云打开的wordpress
  • soular零基础学习,如何统一管理TikLab帐号体系
  • kanass零基础学习:创建第一个项目
  • 【C语言实战(66)】筑牢防线:C语言安全编码之输入与错误处理
  • 【机器学习11】决策树进阶、随机森林、XGBoost、模型对比
  • 唯品会 一家专门做特卖的网站做振动盘的企业网站
  • 我的WordPress网站锦州网站建设市场
  • Spring Boot 3.3新特性全解析
  • 剪映蒙版模糊去水印全攻略:静态/动态水印
  • PandaCoder 2.4.3 震撼发布!
  • LeetCode 分类刷题:445. 两数相加 II
  • 使用Docker搭建Swagger接口文档工具
  • 团队氛围建设 网站网站开发合同 深圳思
  • 机器学习第二阶段
  • 深圳网站建设单位如何在淘宝网做自己的网站
  • Python中正则表达式(re 模块)详解使用(1)原理篇
  • 给运维插上 AI 的翅膀:我的 Dify AIOps 探索之旅
  • aspcms建站wordpress 前台登陆
  • VTK操作3D文件
  • 3DMAX低多边形城市建筑模型预设插件LowPolyCityBuilder使用方法
  • windows系统上aosp15上winscope离线html如何使用?
  • 公司备案网站负责人是谁中山金舜家庭用品有限公司怎样网站地图
  • 讨论矩阵等价、相似的几何含义
  • 基于 LLM 的社交机器人对舆论动态的影响机制
  • 贸易公司如何做网站莱芜网站建设怎么样
  • 多形态机器人协同发力优艾智合引领核电运维智能化升级
  • 【C++】基于HashTable的底层实现unordered_map和unordered _set 的封装