Why Does 2.01 Turn Into 2.00 in Java? Fix Money Precision with BigDecimal
This article explains why using double for monetary values in Java can cause rounding errors such as 2.01 becoming 2.00, demonstrates the binary precision problem with sample code, and provides a robust BigDecimal‑based solution with performance testing.
During testing a bug was discovered where an order price of 2.01 was displayed as 2.00, raising suspicion about double precision.
In Java, decimal numbers like 2.01 are stored in binary two's‑complement form, which cannot represent them exactly; the binary representation truncates, leading to loss of precision (e.g., 000000010.009999999999999787).
A loop that converts int money to a string with String.format("%.2f", money * 1.0 / 100) and then back to int using Double.valueOf(...)*100 shows mismatches; 573 out of 10,000 values lose precision.
for (int money = 0; money < 10000; money++) {
String valueYuan = String.format("%.2f", money * 1.0 / 100);
int value = (int) (Double.valueOf(valueYuan) * 100);
if (value != money) {
System.out.println(String.format("原值: %s, 现值:%s", money, value));
}
}To avoid this, Java’s BigDecimal should be used. The following utility methods safely convert between yuan (as String) and fen (as int).
public static String change2Yuan(int money) {
BigDecimal base = BigDecimal.valueOf(money);
BigDecimal yuanBase = base.divide(new BigDecimal(100));
return yuanBase.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
public static int change2Fen(String money) {
BigDecimal base = new BigDecimal(money);
BigDecimal fenBase = base.multiply(new BigDecimal(100));
return fenBase.setScale(0, BigDecimal.ROUND_HALF_UP).intValue();
}Extensive testing from 0 to 100 000 000 shows zero conversion errors, and a performance test indicates the BigDecimal approach adds only about 2 ms overhead for the whole range.
int error = 0;
long time = System.currentTimeMillis();
for (int money = 0; money < 100000000; money++) {
String valueYuan = change2Yuan(money);
int value = change2Fen(valueYuan);
if (value != money) {
error++;
}
}
System.out.println(String.format("时间:%s", (System.currentTimeMillis() - time)));
System.out.println(error);In summary, any code that converts monetary amounts using double should be reviewed and replaced with a dedicated utility based on BigDecimal to prevent precision loss.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
