问题说明
业务背景:
下单的时候校验商品金额、使用抵扣比例是否与抵扣金额是否相等的业务。
开发同学给出一个简单的方法:
/**
* 校验金额、抵扣比例、折扣比例是否相等
*
* @param amount 金额(分)
* @param ratio 抵扣比例(比例*100)
* @param deductFee 抵扣比例
* @return 是否相等
*/
private static boolean division(long amount, float ratio, long deductFee) {
if (ratio <= 0) return false;
return amount / ratio == deductFee;
}
看看这个方法有什么问题吗?乍一看,方法没什么问题。
测试结果:
public static void main(String[] args) {
System.out.println(division(49969950,50.0f,999399));
}
输出:
false
我们想要的结果是49969950是50的整数倍,相除的话,正好是999399,但是实际上运行的结果确是false,与预期结果不一致。
来看下实际运行效果
public static void main(String[] args) {
System.out.println(49969950/50.0f);
System.out.println((float)49969950);
}
输出结果为:
999399.06
4.9969952E7
我们发现数值变了,实际上49969950/50.0f 得到的结果是999399.06
实际上想得到的结果是49969950除以50,是一个整数,但是经过运算得出的却是个小数。
但是这个方法不是一定是失败的,例如:
public static void main(String[] args) {
System.out.println(division(100L,10.0f,10));
}
输出结果:
true
所以类似于这样的数值,运算结果是符合之前的预期的,这样就导致如果真正在下单业务中运用,如果商品价格、抵扣比例正好是这样的数值的话,结果完全是正确的。如果测试不充分的话,上线就是故障。
解决方案之一就是采用BigDecimal做精度运算,但是也有坑,后续分析。
针对以上问题,我抛出了几个疑问:
== 1.49969950转float的时候为什么会变成4.9969952E7?多个2出来。 ==
== 2.long型为什么可以转float? ==
== 3.long型转float为什么值会变? ==
== 4.float精度比较问题 ==
搞明白这几个问题,需要重新回顾一下java基本类型的基础知识。真正的搞明白这里面的原理。
未完待续~