小白日记[Mysql与Java精度损失]

小白一枚,请多指教

小白今日任务:解决精度损失BUG

1、Mysql中的精度损失

1)数据准备

CREATE TABLE `demo` (
  `f1` float(9,2) DEFAULT NULL,
  `f2` float(9,2) DEFAULT NULL,
  `d1` decimal(9,2) DEFAULT NULL,
  `d2` decimal(9,2) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into demo(f1,f2,d1,d2) values(1.31,1.21,1.31,1.21);

2)问题出现与解决

select truncate(f1-f2,2) as sub_f,truncate(d1-d2,2) as sub_d from demo;

+-------+-------+
| sub_f | sub_d |
+-------+-------+
|  0.09 | 0.1   |
+-------+-------+

用truncate保留一位小数时,float出现精度损失,float与double都属于浮点数,在比较或者插入时可能会精度损失,double取值范围比较大,可能会造成精度不会损失的假象,所以正式环境涉及到精度比较高的场景,尽量用decimal类型表示

2、Java中的精度损失

    @Test
    public void accuracyDemo() {
        // float
        float f  = 1.231f;
        System.out.println("float is " + f * 100);
        // 原生double类型
        double d  = 1.231d;
        System.out.println("double is " + d * 100);
        // 用double直接转换 BigDecimal
        BigDecimal d2BigDecimal =new BigDecimal(d);
        System.out.println("double format BigDecimal is " + d2BigDecimal);
        // 用String直接转换 BigDecimal
        BigDecimal b = new BigDecimal("1.231");
        System.out.println("String format BigDecimal is " + b.multiply(new BigDecimal("100")));
    }

打印结果:

float is 123.09999
double is 123.10000000000001
double format BigDecimal is 1.2310000000000000941469124882132746279239654541015625
String format BigDecimal is 123.100

从结果可以看到float与double都出现了精度损失,因为double本身精度损失,所以转换后的BigDecimal也同样出现了精度损失,最后推荐使用用字符串转换BigDecimal,可以得到比较准确的结果

附:Java BigDecimal常用保留小数策略

1)直接舍去不需要的位数

 BigDecimal keepPoint = new BigDecimal("1.236");
 System.out.println(keepPoint.setScale(2,BigDecimal.ROUND_DOWN));
-----
 1.23

2)四舍五入

 BigDecimal keepPoint = new BigDecimal("1.236");
 System.out.println(keepPoint.setScale(2,BigDecimal.ROUND_HALF_UP));
-----
 1.24

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值