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

【笔记】float类型的精度有限,无法精确表示123456.6789

一、前情提要

有个Java数据转换的小示例:

public class Example2_2 {public static void main(String[] args) {float f = 123456.6789f;System.out.printf("f=%30.12f", f);}
}

输出的结果是:
在这里插入图片描述

123456.679687500000

这里就发现了个问题,我变量f定义的值是123456.6789,为什么输出的结果小数位变了呢??

简单来说,核心原因是 float类型的精度有限,无法精确表示123456.6789

Java 中float是32 位单精度浮点数,遵循 IEEE 754 标准。它的存储结构由 1 位符号位、8 位指数位和 23 位尾数位(实际有效精度约 24 位)组成。
这种结构导致float只能精确表示有限的十进制小数,对于大多数十进制小数(如代码中的123456.6789),它无法精确存储,只能存储一个最接近的近似值。

那么如何理解float类型无法精确表示123456.6789??

要理解“float类型无法精确表示123456.6789”,需要从计算机如何存储小数说起。这本质上是“二进制与十进制的转换限制”和“float的存储空间有限”共同导致的问题,我们一步步拆解:

二、计算机如何存储小数以及float空间限制

1. 计算机只认识二进制,不认识十进制

我们日常用的是十进制(0-9),但计算机内部所有数据(包括小数)都必须转换成二进制(0和1)存储。
对于整数(如123),十进制转二进制是“除2取余”,结果是有限的二进制数(比如123的二进制是1111011),可以精确存储。

小数的转换要复杂得多:十进制小数转二进制的方法是“乘2取整”,例如0.6789转二进制的过程是:

  • 0.6789 × 2 = 1.3578 → 取整数部分1(二进制小数第一位是1)
  • 剩下的0.3578 × 2 = 0.7156 → 取整数部分0(第二位是0)
  • 剩下的0.7156 × 2 = 1.4312 → 取整数部分1(第三位是1)
  • 剩下的0.4312 × 2 = 0.8624 → 取整数部分0(第四位是0)
  • … 以此类推

这个过程可能无限进行下去(永远无法得到整数1.0),就像十进制中1/3=0.3333…无限循环一样。
也就是说:大部分十进制小数无法用有限长度的二进制精确表示,只能得到一个近似值。

2. float类型的“存储空间”被严格限制

Java的float是32位单精度浮点数,遵循IEEE 754标准,它的存储空间被分成3部分:

  • 1位符号位(表示正负)
  • 8位指数位(表示数值的大小范围)
  • 23位尾数位(表示数值的精度,即有效数字)

关键限制在这里:尾数位只有23位(加上默认的1位隐藏位,总共24位有效精度)。
24位二进制能表示的有效数字相当于多少位十进制呢?
通过公式换算:24 × log₁₀(2) ≈ 7.2位。
也就是说:float最多只能精确表示6-7位十进制有效数字,超过这个范围的数字会被“舍入”,导致精度丢失。

3. 为什么123456.6789无法被float精确表示?

我们来看123456.6789的有效数字:
整数部分是123456(6位),小数部分是6789(4位),总共是10位有效数字(1-2-3-4-5-6-6-7-8-9)。

而float最多只能精确到7位有效数字,第8位及以后的数字无法精确存储,只能根据二进制转换规则进行“四舍五入”。

具体来说:
当你写float f = 123456.6789f时,计算机需要把123456.6789转换成二进制,但因为:

  • 小数部分0.6789的二进制是无限循环的
  • 尾数位只有23位,无法容纳全部二进制 digits

最终计算机只能存储一个“最接近123456.6789的二进制近似值”。当这个二进制近似值再转换回十进制时,就变成了123456.6796875(而不是原来的123456.6789)。

4. 一个更简单的类比

假设你有一个只能写7个数字的笔记本,现在要记录“123456789”(9个数字)。
因为本子空间不够,你只能记一个近似值,比如“123456800”(前7位保留,后面的四舍五入)。

float的问题和这个类比完全一样:它的“笔记本”(尾数位)只能放下相当于7位十进制的有效数字,对于123456.6789(10位有效数字),只能记录一个近似值。

三、总结

float无法精确表示123456.6789的核心原因是:

  1. 十进制小数转二进制时,大部分是无限循环的,无法用有限位数表示;
  2. float的尾数位只有23位(约7位十进制精度),无法容纳123456.6789的10位有效数字,只能存储近似值。

这也是为什么输出结果是123456.6796875——这是float能存储的最接近原始值的近似值。

http://www.dtcms.com/a/362038.html

相关文章:

  • 【Audio】静音或振动模式下重复来电响铃
  • Java Web项目后台管理系统之内容管理仿写(三):图片上传
  • 使用 BayesFlow 通过神经网络简化贝叶斯推断(一)
  • C扩展4:X宏(X-MACRO)
  • JS循环机制
  • IS-IS的原理
  • Java超卖问题
  • MySQL安装与使用指南
  • 【读论文】量子关联增强双梳光谱技术
  • 力扣404 代码随想录Day15 第三题
  • 故障排查指南:理解与解决 “No route to host“ 错误
  • NOSQL——Redis
  • MySQL基础知识保姆级教程(四)视图与约束
  • 浅谈中断控制器:从 IRQ 到 IRR、IMR、In-Service Register
  • 软考-操作系统-错题收集(3)文件系统的索引节点结构
  • 【前端】《手把手带你入门前端》前端的一整套从开发到打包流程, 这篇文章都会教会你;什么是vue,Ajax,Nginx,前端三大件?
  • ComPE for win 纯净的PE系统
  • 软考中级数据库系统工程师学习专篇(67、数据库恢复)
  • Spring Security 深度学习(四): 会话管理与CSRF防护
  • 2025 数字化转型期,值得关注的 10 项高价值证书解析
  • Linux笔记---计算机网络概述
  • 视频动作识别模型-C3D
  • 线程池项目代码细节5(解决linux死锁问题)
  • 关系型数据库——GaussDB的简单学习
  • 《投资-43》- 自然=》生物=》人类社会=》商业=》金融=》股市=》投资的共同逻辑:生存竞争与进化论
  • 前端实现查询数据【导出】功能
  • 自制扫地机器人(二) Arduino 机器人避障设计——东方仙盟
  • A股大盘数据-20250901 分析
  • 设计模式:代理模式(Proxy Pattern)
  • HOW - 前端团队组长提升(沟通篇)