Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

Money in Java: Precision, Rounding, and Reality

Posted on November 5, 2015 By Luis Fernandez

Money looks simple until a single cent sneaks away and your numbers do not match the bank. Java gives you many ways to represent it, some friendly, some dangerous.

Let us talk about precision, rounding, and reality so your totals land exactly where your accountant expects.

Precision beats convenience

Floating point feels easy. It is also how people end up with a receipt that says 19.999999. Binary floats cannot exactly represent values like 0.1 or 0.01, and money lives on those values all day. The fix is boring and proven. Use BigDecimal with the string constructor and set your scale on purpose. That keeps every cent exact across math, storage, and JSON.

Store amounts as minor units when you can cents for USD, pennies for GBP and only turn them into pretty strings at the edge. If you do store decimals, lock scale and rounding early and enforce it with tests. This avoids the haunted bug where a later operation changes the number of fraction digits and breaks comparisons.

// Bad: binary float math
double subtotal = 0.1 + 0.2;           // 0.30000000000000004
System.out.println(subtotal);

// Good: exact math with BigDecimal
BigDecimal a = new BigDecimal("0.10");
BigDecimal b = new BigDecimal("0.20");
BigDecimal total = a.add(b);           // 0.30 exactly

// Always set scale and rounding for money
BigDecimal money = total.setScale(2, RoundingMode.HALF_EVEN);

Rounding is a product choice

Rounding is not a math problem. It is a business rule. Accounting tools expect bankers rounding which in Java is RoundingMode.HALF_EVEN. Point of sale might round cash to five cents. Some tax codes require rounding at the line, others at the invoice. The rule you pick changes totals, so write it down and test for it.

Also, not every currency uses two decimals. JPY has zero fraction digits. Some currencies change rules when inflation hits. Use java.util.Currency to get default fraction digits, then lock your scale to that or to a product rule you own. Mix that with clear naming so no one adds a three decimal crypto amount to a two decimal receipt.

// Currency aware rounding
Currency usd = Currency.getInstance("USD");
int scale = usd.getDefaultFractionDigits(); // usually 2

BigDecimal price = new BigDecimal("19.995");
BigDecimal rounded = price.setScale(scale, RoundingMode.HALF_EVEN); // 20.00

// Tax per line vs tax on subtotal
BigDecimal rate = new BigDecimal("0.0875"); // 8.75 percent
BigDecimal line = new BigDecimal("12.49");

BigDecimal taxPerLine = line.multiply(rate)
    .setScale(scale, RoundingMode.HALF_EVEN); // round here

BigDecimal subtotal = line.multiply(new BigDecimal("3"));
BigDecimal taxOnSubtotal = subtotal.multiply(rate)
    .setScale(scale, RoundingMode.HALF_EVEN); // or round here

// These can differ by a cent. Pick one rule and stick to it.

Java Money moves the pieces into place

There is fresh work in this area with JSR 354 also called Java Money and Currency. It brings types for amounts and currencies, conversion providers, and sane operators for rounding and formatting. The reference implementation is called Moneta, and it is easy to drop into a Java 8 project. If your stack is not ready for it, wrap BigDecimal behind your own Money type with the same ideas names and rules stay readable and safe.

The goal is not clever code. The goal is repeatable numbers across services and days. That means a single place for rounding modes, currency scale, and conversion rules. If you are doing exchange rates, lock a provider and a timestamp so totals match a given day. Put that into tests with a few real receipts and a synthetic case full of fives and halves to catch midpoint ties.

// Example with JSR 354 Moneta
import javax.money.*;
import org.javamoney.moneta.Money;
import org.javamoney.moneta.function.MonetaryOperators;

CurrencyUnit usd = Monetary.getCurrency("USD");
MonetaryAmount unit = Money.of(19.995, usd);

// Bankers rounding to currency scale
MonetaryAmount rounded = unit.with(MonetaryOperators.rounding());

// Add and multiply are exact on amount types
MonetaryAmount subtotal = rounded.multiply(3);
MonetaryAmount tax = subtotal.multiply(0.0875).with(MonetaryOperators.rounding());

MonetaryAmount total = subtotal.add(tax);

// Optional conversion
// ExchangeRateProvider provider = MonetaryConversions.getExchangeRateProvider("ECB");
// MonetaryAmount eurTotal = total.with(MonetaryConversions.getConversion("EUR"));

Treat money as a first class type and the cents will stay where you put them.

Software Architecture Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes