float、double计算中精度丢失的处理

本文探讨了Java中String转float不会丢失精度的特点,但float进行乘法运算时会出现精度损失的问题,并通过使用BigDecimal实现了高精度计算。

参考http://blog.youkuaiyun.com/luweicheng24/article/details/77800688

import java.math.BigDecimal;


public class T {
public static void main(String[] args) {
    String aaString="37.10";
    System.err.println(Double.valueOf(aaString));
    System.err.println(Float.valueOf(aaString));

    float amount =37.10f;
    float amount2 =amount*100;
    float amount4 =amount*100f;
    long amount3 =(long)amount2;

    System.err.println(amount);
    System.err.println(amount2);
    System.err.println(amount3);
    System.err.println(amount4);



//  
    BigDecimal bigDecimal1 = new BigDecimal(Float.toString(amount));
    System.err.println(bigDecimal1);
    BigDecimal bigDecimal2 = new BigDecimal(Float.toString(100));
    System.err.println(bigDecimal2);

    BigDecimal result = bigDecimal1.multiply(bigDecimal2);
    System.err.println(result);

    long longValue =result.longValue();

    System.err.println(longValue);


}
}

37.1
37.1
37.1
3709.9998
3709
3709.9998
37.1
100.0
3710.00
3710

1、String 转 float不会丢失精度;
2float乘法计算会丢失精度、
乘积总是在一个正确的结果左右偏0.0000**1,这是因为当两个float数值相乘时,底层采用转换成二进制来进行乘法的运算
3、采用BigDecimal 可以实现高精度运算
在C++中,将`float`类型换为`double`类型时可能会出现精度丢失问题,这是由于浮点数在计算机中的存储方式决定的。根据IEEE 754标准,浮点数是以二进制形式存储的,其中`float`类型通常占用32位,而`double`类型占用64位。尽管`double`类型的精度高于`float`,但在某些情况下,将`float`换为`double`时仍然会出现精度丢失的现象[^4]。 ### 精度丢失的原因 1. **浮点数的二进制表示**:浮点数在计算机中是以二进制形式存储的,这意味着某些十进制小数无法精确表示为二进制小数。例如,十进制的0.01在二进制中是一个无限循环小数,因此在`float`类型中只能近似表示为0.00999999978[^1]。 2. **有效数字的限制**:`float`类型的有效数字约为6-7位,而`double`类型的有效数字约为15-16位。当`float`类型的数值换为`double`类型时,虽然`double`可以存储更多的有效数字,但由于`float`本身已经丢失了部分精度,因此换后的结果仍然不准确[^2]。 3. **格式化输出的影响**:在将浮点数换为字符串时,如果使用的格式化字符串不够精确(例如,使用`%f`而不是`%.8lf`),也会导致精度丢失。对于`float`类型,使用`%.8lf`可以避免精度丢失;而对于`double`类型,使用`%.20lf`可以更好地保留精度[^2]。 ### 解决方案 1. **使用字符串换**:一种规避精度丢失的方法是将`float`类型换为字符串,然后再换为`double`类型。这种方法可以避免直接换时的精度损失,因为字符串可以保留更多的有效数字[^1]。 ```cpp #include <sstream> #include <string> float f = 0.01f; std::stringstream ss; ss << f; std::string str = ss.str(); double d = std::stod(str); ``` 2. **使用高精度库**:对于需要更高精度的应用,可以使用第三方库如Boost.Multiprecision。该库提供了`cpp_dec_float`类,可以支持任意精度的十进制浮点数运算,从而避免精度丢失问题[^3]。 ```cpp #include <boost/multiprecision/cpp_dec_float.hpp> using boost::multiprecision::number; using boost::multiprecision::cpp_dec_float; typedef number<cpp_dec_float<50>> cpp_dec_float_50; cpp_dec_float_50 v1("5726.867366095"); // 以字符串形式赋值,防止精度丢失 cpp_dec_float_50 v2("5837.754018494999"); const int64_t N = pow(10, 8); double newV1 = (int64_t)round(v1 * N) / double(N); double newV2 = (int64_t)round(v2 * N) / double(N); printf("%.8f\n", newV1); printf("%.8f\n", newV2); ``` 3. **格式化输出控制**:在进行浮点数到字符串的换时,合理选择格式化字符串可以减少精度丢失的可能性。对于`float`类型,建议使用`%.8lf`格式化字符串;对于`double`类型,建议使用`%.20lf`格式化字符串以保留更多有效数字。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值