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.

Java Backend Technology
Java Backend Technology
Java Backend Technology
Why Does 2.01 Turn Into 2.00 in Java? Fix Money Precision with BigDecimal

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).

Binary representation of 2.01
Binary representation of 2.01

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);
Performance test result
Performance test result

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

BigDecimalfloating-pointmoney conversion
Java Backend Technology
Written by

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!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.