Packages
Number formatting, currency and financial math for Elixir. Format currency and numbers for 22 locales, convert numbers to words and Roman numerals, calculate compound interest, EMI, VAT and income tax, run statistics, validate credit cards, and convert units. One zero-config dependency.
Current section
Files
Jump to
Current section
Files
README.md
<p align="center">
<img src="https://raw.githubusercontent.com/jamesnjovu/elixir_number_functions/master/priv/static/images/logo.svg" alt="NumberF logo" width="120" height="120">
</p>
<h1 align="center">NumberF</h1>
<p align="center">
<strong>Number formatting, currency, and financial math for Elixir.</strong><br>
One zero-config dependency for the numeric work every app ends up rewriting.
</p>
<p align="center">
<a href="https://hex.pm/packages/number_f"><img src="https://img.shields.io/hexpm/v/number_f.svg?style=flat-square" alt="Hex.pm version"></a>
<a href="https://hexdocs.pm/number_f"><img src="https://img.shields.io/badge/hex-docs-informational.svg?style=flat-square" alt="HexDocs"></a>
<a href="https://hex.pm/packages/number_f"><img src="https://img.shields.io/hexpm/dt/number_f.svg?style=flat-square" alt="Total downloads"></a>
<a href="https://github.com/jamesnjovu/elixir_number_functions/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/jamesnjovu/elixir_number_functions/ci.yml?branch=master&style=flat-square" alt="CI status"></a>
<a href="https://github.com/jamesnjovu/elixir_number_functions/blob/master/LICENSE"><img src="https://img.shields.io/hexpm/l/number_f.svg?style=flat-square" alt="MIT license"></a>
</p>
---
NumberF is an Elixir library that handles the numeric chores that show up in almost
every real application: formatting money, printing amounts in words on an invoice,
working out loan repayments, applying VAT, and displaying numbers the way a user's
locale expects them.
It has one runtime dependency (`decimal`), needs no configuration, and every function
is callable directly off the top-level `NumberF` module.
```elixir
NumberF.currency(1234.567, "USD") # => "USD 1,234.57"
NumberF.to_words(42.75, "Dollars", "Cents") # => "Forty Two Dollars And Seventy Five Cents"
NumberF.format_currency(1234.56, "fr-FR") # => "1 234,56 €"
NumberF.calculate_emi(100_000, 0.10, 12) # => 8791.59
NumberF.calculate_vat(100, 0.2) # => %{net: 100.0, vat: 20.0, gross: 120.0}
NumberF.standard_deviation([2, 4, 4, 4, 5, 5, 7, 9]) # => 2.0
```
## Installation
Add `number_f` to your dependencies in `mix.exs`:
```elixir
def deps do
[
{:number_f, "~> 0.3.0"}
]
end
```
Then fetch it:
```bash
mix deps.get
```
Requires Elixir 1.14 or later. No application configuration is needed.
## What it does
| Area | Functions | Example |
|---|---|---|
| **Currency formatting** | `currency/3`, `comma_separated/2`, `number_to_delimited/2` | `NumberF.currency(1234.5)` → `"ZMW 1,234.50"` |
| **Numbers to words** | `to_words/3`, `spell_number/2` (en/fr/es/de), `ordinal/1`, Roman numerals | `NumberF.to_roman(1999)` → `"MCMXCIX"` |
| **Financial math** | interest, `amortization_schedule/3`, `npv/2`, `irr/2`, `present_value/3`, `cagr/3`, annuities, depreciation, `payback_period/2` | `NumberF.npv(0.1, flows)` → `388.77` |
| **Tax** | `calculate_vat/3`, `calculate_sales_tax/3`, `NumberF.Tax.calculate_income_tax/2` | `NumberF.calculate_vat(100, 0.2)` |
| **Statistics** | mean/median/mode, population **and** sample variance, `percentile/2`, `quartiles/1`, `correlation/2`, `linear_regression/2`, `summary/1`, `outliers/2` | `NumberF.percentile(data, 25)` → `3.25` |
| **Internationalization** | `format_number/2`, `format_currency/3` across 22 locales | `NumberF.format_number(1234567.89, "de-DE")` |
| **Unit conversion** | metric ↔ imperial, temperature, arbitrary unit tables | `NumberF.celsius_to_fahrenheit(25)` → `77.0` |
| **Validation** | IBAN, ISBN, EAN/UPC, IMEI, ABA routing, Luhn + `card_brand/1` | `NumberF.valid_iban?("GB82 WEST…")` → `true` |
| **Precision** | `clamp/3`, `safe_divide/3`, bankers rounding, half-away-from-zero, float comparison | `NumberF.clamp(15, 0, 10)` → `10` |
| **Dates** | age, business days (forward and back), quarters, fiscal years, ISO weeks | `NumberF.quarter(~D[2024-08-22])` → `3` |
| **Humanizing** | `format_bytes/2` (SI and binary), `format_duration/2`, `pluralize/3`, `accounting_format/2`, phone numbers | `NumberF.format_duration(3725)` → `"1h 2m 5s"` |
Plus number theory and base conversion: `fibonacci/1`, `prime_factors/1`, `divisors/1`,
`digital_root/1`, `to_base/2` and `from_base/2` for any base from 2 to 36.
**260+ functions, all reachable from the single `NumberF` module**, grouped in the docs
by area. Full API reference: **[hexdocs.pm/number_f](https://hexdocs.pm/number_f)**
## Common tasks
<details>
<summary><strong>How do I format a number as currency in Elixir?</strong></summary>
```elixir
NumberF.currency(1234.567) # => "ZMW 1,234.57" (default unit)
NumberF.currency(1234.567, "USD") # => "USD 1,234.57"
NumberF.currency(1234.567, "USD", 0) # => "USD 1,235"
# Locale-aware, with the correct symbol and placement:
NumberF.format_currency(1234.56, "en-US") # => "$1,234.56"
NumberF.format_currency(1234.56, "fr-FR") # => "1 234,56 €"
NumberF.format_currency(1234.56, "de-DE") # => "1.234,56 €"
```
See the [Currency Formatting guide](https://hexdocs.pm/number_f/currency-formatting.html).
</details>
<details>
<summary><strong>How do I convert a number to words for an invoice or cheque?</strong></summary>
```elixir
NumberF.to_words(42) # => "Forty Two Kwacha"
NumberF.to_words(42.75, "Dollars", "Cents") # => "Forty Two Dollars And Seventy Five Cents"
NumberF.spell_number(42, "fr") # => "Quarante-deux"
```
</details>
<details>
<summary><strong>How do I calculate a loan repayment (EMI) or compound interest?</strong></summary>
```elixir
NumberF.simple_interest(1000, 0.05, 2) # => 100.0
NumberF.compound_interest(1000, 0.05, 2) # => 102.5
NumberF.compound_interest(1000, 0.05, 2, 12) # => 104.94 (monthly compounding)
NumberF.calculate_emi(100_000, 0.10, 12) # => 8791.59 (principal, annual rate, months)
```
See the [Financial Calculations guide](https://hexdocs.pm/number_f/financial-calculations.html).
</details>
<details>
<summary><strong>How do I add or remove VAT / sales tax?</strong></summary>
```elixir
NumberF.calculate_vat(100, 0.2) # => %{net: 100.0, vat: 20.0, gross: 120.0}
NumberF.calculate_vat(120, 0.2, true) # VAT-inclusive: extracts the tax from the gross
NumberF.Tax.calculate_income_tax(75_000, brackets)
# => %{tax: 12248.5, effective_rate: 0.1633} (progressive brackets)
```
</details>
<details>
<summary><strong>How do I format numbers for a different locale?</strong></summary>
```elixir
NumberF.format_number(1234567.89, "en-US") # => "1,234,567.89"
NumberF.format_number(1234567.89, "fr-FR") # => "1 234 567,89"
NumberF.format_number(1234567.89, "de-DE") # => "1.234.567,89"
```
See the [Internationalization guide](https://hexdocs.pm/number_f/internationalization.html).
</details>
## How it compares
NumberF is a **breadth-first utility belt**, not a specialist library. Reach for it when
you want one small dependency covering many numeric needs; reach elsewhere when you need
depth in a single area:
- **[ex_cldr](https://hex.pm/packages/ex_cldr)** — full Unicode CLDR data, the right choice
when locale correctness across hundreds of locales is a hard requirement.
- **[money](https://hex.pm/packages/money) / [ex_money](https://hex.pm/packages/ex_money)** —
a dedicated `Money` type with currency-safe arithmetic. Use these if money is a first-class
domain type in your system.
- **[number](https://hex.pm/packages/number)** — a focused port of Rails' number helpers.
NumberF overlaps with all three at the edges, but bundles formatting, finance, tax,
statistics, validation, and unit conversion behind a single flat API.
## Documentation
- [Getting Started](https://hexdocs.pm/number_f/getting-started.html)
- [Cheatsheet](https://hexdocs.pm/number_f/cheatsheet.html) — every function on one page
- [Currency Formatting](https://hexdocs.pm/number_f/currency-formatting.html)
- [Financial Calculations](https://hexdocs.pm/number_f/financial-calculations.html)
- [Internationalization](https://hexdocs.pm/number_f/internationalization.html)
- [FAQ](https://hexdocs.pm/number_f/faq.html)
- [Changelog](https://github.com/jamesnjovu/elixir_number_functions/blob/master/CHANGELOG.md)
### For AI assistants and LLM tooling
The documentation is published in an LLM-readable form at
[`hexdocs.pm/number_f/llms.txt`](https://hexdocs.pm/number_f/llms.txt), following the
[llms.txt convention](https://llmstxt.org). Point Claude, ChatGPT, Cursor, or any
retrieval tool at that URL for a complete, plain-text API reference. A condensed
[`llms.txt`](https://github.com/jamesnjovu/elixir_number_functions/blob/master/llms.txt)
also lives at the root of this repository.
## Contributing
Issues and pull requests are welcome. See [CONTRIBUTING.md](https://github.com/jamesnjovu/elixir_number_functions/blob/master/CONTRIBUTING.md) for
the development workflow, and [SECURITY.md](https://github.com/jamesnjovu/elixir_number_functions/blob/master/SECURITY.md)
for reporting vulnerabilities.
```bash
git clone https://github.com/jamesnjovu/elixir_number_functions.git
cd elixir_number_functions
mix deps.get
mix test
```
## License
Released under the [MIT License](https://github.com/jamesnjovu/elixir_number_functions/blob/master/LICENSE). Copyright © 2024-2026 James Njovu.