float、double除法计算小数精确度问题

ava中的float和double类型在表示小数时存在精度问题,因为它们是基于二进制浮点数的IEEE 754标准实现的。BigDecimal类可以解决这个问题,它提供了精确的小数运算能力。

从float/double创建BigDecimal

避免直接使用float或double的构造方法,因为这会传递不精确的值。推荐使用字符串构造方法:

float f = 0.1f;
double d = 0.1;

// 不推荐:可能引入不精确的值
BigDecimal bd1 = new BigDecimal(f); 
BigDecimal bd2 = new BigDecimal(d);

// 推荐:使用字符串构造
BigDecimal bd3 = new BigDecimal("0.1");
BigDecimal bd4 = new BigDecimal(Float.toString(f));
BigDecimal bd5 = new BigDecimal(Double.toString(d));
 

设置精度和舍入模式

BigDecimal的运算需要指定舍入模式,常见的模式包括:

  1. RoundingMode.UP(进位):不管保留数字后面是大是小(0除外)都会进1。结果会向原点的反方向对齐,正数向正无穷方向对齐,负数向负无穷方向对齐。
  2. RoundingMode.DOWN(舍去):将要丢掉的数字直接丢掉。结果会向原点的反方向对齐,正数向正无穷方向对齐,负数向负无穷方向对齐。
  3. RoundingMode.CEILING(天花板):向上取整,即不管保留数字后面是大是小(0除外)都会进1,正数不变化,负数向正无穷方向对齐。
  4. RoundingMode.FLOOR(地板):向下取整,即将要丢掉的数字直接丢掉,正数向负无穷方向对齐,负数不变化。
  5. RoundingMode.HALF_UP(四舍五入):四舍五入,保留数字后面第一位是非零即进1。
  6. RoundingMode.HALF_DOWN(半舍半入):保留数字后面第一位是非零即进1,如果第二位是5则进1。
  7. RoundingMode.HALF_EVEN(银行家舍入):四舍六入五留双,保留数字后面第一位是非零即进1,如果第二位是5则看第一位,是偶数则进1,否则舍去。
  8. RoundingMode.UNNECESSARY(必要):如果舍入后的结果不是原数则抛出异常。

以上就是BigDecimal中的八种RoundingMode,每种模式都有其特定的行为和用途。在使用BigDecimal进行高精度计算时,可以根据需要选择合适的舍入模式来保证计算的准确性和精度。

BigDecimal a = new BigDecimal("1.2345");
BigDecimal b = new BigDecimal("3.1415");

// 加法
BigDecimal sum = a.add(b);

// 减法
BigDecimal difference = a.subtract(b);

// 乘法
BigDecimal product = a.multiply(b);

// 除法,指定精度和舍入模式
BigDecimal quotient = a.divide(b, 4, RoundingMode.HALF_UP);
 

示例:百分数数字转换

将99.99%转换成小数0.9999,再将0.9999转换成99.99

        double p = 99.99;
        BigDecimal bP = new BigDecimal(String.valueOf(p));
        BigDecimal b100 = new BigDecimal(String.valueOf(100));
        BigDecimal bigDiv = bP.divide(b100);
        double d = bigDiv.doubleValue();
        System.out.println(bigDiv);//0.9999
        System.out.println(d);//0.9999

        BigDecimal dP = new BigDecimal(String.valueOf(d));

        BigDecimal s = dP.multiply(b100);
        double ss = s.doubleValue();
        System.out.println(s);//99.9900
        System.out.println(ss);//99.99

比较BigDecimal值

避免使用equals()方法,因为它会比较精度和值。使用compareTo()方法进行值比较:

BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("1.00");

// 不推荐:false,因为精度不同
boolean eq = x.equals(y);

// 推荐:0,表示值相等
int cmp = x.compareTo(y);
 

格式化BigDecimal输出

使用DecimalFormat可以控制BigDecimal的输出格式:

BigDecimal value = new BigDecimal("1234.5678");
DecimalFormat df = new DecimalFormat("#,##0.00");
String formatted = df.format(value);  // 输出:1,234.57
 

注意事项

  • BigDecimal是不可变对象,每次运算都会产生新对象
  • 对于金融计算等需要精确小数的场景,优先使用BigDecimal
  • 构造BigDecimal时尽量使用字符串而非float/double字面量
  • 运算时明确指定舍入模式,避免出现ArithmeticException
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值