Why Float Is Dangerous for Money: Binary Pitfalls and Safer Alternatives
This article explains why using the float type for monetary values leads to precision loss due to binary representation, demonstrates the problem with a Java example, and recommends using integer cents, BigDecimal, or MySQL decimal to store amounts safely.
Why Float Is Dangerous for Money: Binary Pitfalls and Safer Alternatives
When building a trading system that handles money, developers may be tempted to store amounts in a float, but floating‑point arithmetic is approximate and can cause financial loss.
Illustrative Java Example
public class FloatTest {
public static void main(String[] args) {
float f1 = 6.6f;
float f2 = 1.3f;
System.out.println(f1 + f2);
}
}The program prints 7.8999996, which differs from the expected 7.9.
Binary Representation of 6.6 + 1.3
Computers operate on binary data. A 32‑bit float consists of a sign bit, an 8‑bit exponent, and a 23‑bit fraction (mantissa). Converting 6.6 and 0.6 to binary yields repeating fractions, so only the first 23 bits are kept, causing rounding errors.
Example conversion steps:
Integer part of 6 → 110 Fractional part of 0.6 → repeated binary 0.10011001… Combined, 6.6 becomes 110.10011001…. After normalisation (scientific notation in binary) it is 1.1010011001 × 2^2. The exponent bias for float is 127, so the stored exponent is 129 (10000001₂). The final 32‑bit pattern is 01000000110100110011001100110011.
Why Precision Is Lost
During storage the fraction is truncated to 23 bits, and the binary representation of many decimal fractions is infinite, so the stored value is only an approximation. The same issue exists for double, though with more bits.
Safer Storage Options
Instead of float, use one of the following:
Integer cents : store the amount in the smallest currency unit (e.g., cents) as an int or bigint in the database, and convert to dollars only for display.
Java BigDecimal : provides arbitrary‑precision decimal arithmetic. Example DAO and test code demonstrate adding two amounts retrieved as BigDecimal and printing the correct result 7.9.
MySQL DECIMAL(P,D) : defines precision P and scale D. Example table creation and Java MyBatis mapper show how DECIMAL maps to BigDecimal.
CREATE TABLE test_decimal (
id INT NOT NULL,
amount DECIMAL(10,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @Repository
public interface TestDecimalDao {
@Select("select * from test_decimal where id = #{id}")
TestDecimal getTestDecimal(int id);
} public class TestDecimalDaoTest extends BaseTest {
@Resource
private TestDecimalDao testDecimalDao;
@Test
public void test() {
TestDecimal a = testDecimalDao.getTestDecimal(1);
TestDecimal b = testDecimalDao.getTestDecimal(2);
BigDecimal result = a.getAmount().add(b.getAmount());
System.out.println(result.floatValue()); // prints 7.9
}
}Drawbacks of DECIMAL
Using DECIMAL consumes more storage space than floating‑point types and has lower computational performance. For many scenarios, storing integer cents is the most efficient, while BigDecimal offers precision when complex calculations are required.
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.
