金额的存储

本文探讨Java中浮点数运算存在的问题及其原因,并提出两种解决方案:利用BigDecimal类进行精确计算和通过转换整型避免误差。对于金融会计等需要高精度计算的场景,推荐使用BigDecimal。

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

存在的问题

public class Client{
 public static void main(String[] args){
   System.out.print(10.00-9.60);
     }
}

我们期望的结果为0.4,但是打印的结果却是0.40000000000000036

原因:机器运算时二进制运算,将0.4转为二进制,他是无限循环小数,可以这样理解在十进制世界里没有办法准确表示1/3,这样一来结果很容易出现偏差
尝试解决方案:

publi class client{
 public static void main(String[] args){
  NumberFormat f=new DecimalFormat("#.##");
  Syso(f.format(10.00-9.60));
  }
}

结果:0.4
看似解决了,但是隐藏了一个很深的问题,一般金融会计系统会记录小数点后四位,
但是在汇总,展现,报表中则只记录小数点的2位小数,如果使用浮点数来计算货币,
在大批量的加减乘除后结果会有很大的差距!会计系统要的就是准确,但是却因为计算机的缘故不准确了
真正解决方案:
1 使用BigDecimal
专门用来弥补浮点数无法精确计算的缺憾而设计的类,并且本身也提供了加减乘除的常用数据算法.
特别是与数据库Decimal类型的字段映射时,BigDecimal时最优的结解决方案
金额的运算(小数的精确计算)

BigDecimal b1 = new BigDecimal("0.03");
        BigDecimal b2 = new BigDecimal("0.04");
        // 加法
        System.out.println(b1.add(b2));
        // 减法
        System.out.println(b2.subtract(b1));
        // 乘法
        System.out.println(b2.multiply(b1));
        // 除法
        // 如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作。    
     System.out.println(b2.divide(b1, RoundingMode.HALF_UP));
 注:在这里HALF_UP是一种舍入模式
  BigDecimal和RoundingMode是一个绝配,想要采用什么舍入模式
  使用RoundingModel设置即可,目前java支持七种舍入方式:
   1 ROUND_UP:远离零方向舍入
     也就是说,想绝对值最大限额方向舍入,只要舍弃位非0即进位
   2 ROUND_DOWN:远离零方向舍入
     也就是说,想绝对值最小的方向输入,注意:所有的位都舍弃,不存在进位情况
   3 ROUND_CEILING:向正无穷方向舍入
     如果是正数,舍入行为类似ROUND_UP;
     如果是负数,舍入行为类似于ROUND_DOWN;
     注意:Math.round方法使用的即为此模式
   4 ROUND_FLOOR:向负无穷方向舍入.
     如果是正数,则舍入行为类似于ROUND_DOWN;
     如果为负数,则舍入行为 类似于ROUND_UP;
   5 HALF_UP:最近数字舍入(5进)  最经典的四舍五入
   6 HALF_EVEN:银行家算法
     规定:
     四舍六入五考虑,五后非零就进一,五后为0看奇偶,五前为偶应舍去,

五前为奇要进一
2 使用整型
把参数与运算的值扩大100倍,并转为整形,然后在展现时,再缩小100倍,
这样处理的好处是计算简单,准确,但只适用于一般在非金融行业应用较多如POS机

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值