刚学Java那会儿 我总被小数点坑得死去活来。明明算出来应该是3.5的结果 程序非要显示3.4999999999999996 这种鬼数字。最要命的是做金额计算的时候 老板说差了一分钱让我通宵查bug 你能想象这种崩溃吗?
当时我就想啊 Java不是号称精准吗?怎么连个简单的四舍五入都搞不定?后来才发现 原来处理小数点有这么多讲究。今天咱们就掰开了揉碎了说说 怎么在Java里驯服这些调皮的小数点。
先说最简单的场景——四舍五入到整数。这时候你可能会直接想到Math.round()方法。比如System.out.println(Math.round(3.4)); 输出3对吧?那3.5呢?System.out.println(Math.round(3.5)); 结果却是4。看起来挺正常的?
但这里藏着个坑:Math.round()处理的是float和double类型。如果你用3.5f和3.5d分别试试看 结果都是4。不过要注意 当数值刚好在两个整数中间时(比如3.5) 这个方法会向最近的偶数取整。比如Math.round(2.5)会得到2而不是3 这个特性很多人都会踩坑。
这时候你可能会想 四舍五入到整数好像不够用啊?咱们经常需要保留两位小数对吧?这时候就要请出BigDecimal了。这个类虽然用起来麻烦 但处理精度问题那是相当靠谱。比如说要把3.1415926四舍五入到两位小数 可以这么写:
BigDecimal num = new BigDecimal(“3.1415926”); num = num.setScale(2, RoundingMode.HALF_UP); System.out.println(num); // 输出3.14
等等 为什么要用字符串构造BigDecimal?这里有个重点:直接用double类型初始化BigDecimal会丢失精度。比如new BigDecimal(3.1415926) 实际存储的值可能已经有误差了 所以用字符串构造才是正确姿势。
不过每次都要new对象好麻烦啊 有没有更简单的办法?这时候DecimalFormat就派上用场了。比如:
DecimalFormat df = new DecimalFormat(“#.##”); System.out.println(df.format(3.1415926)); // 输出3.14
但这个方法返回的是String类型 如果你需要继续做数值运算 记得要转换回去。还有个隐藏的坑:DecimalFormat默认用的是当前系统语言环境的舍入规则 有些国家用的是逗号作为小数点 这时候可能出幺蛾子。
那什么时候该用哪种方法呢?咱们来做个对比: – Math.round():适合快速处理整数取整 但要注意奇进偶退的特性 – BigDecimal:金融计算必选 处理高精度需求的首选 – DecimalFormat:适合最终结果展示 但不要用于中间计算
看到这里你可能要问:为什么Java搞这么多种方法?直接给个统一的四舍五入函数不行吗?这就要说到计算机处理浮点数的本质问题了。因为二进制无法精确表示某些十进制小数(比如0.1) 所以必须用专门的方法来处理精度问题。
举个实际案例:超市收银系统要计算95折优惠。原价是19.9元 打95折应该是18.905元。如果用double直接计算: double price = 19.9 * 0.95; System.out.println(price); // 输出18.904999999999998
这时候如果用Math.round(price*100)/100.0 结果会变成18.9元 少算0.005元。而用BigDecimal处理: BigDecimal price = new BigDecimal(“19.9”) .multiply(new BigDecimal(“0.95”)) .setScale(2, RoundingMode.HALF_UP); // 正确得到18.91元
所以重点来了:涉及金钱计算必须用BigDecimal 其他方法都可能出现莫名其妙的误差。但日常简单计算用Math.round()就够用了 毕竟代码写起来方便。
最后说个冷知识:Java 8开始新增了Math.addExact()这种精确计算方法 但四舍五入还是得靠传统方法。现在你知道为什么很多Java面试题都爱考小数点处理了吧?这玩意儿看起来简单 实际操作处处是坑啊!
小编观点:别再用double算钱了!下次看到浮点数计算 先想想是不是该请BigDecimal出马。记住 你省下来的每一分代码量 都可能变成加班查bug的深夜时光。
本站文章由SEO技术博客撰稿人原创,作者:阿君创作,如若转载请注明原文及出处:https://www.ainiseo.com/hosting/18868.html