float小,double大,我把小的数放到大的空间里面,为什么还会有精度损失?

让我们来看这样一个例子:

double a = 2.3F;
System.out.println(a);

输出的 a 为 2.299999952316284

不再是 2.3 了!

明明 float 小,double 大,我把小的数放到大的空间里面,为什么还会有“精度损失”?

关键点是表示精度而非“空间”大小:

  1. 浮点数的存储机制(IEEE 754 标准):

    • floatdouble 都是基于 IEEE 754 标准存储浮点数。它无法精确存储所有的十进制小数,原因在于 二进制表示系统的局限性
    • float 使用 32 位,其中 1 位用于符号,8 位用于指数,23 位用于尾数(也叫有效位数)。
    • double 使用 64 位,其中 1 位用于符号,11 位用于指数,52 位用于尾数。

    因此,float 的尾数只能存储 23 位有效数字,而 double 的尾数可以存储 52 位有效数字。

  2. 浮点数在二进制中的表示限制:
    浮点数通常不能被精确表示为二进制数。例如,2.3 是一个十进制数,但在二进制中它无法被精确表示,只能是一个近似值。

    • 当你在 Java 中声明 float a = 2.3F; 时,Java 会将 2.3 转换成其在 float 类型中的二进制近似值,这个近似值是 2.2999999523162841796875(其二进制表示)。
    • 由于 float 的精度只有 23 位尾数,所以它只能表示到这么精确的值,即我们看到的四舍五入结果为 2.3
  3. floatdouble 的转换:
    当你将 float 转换为 double 时,不会发生“精度损失”,只是 double 能够表示得更加精确,它可以保留 float 的原始二进制表示,但仍然是 float 精度的近似值(这是因为它来自 float 的有限精度的二进制近似)。

    • float 的精度是 23 位尾数,即它的二进制近似值是 2.2999999523162841796875
    • 当这个值转换为 double 时,double 可以表示更多的位数(52 位尾数),于是它就显示出了更多原始 float 的二进制近似值的真实数字,即 2.299999952316284
  4. 为什么看起来像是“损失精度”?
    并不是你在 double 中“损失了精度”,而是由于 float 本身的精度有限,它只能表示出一个有限的近似值。这个近似值在被转换为 double 时,double 可以显示更多的二进制位数,于是你看到的是 float 原本就不够精确的数字。

    换句话说,float 被转化为 double 时,并没有损失任何精度,只是 double 展现了 float 精度限制下的原本“隐藏的”部分

总结:

  • float a = 2.3F;:由于 float 的精度限制,它存储的近似值是 2.2999999523162841796875,但显示为 2.3
  • double a = 2.3F;:当 float 的二进制近似值被存储到 double 时,double 能显示出更多的尾数位数,展示了原本 float 类型未能显示的那部分,即 2.299999952316284

补充具体说明:

计算机在底层使用二进制存储数值,但并非所有的十进制小数都可以用二进制精确表示。这与我们用十进制表示某些分数(如 1/3)时需要无限循环小数类似。

float 在 Java 中是一个 32 位的浮点类型,它能够精确存储的数的范围主要是有限的离散值

在十进制系统中,数字 2.3 的分数表示是 23/10。当我们将这个十进制数转换为二进制时,它无法表示为一个精确的有限二进制小数,因为:

  • 二进制中只能精确表示某些分数,比如 1/2, 1/4, 1/8 等,都是 2 的幂。
  • 2.3 并不是可以通过这些简单的 2 的幂表示出来的,因此它只能近似表示为一个有限的二进制数。

具体来说,2.3 转换为二进制后的无限小数大致是:

2.3 ≈ 10.0100110011001100110011...(无限循环)

由于计算机的位数有限,它无法存储无限位数的小数,因此只能截断,导致了精度误差。

对于像 1.2345678 这样的数字,float 可以精确表示。

但是对于像 2.3 这样的数字,它不能被精确表示,因为它无法在有限的位数内表示该小数的二进制表示。

如果需要表示精度更高的数字,应该使用 double 类型,它使用 64 位存储浮点数,拥有更大的尾数位数(52 位),可以表示大约 15 位十进制有效数字

但是,即便使用 double,并不是所有的十进制数仍然都可以精确表示,因为这是二进制系统的固有限制。

如果需要更高的精度,应考虑使用 doubleBigDecimal 来表示和计算精确的十进制值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值