Every NumberF function on one page. All examples are real output.
Installation
mix.exs
def deps do
[{:number_f, "~> 0.3.0"}]
endUsage
No configuration, no setup, no supervision tree
entry. Call everything off NumberF:
NumberF.currency(1234.5)
# => "ZMW 1,234.50"Currency & number formatting
Currency
NumberF.currency(1234.567)
# => "ZMW 1,234.57"
NumberF.currency(1234.567, "USD")
# => "USD 1,234.57"
NumberF.currency(1234.567, "USD", 0)
# => "USD 1,235"Delimiters
NumberF.comma_separated(1234567.89)
# => "1,234,567.89"
NumberF.number_to_delimited(1234567.89,
delimiter: ".", separator: ",")
# => "1.234.567,89"Abbreviation
NumberF.abbreviate_number(1_234_567)
# => "1.2M"
NumberF.abbreviate_number(1_234_567, 2)
# => "1.23M"
NumberF.abbreviate_number(1_500_000_000_000)
# => "1.5T"
NumberF.abbreviate_number(-5000)
# => "-5.0K"Percentages
NumberF.percentage(25, 200)
# => 12.5
NumberF.percentage(25, 200, 2)
# => 12.5Numbers to text
Words (currency style)
NumberF.to_words(42)
# => "Forty Two Kwacha"
NumberF.to_words(42.75, "Dollars", "Cents")
# => "Forty Two Dollars And Seventy Five Cents"Words (multilingual)
NumberF.spell_number(42, "en")
# => "Forty-two"
NumberF.spell_number(42, "fr")
# => "Quarante-deux"
# Fractions are read digit by digit, so a
# leading zero survives:
NumberF.spell_number(1.05, "en")
# => "One point zero five"NumberF.spelling_languages() => ["de", "en", "es", "fr"]. Any other language raises
ArgumentError rather than quietly returning
English.
Ordinals
NumberF.ordinal(1) # => "1st"
NumberF.ordinal(21) # => "21st"
NumberF.ordinal(112) # => "112th"Roman numerals
NumberF.to_roman(1999) # => "MCMXCIX"
NumberF.from_roman("MCMXCIX") # => 1999Internationalization
Locale-aware numbers
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"Locale-aware currency
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",
currency_code: "USD")
# => "1.234,56 $"Currency metadata
NumberF.get_currency("USD")
# => %{name: "US Dollar", symbol: "$", ...}
NumberF.currency_data()
# => %{"USD" => %{symbol: "$", ...}, ...}Explicit currency codes
NumberF.format_with_currency(1234.56, "JPY")
# => "¥1,235" (JPY has 0 decimal places)Financial calculations
Interest
NumberF.simple_interest(1000, 0.05, 2)
# => 100.0
NumberF.compound_interest(1000, 0.05, 2)
# => 102.5
# 12 compounding periods per year
NumberF.compound_interest(1000, 0.05, 2, 12)
# => 104.94Loan repayment
# principal, annual rate, months
NumberF.calculate_emi(100_000, 0.10, 12)
# => 8791.59Currency conversion
# amount, from_rate, to_rate
NumberF.convert_currency(100, 1.0, 0.85)
# => 85.0Decimal-safe sums
NumberF.sum_decimal([
Decimal.new("1.10"),
Decimal.new("2.20")
])
# => Decimal.new("3.30")Tax
VAT
NumberF.calculate_vat(100, 0.2)
# => %{net: 100.0, vat: 20.0, gross: 120.0}
# VAT-inclusive: extract tax from gross
NumberF.calculate_vat(120, 0.2, true)
# => %{net: 100.0, vat: 20.0, gross: 120.0}Sales tax
NumberF.calculate_sales_tax(100, 0.06)
# => %{subtotal: 100.0, tax: 6.0, total: 106.0}
NumberF.calculate_sales_tax(100, 0.0625, round_to: 0.05)
# => %{subtotal: 100.0, tax: 6.25, total: 106.25}Income tax (progressive)
brackets = NumberF.Tax.income_tax_brackets()["US"]
NumberF.Tax.calculate_income_tax(75_000, brackets)
# => %{tax: 12248.5, effective_rate: 0.1633}Other taxes
NumberF.Tax.calculate_capital_gains_tax(50_000, 0.15)
# => %{gain: 50000.0, taxable_gain: 50000.0,
# tax: 7500.0, net: 42500.0}
NumberF.Tax.calculate_corporate_tax(500_000, 0.21)
NumberF.Tax.calculate_withholding_tax(1000, 0.15)
NumberF.Tax.calculate_payroll_tax(60_000, 0.062, 0.0145)
NumberF.vat_rates() # VAT rate by country
NumberF.Tax.income_tax_brackets()
# => %{"US" => [...], "UK" => [...],
# "Germany" => [...], "Zambia" => [...]}Statistics
Central tendency
NumberF.mean([1, 2, 3, 4, 5]) # => 3.0
NumberF.median([1, 3, 5, 7, 9]) # => 5
NumberF.mode([1, 2, 2, 3, 3, 3]) # => [3]Spread
variance/1 and standard_deviation/1 are the
population forms (÷N). Use the sample_*
variants (÷N-1) when the list is a sample —
which is usually what you want.
NumberF.variance([1, 2, 3, 4, 5])
# => 2.0
NumberF.standard_deviation([2,4,4,4,5,5,7,9])
# => 2.0
NumberF.sample_variance([2,4,4,4,5,5,7,9])
# => 4.571428571428571
NumberF.sample_standard_deviation([2,4,4,4,5,5,7,9])
# => 2.138089935299395
NumberF.range([1, 5, 9]) # => 8.0Precision & rounding
Bankers rounding (round half to even)
NumberF.bankers_round(2.5, 0) # => 2.0
NumberF.bankers_round(3.5, 0) # => 4.0Use this for financial totals — it avoids the
upward bias of always rounding .5 away from zero.
Directional rounding
ceiling/2 and floor/2 take decimal places;
round_to/3 takes an increment.
NumberF.ceiling(2.111, 2) # => 2.12
NumberF.floor(2.999, 2) # => 2.99
NumberF.round_to(127, 5) # => 125.0
NumberF.round_to(2.567, 0.05) # => 2.55
NumberF.round_to(2.5, 1, :up) # => 3.0
NumberF.round_to_nearest(127, 5) # => 125.0Guards
NumberF.clamp(15, 0, 10) # => 10
NumberF.safe_divide(10, 0) # => 0.0
NumberF.safe_divide(10, 0, :none) # => :none
NumberF.sign(-4.2) # => -1Float comparison
NumberF.approximately_equal(0.1 + 0.2, 0.3)
# => true
NumberF.Precision.sanitize_float(:nan)Never compare floats with ==. Use
approximately_equal/3 with an explicit epsilon.
Precision helpers
NumberF.round_with_precision(3.14159, 2)
# => 3.14
NumberF.Precision.custom_round(2.565, 2, :half_down)
# => 2.56
NumberF.Precision.truncate(3.999, 2)
# => 3.99
NumberF.Precision.precise_format(3.14159, 3)
# => "3.142"Validation
Credit cards (Luhn)
NumberF.is_valid_credit_card?("4111111111111111")
# => true
NumberF.is_valid_credit_card?("4111-1111-1111-1111")
# => trueNumber formats
NumberF.is_valid_number?("1234.56") # => true
NumberF.is_valid_integer?("1234") # => true
NumberF.in_range?(5, 1, 10) # => trueUnit conversion
Temperature
NumberF.celsius_to_fahrenheit(25) # => 77.0
NumberF.fahrenheit_to_celsius(77) # => 25.0Length & distance
NumberF.km_to_miles(100)
NumberF.miles_to_km(62)
NumberF.cm_to_inches(30)
NumberF.inches_to_cm(12)Weight & volume
NumberF.kg_to_pounds(70)
NumberF.Metrics.pounds_to_kg(154)
NumberF.Metrics.ml_to_oz(500)
NumberF.Metrics.oz_to_ml(16)Generic conversion
Unit keys are strings, not atoms.
NumberF.Metrics.convert_units(100, "km", "mi",
NumberF.Metrics.length_units())
# => 62.137...Unit tables: length_units/0, weight_units/0,
volume_units/0, area_units/0.
Dates
Age & spans
NumberF.calculate_age(~D[1990-01-15])
NumberF.days_between(~D[2025-01-01], ~D[2025-12-31])Business days
NumberF.is_business_day?(~D[2025-06-14])
NumberF.business_days_between(
~D[2025-01-01], ~D[2025-01-31])Payment terms
NumberF.payment_due_date(~D[2025-01-01])
NumberF.payment_due_date(~D[2025-01-01], 60)Advanced statistics
Percentiles and spread
NumberF.percentile([1,2,3,4,5,6,7,8,9,10], 25)
# => 3.25
NumberF.quartiles([1,2,3,4,5,6,7,8])
# => %{q1: 2.75, q2: 4.5, q3: 6.25}
NumberF.iqr([1,2,3,4,5,6,7,8])
# => 3.5Relationships between two series
NumberF.correlation([1,2,3,4,5], [2,4,5,4,5])
# => 0.7745966692414833
NumberF.covariance([1,2,3,4,5], [2,4,5,4,5])
# => 1.2
NumberF.linear_regression([1,2,3,4,5], [2,4,5,4,5])
# => %{slope: 0.6, intercept: 2.2,
# r_squared: 0.5999999999999999}Other means
NumberF.weighted_mean([90,80,70], [0.5,0.3,0.2])
# => 83.0
# Growth rates: pass factors, not percentages
NumberF.geometric_mean([1, 4, 16])
# => 4.0
# Rates over a fixed distance
NumberF.harmonic_mean([40, 60])
# => 47.99999999999999 (48, modulo IEEE 754)Describing and reshaping
NumberF.summary([1,2,3,4,5])
# => %{count: 5, min: 1, q1: 2.0, median: 3,
# q3: 4.0, max: 5, mean: 3.0, stddev: 1.414...}
NumberF.z_scores([2, 4, 6])
# => [-1.2247448713915889, 0.0, 1.2247448713915889]
NumberF.normalize([10, 20, 30]) # => [0.0, 0.5, 1.0]
NumberF.moving_average([1,2,3,4,5], 3) # => [2.0, 3.0, 4.0]
NumberF.cumulative_sum([1,2,3,4]) # => [1, 3, 6, 10]
NumberF.outliers([1,2,3,4,1000]) # => [1000]
NumberF.trimmed_mean([1,2,3,4,100], 0.2) # => 3.0Investment and loans
Time value of money
NumberF.present_value(1000, 0.05, 10) # => 613.91
NumberF.future_value(1000, 0.05, 10) # => 1628.89
NumberF.npv(0.1, [-1000, 300, 400, 500, 600])
# => 388.77
NumberF.irr([-1000, 300, 400, 500, 600])
# => {:ok, 0.24888...}irr/2 returns {:error, :no_sign_change} when the
cash flows never cross zero — there is no rate that
zeroes an all-positive series.
Amortization
NumberF.amortization_schedule(100_000, 0.10, 12)
# => [%{period: 1, payment: 8791.59,
# principal: 7958.26, interest: 833.33,
# balance: 92041.74}, ...]The last period absorbs accumulated rounding, so the
balance closes at exactly 0.0.
Returns and break-even
NumberF.roi(1500, 1000) # => 50.0
NumberF.cagr(1000, 2000, 5) # => 14.87
NumberF.effective_annual_rate(0.12, 12) # => 0.1268
NumberF.break_even_point(10_000, 25, 15) # => 1000.0
NumberF.payback_period(1000, [300,400,500])
# => {:ok, 2.6}Annuities and depreciation
NumberF.annuity_payment(10_000, 0.05, 10) # => 1295.05
NumberF.annuity_present_value(100, 0.05, 10) # => 772.17
NumberF.annuity_future_value(100, 0.05, 10) # => 1257.79
NumberF.depreciation_straight_line(10_000, 1_000, 5)
# => 1800.0
NumberF.depreciation_declining_balance(10_000, 1_000, 5)
# => [%{year: 1, depreciation: 4000.0,
# book_value: 6000.0}, ...]Identifiers and checksums
Financial identifiers
NumberF.valid_iban?("GB82 WEST 1234 5698 7654 32")
# => true
NumberF.valid_routing_number?("021000021") # => true
NumberF.valid_currency_code?("USD") # => trueCards
NumberF.card_brand("4111111111111111") # => :visa
NumberF.card_brand("5500000000000004") # => :mastercard
NumberF.card_brand("378282246310005") # => :amex
NumberF.valid_luhn?("4111111111111111") # => true
NumberF.luhn_check_digit("411111111111111") # => 1card_brand/1 identifies the network from the prefix
and length. It does not validate — pair it with
is_valid_credit_card?/1.
Products and publications
NumberF.valid_isbn?("978-3-16-148410-0") # => true
NumberF.valid_isbn?("0-306-40615-2") # => true (ISBN-10)
NumberF.valid_ean?("4006381333931") # => true
NumberF.valid_upc?("036000291452") # => true
NumberF.valid_imei?("490154203237518") # => trueNumber theory and bases
Sequences and factors
NumberF.fibonacci(10) # => 55
NumberF.fibonacci_sequence(8) # => [0,1,1,2,3,5,8,13]
NumberF.permutations(5, 2) # => 20
NumberF.prime_factors(360) # => [2,2,2,3,3,5]
NumberF.divisors(28) # => [1,2,4,7,14,28]fibonacci/1 and combinations/2 return exact
integers at any size — fibonacci(100) is the true
value, not a float approximation.
Digits
NumberF.digits(12345) # => [1,2,3,4,5]
NumberF.digit_sum(12345) # => 15
NumberF.digital_root(12345) # => 6
NumberF.reverse_number(12345) # => 54321
NumberF.palindrome?(12321) # => true
NumberF.perfect_square?(144) # => trueRoots and logs
NumberF.nth_root(27, 3) # => 3.0
NumberF.log_base(1024, 2) # => 10.0Base conversion
NumberF.to_base(255, 16) # => "FF"
NumberF.from_base("FF", 16) # => 255
NumberF.to_hex(255) # => "FF"
NumberF.to_binary(5) # => "101"
NumberF.to_octal(8) # => "10"
NumberF.from_binary("101") # => 5Any base from 2 to 36.
Presentation
Accounting and signs
NumberF.accounting_format(-1234.56, unit: "$")
# => "($1,234.56)"
NumberF.with_sign(42) # => "+42"
NumberF.with_sign(-42) # => "-42"
NumberF.pad_number(42, 6, char: "0") # => "000042"
NumberF.pluralize(3, "person", "people")
# => "3 people"Sizes and durations
NumberF.format_bytes(1_500_000) # => "1.5 MB"
NumberF.format_bytes(1_048_576, base: :binary)
# => "1.0 MiB"
NumberF.format_duration(3725) # => "1h 2m 5s"
NumberF.format_duration(3725, format: :clock)
# => "01:02:05"
NumberF.format_duration(90, format: :long)
# => "1 minute, 30 seconds"Significant figures
NumberF.significant_figures(1234.5678, 3) # => 1230.0
NumberF.significant_figures(0.00012345, 3) # => 0.000123
NumberF.format_significant(1.5, 4) # => "1.500"Significant figures count from the first non-zero digit, so they are scale independent in a way that decimal places are not.
Calendar
Quarters and fiscal years
NumberF.quarter(~D[2024-08-22]) # => 3
NumberF.quarter_start(~D[2024-08-22]) # => ~D[2024-07-01]
NumberF.quarter_end(~D[2024-08-22]) # => ~D[2024-09-30]
# Named for the year the fiscal year ends in
NumberF.fiscal_year(~D[2024-08-22], 4) # => 2025Months and weeks
NumberF.month_start(~D[2024-08-22]) # => ~D[2024-08-01]
NumberF.month_end(~D[2024-02-10]) # => ~D[2024-02-29]
NumberF.days_in_month(2024, 2) # => 29
NumberF.leap_year?(1900) # => false
NumberF.week_number(~D[2024-08-22]) # => 34
NumberF.age_in_months(~D[2020-01-15], ~D[2024-08-22])
# => 55Conversion & utilities
Type coercion
NumberF.to_int("42") # => 42
NumberF.to_float("3.14") # => 3.14
NumberF.to_decimal("1.10")
NumberF.to_boolean("true") # => trueMemory sizes
NumberF.memory_size_cal(1_048_576)
# => "1.0 MB"
NumberF.memory_size_cal(5_000_000_000_000)
# => "4.55 TB"Phone numbers
NumberF.format_phone("260977123456", "ZM")
NumberF.format_phone("14155552671", "US")Random strings
NumberF.randomizer(8)
# => "RCKkn94U" (random; yours will differ)
NumberF.default_password()Math
NumberF.is_prime?(17) # => true
NumberF.factorial(5) # => 120
NumberF.gcd(12, 18) # => 6
NumberF.lcm(4, 6) # => 12
NumberF.combinations(5, 2) # => 10
NumberF.to_radians(180)
NumberF.to_degrees(3.14159)
NumberF.interpolate(0, 100, 0, 10, 5)Introspection
NumberF.modules() # all NumberF modules
NumberF.modules_by_type(:formatting)
NumberF.function_categories() # list of category maps
NumberF.documentation() # generated reference