Convert money between major and minor units correctly
The Currency Minor Unit Converter turns a human-readable amount like $19.99 into the integer 1999 that payment APIs expect, and back again. It uses the official ISO 4217 minor-unit exponent for each currency, so it stays correct for zero-decimal currencies like the Japanese yen and three-decimal currencies like the Bahraini dinar.
How it works
ISO 4217 assigns each currency an exponent — the number of decimal digits in its minor unit. The conversion is a simple power of ten:
minor = round(major × 10^exponent)
major = minor ÷ 10^exponent
- USD has exponent 2:
19.99 × 100 = 1999cents. - JPY has exponent 0:
2000 × 1 = 2000— major and minor are the same. - BHD has exponent 3:
1.999 × 1000 = 1999fils.
When converting major to minor, the tool rounds to the nearest integer. This matters because 19.99 * 100 in floating-point arithmetic can evaluate to 1998.9999999999998; naive truncation would give 1998 instead of the correct 1999.
Example
Sending a charge of 1.5 BHD to a payment processor requires 1500, not 150. Selecting BHD (exponent 3) and converting major to minor gives exactly that. Conversely, refunding 1500 minor BHD divides by 1000 to show 1.500 BHD.
The floating-point rounding problem
Payment APIs require integers because floating-point arithmetic is not exact. Consider 19.99 * 100 in JavaScript:
19.99 * 100
// → 1998.9999999999998
Naively truncating that gives 1998 — a one-cent undercharge. The correct approach is to multiply then round to the nearest integer, which is what this tool does. The issue becomes more pronounced with currencies that have three decimal places:
1.999 * 1000
// → 1998.9999999999998 (should be 1999 fils for BHD)
This is why payment APIs universally specify integers in minor units, and why it is safer to let a library or this tool handle the conversion rather than writing Math.floor(amount * 100).
Common mistakes and their symptoms
| Mistake | What the code does | What happens |
|---|---|---|
Hard-code ×100 for JPY | Charges ¥2000 as 200000 | 100× overcharge — the API may reject it or the customer is charged 100× more |
Hard-code ×100 for BHD | Charges 1.000 BHD as 100 not 1000 | 10× undercharge |
Use Math.floor not Math.round | 19.99 → 1998 | One minor unit undercharge per transaction |
| Store amount without currency | Amount 100 with no code | Cannot determine if it is USD ($1), JPY (¥100), or BHD (0.100) |
Notes
Always derive the multiplier from the ISO 4217 exponent rather than hard-coding ×100. A fixed multiplier silently fails for zero-decimal currencies (JPY, KRW, VND, UGX) and three-decimal currencies (BHD, KWD, JOD, OMR, TND), causing 100× overcharges or undercharges that are easy to miss in testing when you only test with USD and EUR amounts.