浮点数精度丢失的原因和解决办法

本文深入探讨了二进制浮点数与十进制浮点数之间的转换原理,解析了float和double类型在计算机中的存储方式,尤其是指数部分为何float加127而double加1023。同时,文章揭示了浮点数加减运算中精度丢失的原因,并提供了使用BigDecimal类来避免精度问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二进制浮点数转换为十进制浮点数

在这里插入图片描述

十进制浮点数转换为二进制浮点数

在这里插入图片描述

浮点数的存储

在这里插入图片描述

在这里插入图片描述

float类型在计算机中的存储形式中指数为什么要加127,而double类型要加1023?

以float为例,计算机表示单精度浮点数时,是用8位去存储指数部分,即表示0-255,但我们同样需要有负指数,正负指数的位数量为了均等,各自一半,-127-128。0是特殊点,特殊处理。储存时候会加上127,这样就刚刚好是0~255,就能很好的储存了,不然,不移量的话需要判断符号位来判断数值的正负。
在这里插入图片描述

浮点数加减运算时可能精度丢失的原因

public static void main(String[] args) {
      System.out.println(2.0f-1.5f);//0.5
      System.out.println(2.0f-1.4f);//0.6
      System.out.println(2.0f-1.3f);//0.70000005
}

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

如何避免精度丢失

使用float和double进行运算时可能会有进度丢失,因此实际开发中不建议直接使用float和都被进行运算,而是使用new BigDecimal(String str)来解决:

public static void main(String[] args) {
   System.out.println(2.0f-1.3f);//0.70000005
   System.out.println(new BigDecimal(2.0f).subtract(new BigDecimal(1.3f)));//0.7000000476837158203125
   System.out.println(BigDecimal.valueOf(2.0f).subtract(BigDecimal.valueOf(1.3f)));//0.7000000476837158
   //new BigDecimal(String str)这种方式可以解决浮点数问题
   System.out.println(new BigDecimal(String.valueOf(2.0f)).subtract(new BigDecimal(String.valueOf(1.3f))));//0.7
}
### 浮点数在双字节传输中的精度保持 为了确保浮点数在双字节传输过程中不丢失精度,通常需要采取特定的技术手段协议。以下是几种常见的方法: #### 使用更高精度的数据类型 当涉及浮点数的传输时,可以选择使用更高精度的数据类型来减少舍入误差。例如,在某些编程环境中支持 `double` 数据类型的变量可以在发送前换为更高的精度再进行压缩传输[^1]。 ```c++ // 将float成string并保留更多有效位数后再传送给接收端解析 std::stringstream stream; stream << std::setprecision(15) << myFloatValue; // 设置输出流的小数点后的精度 std::string str = stream.str(); ``` 然而需要注意的是,这种方法增加了数据大小,并不是真正的解决办法而是变通方案;对于严格意义上的“双字节”,即每次仅能传递两个字节的情况并不适用。 #### BCD 编码的应用 考虑到题目中提到的双字节限制以及对精度的要求,可以考虑采用 **BCD (Binary-Coded Decimal)** 编码方式。这种方式下每一位十进制数字由四个二进制比特表示,从而能够保证较高的数值准确性而不受传统浮点表达带来的舍入影响[^4]。 ```cpp uint16_t encode_bcd(float value){ int integerPart = static_cast<int>(value); uint16_t bcdInteger = 0; while(integerPart != 0){ bcdInteger <<= 4; // 左移四位腾出位置给下一个bcd编码 bcdInteger |= (integerPart % 10); // 取余得到当前最低位放入bcd编码最后一位 integerPart /= 10; // 整除去掉已经处理过的那一位 } return bcdInteger; } ``` 此函数实现了将一个浮点数化为其整数部分对应的BCD编码的过程。当然还需要额外编写解码过程以便于接收到的信息被正确解读出来。 #### 自定义协议与校验机制 除了上述技术外,还可以通过自定义通信协议的方式增加冗余信息来进行纠错或验证。比如利用循环冗余检验(CRC),哈希算法等附加字段帮助检测错误的发生,一旦发现异常则请求重发直至确认无误为止。 综上所述,针对双字节环境下的浮点数传输问题并没有完美的通用解答,具体实施取决于应用场景的具体需求技术条件允许范围内的折衷选择。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值