上次,提到“元转分”这个浮点数问题,boss倾向于手动把1.23元这种格式,转换成123分。 但实际上,浮点数很容易遇到精度问题。 比如,System.out.println(4.015 * 1000);结果就不会是4015。 以前,总结的元转分的问题,没能考虑到所有的场景,今天补充点上次遗漏的。 -5.09,如果金额是负数,应该是-500-9=-509,而不是-500+9=-441,这是上次的一个超级bug。 另外,需要还有一个超级bug,“1045189788”转换成double类型的元时,结果变成了1.04。 debug了好久,才发现以前代码的漏洞。 1045189788这种比较大的浮点数,在传递过程中,是“科学计数法”表示的,类似“1.04E”, 所以,最后转换出了问题。 其实,我一直不建议boss采用这种人工截取计算的方式,需要考虑的场景太复杂,建议使用JDK内置的BigDecimal。 经过实践,发现很不错。 可以用double、string等多种原始类型,构造BigDecimal,再进行四则运算。 使用BigDecimal的关键是,控制“标度”即“精度”,scale。 算术运算结果的首选标度 运算 结果的首选标度 加 max(addend.scale(), augend.scale()) 减 max(minuend.scale(), subtrahend.scale()) 乘 multiplier.scale() + multiplicand.scale() 除 dividend.scale() - divisor.scale() 下面这个工具类,是从网上copy的,还是非常有价值的。 import java.math.BigDecimal; /** * 消除加减乘除的精度,解决Float与Double类型进度不准确的问题. */ public class DoubleUtil { /** * 加法运算 * * @param v1 * @param v2 * @return */ public static double add(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2).doubleValue(); } /** * 减法运算 * * @param v1 * @param v2 * @return */ public static double sub(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.subtract(b2).doubleValue(); } /** * 乘法运算 * * @param v1 * @param v2 * @return */ public static double mul(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.multiply(b2).doubleValue(); } /** * 除法运算 * * @param v1 * 被除数 * @param v2 * 除数 * @return 商 */ public static double div(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.divide(b2).doubleValue(); } /** * 除法运算 * * @param v1 * 被除数 * @param v2 * 除数 * @return 商和余数 */ public static BigDecimal[] divideAndRemainder(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); BigDecimal[] arr = b1.divideAndRemainder(b2); return arr; } /** * 求商(向下舍入) * * @param v1 * @param v2 * @return */ public static BigDecimal divideToIntegralValue(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); System.out.println("------------"); return b1.divideToIntegralValue(b2); } public static void main(String[] args) { testUnPrecision(); System.out.println("----------使用BigDecimal消除精度影响------------\n" + DoubleUtil.add(0.05, 0.01)); System.out.println(DoubleUtil.sub(1.0, 0.54)); System.out.println(DoubleUtil.mul(4.015, 1000)); System.out.println(DoubleUtil.div(12.3, 10)); // 得到商和余数 BigDecimal[] arr = DoubleUtil.divideAndRemainder(12.3, 10); System.out.println("得到商和余数"); for (BigDecimal bigDecimal : arr) { System.out.println(bigDecimal); } System.out.println(DoubleUtil.divideToIntegralValue(4.5, 2)); } /** * 不准确问题示例 */ private static void testUnPrecision() { System.out.println("--------Java自身的Double类型有精度损失----------"); System.out.println(0.05 + 0.01); System.out.println(1.0 - 0.54); System.out.println(4.015 * 1000); System.out.println(12.3 / 100); } }
java+浮点数加减_Java中的浮点数-科学计数法-加减乘除
最新推荐文章于 2022-09-21 11:14:54 发布