Java 和 Oracle 中金额计算常用的方法和一些坑

目录

1. 基本的加减乘除

2. 除法除不尽可能报错

 3. 使用 ROUND_UP & ROUND_DOWN 小心有坑

4. 无条件进位的常用用法之 ROUND_CEILING

5. 无条件舍位的常用用法之 ROUND_FLOOR

6. 四舍五入之 ROUND_HALF_UP & ROUND_HALF_DOWN

7. 银行家算法

8. Oracle 中的常用函数


Java 中在处理金额相关的计算, 基本上都会使用 BigDecimal 类型。BigDecimal 解决了小数精度问题, 避免了浮点数运算产生的一些误差。 本文主要讲述 BigDecimal 一些常用的用法, 也增加了一些 Oracle 中对精度的处理, 供对比学习。

1. 基本的加减乘除


BigDecimal data1 = new BigDecimal("1");
BigDecimal data2 = new BigDecimal("2");
BigDecimal data3 = new BigDecimal("3");

System.out.println("1 + 2 = " + data1.add(data2));

System.out.println("1 - 2 =  " + data1.subtract(data2));

System.out.println("1 x 2 = " + data1.multiply(data2));

System.out.println("1 / 2 =  " + data1.divide(data2));

执行结果:

2. 除法除不尽可能报错


  • 解决方法: 养成做完运算指定保留小数位的好习惯;
// 避免除不尽, 需要指定保留小数位数
System.out.println("1 / 3 = " + data1.divide(data3, 6, BigDecimal.ROUND_CEILING) + " (无条件进位)");

System.out.println("1 / 3 = " + data1.divide(data3, 6, BigDecimal.ROUND_FLOOR) + " (无条件舍弃)");

执行结果

 3. 使用 ROUND_UP & ROUND_DOWN 小心有坑


  • ROUND_UP & ROUND_DOWN 在处理负数时, 要注意值的变化;
System.out.println("1.6 无条件舍弃结果 = " + new BigDecimal("1.6").setScale(0, BigDecimal.ROUND_DOWN));
        
System.out.println("1.11 无条件进位结果 = " + new BigDecimal("1.11").setScale(1, BigDecimal.ROUND_UP));
        
// 实际变大了, 可能误认为变小        
System.out.println("-1.6 无条件舍弃结果(小心有坑) = " + new BigDecimal("-1.6").setScale(0, BigDecimal.ROUND_DOWN));
        
// 实际变小了, 可能误认为变大
System.out.println("-1.11 无条件进位结果(小心有坑) = " + new BigDecimal("-1.11").setScale(1, BigDecimal.ROUND_UP));

执行结果

4. 无条件进位的常用用法之 ROUND_CEILING


// 向正无穷方向 round 如果为正数, 行为和 round_up 一样, 如果为负数, 行为和 round_down 相同        
// 变大了        
System.out.println("1.6 无条件进位结果(ROUND_CEILING) = " + new BigDecimal("1.6").setScale(0, BigDecimal.ROUND_CEILING));
        
// 变大了        
System.out.println("-1.6 无条件进位结果(ROUND_CEILING) = " + new BigDecimal("-1.6").setScale(0, BigDecimal.ROUND_CEILING));
        
// 变大了        
System.out.println("-1.11 无条件进位结果(ROUND_CEILING) = " + new BigDecimal("-1.11").setScale(1, BigDecimal.ROUND_CEILING));

执行结果

5. 无条件舍位的常用用法之 ROUND_FLOOR


// 向负无穷方向 round 如果为正数,行为和 round_down 一样,为负数,行为和 round_up 相同        
// 变小了
System.out.println("1.6 无条件舍弃结果(ROUND_FLOOR) = " + new BigDecimal("1.6").setScale(0, BigDecimal.ROUND_FLOOR));
        
// 变小了
System.out.println("-1.6 无条件舍弃结果(ROUND_FLOOR) = " + new BigDecimal("-1.6").setScale(0, BigDecimal.ROUND_FLOOR));
        
// 变小了
System.out.println("-1.11 无条件进位结果(ROUND_FLOOR) = " + new BigDecimal("-1.11").setScale(1, BigDecimal.ROUND_FLOOR));

执行结果

6. 四舍五入之 ROUND_HALF_UP & ROUND_HALF_DOWN


System.out.println("=========== ROUND_HALF_UP ===========");
        
// 四舍五入, 向最接近的数字舍入, 如果与两个相邻数字的距离相等, 则为向上舍入的舍入模式。        
System.out.println("1.5 四舍五入(向上)结果 = " + new BigDecimal("1.5").setScale(0, BigDecimal.ROUND_HALF_UP));
        
System.out.println("1.11 四舍五入(向上)结果 = " + new BigDecimal("1.11").setScale(1, BigDecimal.ROUND_HALF_UP));
        
System.out.println("=========== ROUND_HALF_DOWN ===========");
        
// 四舍五入, 向最接近的数字舍入, 如果与两个相邻数字的距离相等, 则为向下舍入的舍入模式。        
System.out.println("1.5 四舍五入(向下)结果 = " + new BigDecimal("1.5").setScale(0, BigDecimal.ROUND_HALF_DOWN));
        
System.out.println("1.51 四舍五入(向下)结果(小心有坑) = " + new BigDecimal("1.51").setScale(0, BigDecimal.ROUND_HALF_DOWN));
        
System.out.println("1.11 四舍五入(向下)结果 = " + new BigDecimal("1.11").setScale(1, BigDecimal.ROUND_HALF_DOWN));

执行结果

7. 银行家算法


System.out.println("1.62 银行家算法结果 = " + new BigDecimal("1.65").setScale(1, BigDecimal.ROUND_HALF_EVEN));
        
System.out.println("1.15 银行家算法结果 = " + new BigDecimal("1.15").setScale(1, BigDecimal.ROUND_HALF_EVEN));

执行结果

8. Oracle 中的常用函数


  • 注意 SQL 中处理数据时, 需要将 NULL 转换成 0, 避免出现计算错误。
-- 为 null 转换为 0
select nvl(null, 0) from dual;

-- 转换为绝对值
select abs(-1) from dual;

-- 强制进位, 只会变大
select ceil(-1.1), ceil(1.1) from dual;

-- 强舍, 只会变小
select floor(-1.1), floor(1.1) from dual;

-- 截断函数
select trunc(-1.23, 1), trunc(1.23, 1) from dual;

总结

  • 处理金额相关的计算,数据包含小数的使用 BigDecimal 类型;
  • 除法处理时指定保留小数位数, 避免除不尽时出现错误;
  • ROUND_UP & ROUND_DOWN 注意负数数值大小的变化;
  • ROUND_CEILING 和 ROUND_FLOOR 相对常用一些;
  • Oracle 其他语言环境也有类似的处理, 掌握核心思想一通百通。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值