float精度丢失问题

多年以后1234 2020-12-10 04:20:50
        
//1011000100110010110110.0100110011001100 2903222.29998779296875
//1011000100110010110110.0100111101011100 2903222.30999755859375
Float f1 = 2903222.3F;
Float f2 = 2903222.31F;
System.out.println(f1);
System.out.println(f2);
System.out.println(2903222.3F == 2903222.31F);


如上诉:为什么两者输出显示的都为2903222.2,而不是2903222.299999999999999
...全文
2598 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
冰思雨 2020-12-11
  • 打赏
  • 举报
回复
坐等楼主结贴。
冰思雨 2020-12-11
  • 打赏
  • 举报
回复

//1011000100110010110110.0100110011001100  2903222.29998779296875
//1011000100110010110110.0100111101011100  2903222.30999755859375
// 尝试转换成浮点数进行存储
// 1011000100110010110110.0100110011001100  ==> 1.0110001001100101101100100110011001100 x 2^10101
// 去掉整数部分的“1”和小数点“.”之后,尾数保留23位二进制数
// 尾数部分是 0110001  00110010  11011001
// 阶码是 00010101
// 浮点数存储结构是 00001010  10110001  00110010  11011001

// 我们可以发现,由于尾数的23bit限制,去掉了后面的一些数据。
// 1011000100110010110110.0100110011001100 ==> 1011000100110010110110.01  =  2903222.25
// 1011000100110010110110.0100111101011100 ==> 1011000100110010110110.01  =  2903222.25
// 很明显,2903222.25 ~ 2903222.375 之间的数值由于精度的原因,被丢弃了。
// 为啥是 .25~ .375 呢,因为 0.01(二进制)是0.25(十进制), 0.011(二进制)是0.375(十进制)
// 最后,为啥控制台输出的是 2903222.2 缺少最后一位的5呢?我也不清楚是个啥原因,现在有点晚了,脑子也转不动了,等以后有机会在琢磨吧。
冰思雨 2020-12-11
  • 打赏
  • 举报
回复
数字 13 二进制数 1101 浮点数 1.101x2^11 存储结构 00000011 00000000 00000000 00000101 修正一下,我上面的啰嗦的东西中 0.000101 这个二进制小数 的科学计数法,阶码应该是个负数,我给按照整数来算了,要注意一下,应当是负数。 另外,阶码也是有正负之分的,也就是说,八个bit的存储位中,有一个bit是符号位,负数时保存的也是补码。三十二个bit位的第一个bit位的符号位指的是尾数的符号,也是最终浮点数的正负,当然,尾数是负数时保存的也是补码。
冰思雨 2020-12-11
  • 打赏
  • 举报
回复
楼主需要学习一下 浮点数 在计算机当中的存储结构。 总的来讲,最终都是以二进制的形式进行保存,但是,你要了解其中的精度控制。 这个百度应该也能搜索到。 float 类型,单精度浮点数,使用 32 位二进制数来存储。 知道科学计数法吗? 就是类似1.23×10^4 = 12300 , 等号左边的那种表示方法就是科学计数法,1.23称为尾数,4称为阶码。 浮点数的存储就借鉴了科学计数法这种形式,一共32位二进制数,第一个bit保存正负符号,之后的八个bit保存阶码,剩下的二十三个bit保存尾数, 既然是要保存浮点数(可以带有小数的数据),那么,干脆尾数部分只保存小数就行了,无非是阶码做出相应的调整即可。 例如上述的 1.23×10^4 = 0.123x10^5 两者的值是相同的。我举的例子是十进制数字,主要是为了方便理解,计算机里面存储的还是二进制的数字。 如果一个小数是二进制形式的,那么,二进制只存在0和1的情况,我们在存储的时候,对尾数肯定要做出优化的, 比如 0.000101 这个二进制小数,存做尾数(如果不保存"0"和"."的话)会占用六个bit,尾数优化后,可以表示成 1.01x2^100(注意这是二进制)。 我们可以约定尾数在存储的时候,一定要调整阶码,使其整数部分是 1 (二进制的1)。然后,在存储的时候,调整后的整数部分"1" 和小数点"."不做存储, 主要是为了节省存储空间。然后,在计算和显示的时候,会把 整数部分的 "1" 和小数点 "." 补上,当然,显示的时候还要转换成为十进制数。 啰嗦了这么多,就是要楼主清楚,由于阶码的调整,造成浮点数的精度会受到表示的数值的影响。 换句话说,就是,整数和小数的精度会不一样,不同整数的精度也会存在差别,不同小数的精度也会存在差别, 因为转换成二进制进行保存的时候,尾数要进行优化,阶码要随着进行调整。 阶码的调整不会影响精度,但是,尾数的优化有的时候会影响到精度,因为,尾数只有23bit的空间进行存储,超出这个范围的值就无法保存了。
tianfang 2020-12-10
  • 打赏
  • 举报
回复
单精度浮点就有6位多(10进制)的精度,理论误差的范围内
明白畅达 2020-12-10
  • 打赏
  • 举报
回复
所以还是要用BigDecimal

51,412

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧