Toolmingo
Guides8 min read

Number to Words: How to Convert Any Number to English Text

Learn how to convert numbers to words in English — the algorithm behind place values, groups of three, and special cases from 11–19. Code examples in JavaScript, Python, Go, and PHP.

Number to Words: How to Convert Any Number to English Text

Writing a cheque, generating an invoice, or building a voice assistant — all of them need to spell out numbers in plain English. "1,042" becomes "one thousand forty-two". The conversion looks trivial until you hit the teens (11–19 break the pattern), the hundreds, the millions, and then zero. This guide explains the algorithm from scratch and shows working code in four languages.


Why Number-to-Words Is Trickier Than It Looks

English number names are almost regular — almost:

Range Pattern breaks down?
1–9 Regular (one, two, …, nine)
10 Special ("ten", not "onety")
11–19 All irregular (eleven, twelve, thirteen … nineteen)
20–99 Regular again (twenty-one, thirty-five…)
100–999 Regular with "hundred"
1,000+ Group of three digits repeating with scale words (thousand, million, billion…)

The irregularity of 10–19 is the only real exception to handle.


The Algorithm

Every number can be broken into groups of three digits from right to left:

1,042,007,305
= 1 · billion  +  042 · million  +  007 · thousand  +  305

Each group of three is converted independently, then a scale word (thousand, million, billion, trillion…) is appended.

Step 1 — Words for 1–19

ones = ["", "one", "two", "three", "four", "five", "six",
        "seven", "eight", "nine", "ten", "eleven", "twelve",
        "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
        "eighteen", "nineteen"]

Step 2 — Tens words (20, 30, … 90)

tens = ["", "", "twenty", "thirty", "forty", "fifty",
        "sixty", "seventy", "eighty", "ninety"]

Step 3 — Convert a three-digit group

function threeDigits(n):
  if n == 0: return ""
  if n < 20:  return ones[n]
  if n < 100: return tens[n/10] + (ones[n%10] ? "-" + ones[n%10] : "")
  return ones[n/100] + " hundred" + (n%100 ? " " + threeDigits(n%100) : "")

Step 4 — Assemble with scale words

scales = ["", "thousand", "million", "billion", "trillion"]

function numberToWords(n):
  if n == 0: return "zero"
  if n < 0:  return "negative " + numberToWords(-n)

  parts = []
  i = 0
  while n > 0:
    group = n % 1000
    if group != 0:
      chunk = threeDigits(group)
      if scales[i]: chunk += " " + scales[i]
      parts.prepend(chunk)
    n = n / 1000
    i++

  return parts.join(" ")

Example trace for 1,042:

group 0 (42):  "forty-two"  + "" → "forty-two"
group 1 (1):   "one"        + "thousand" → "one thousand"
result: "one thousand forty-two"

Code Examples

JavaScript

const ones = [
  '', 'one', 'two', 'three', 'four', 'five', 'six',
  'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve',
  'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen',
  'eighteen', 'nineteen',
];
const tens = [
  '', '', 'twenty', 'thirty', 'forty', 'fifty',
  'sixty', 'seventy', 'eighty', 'ninety',
];
const scales = ['', 'thousand', 'million', 'billion', 'trillion'];

function threeDigits(n) {
  if (n === 0) return '';
  if (n < 20) return ones[n];
  if (n < 100) {
    const t = tens[Math.floor(n / 10)];
    const o = ones[n % 10];
    return o ? `${t}-${o}` : t;
  }
  const h = ones[Math.floor(n / 100)];
  const rem = n % 100;
  return rem ? `${h} hundred ${threeDigits(rem)}` : `${h} hundred`;
}

function numberToWords(n) {
  if (!Number.isInteger(n)) throw new Error('Integer required');
  if (n === 0) return 'zero';
  if (n < 0) return 'negative ' + numberToWords(-n);

  const parts = [];
  let i = 0;
  while (n > 0) {
    const group = n % 1000;
    if (group !== 0) {
      const chunk = threeDigits(group);
      parts.unshift(scales[i] ? `${chunk} ${scales[i]}` : chunk);
    }
    n = Math.floor(n / 1000);
    i++;
  }
  return parts.join(' ');
}

console.log(numberToWords(0));           // zero
console.log(numberToWords(42));          // forty-two
console.log(numberToWords(1042));        // one thousand forty-two
console.log(numberToWords(1000000));     // one million
console.log(numberToWords(-7));          // negative seven
console.log(numberToWords(1000000000)); // one billion

Python

ones = [
    '', 'one', 'two', 'three', 'four', 'five', 'six',
    'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve',
    'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen',
    'eighteen', 'nineteen',
]
tens = [
    '', '', 'twenty', 'thirty', 'forty', 'fifty',
    'sixty', 'seventy', 'eighty', 'ninety',
]
scales = ['', 'thousand', 'million', 'billion', 'trillion']


def three_digits(n: int) -> str:
    if n == 0:
        return ''
    if n < 20:
        return ones[n]
    if n < 100:
        t, o = tens[n // 10], ones[n % 10]
        return f'{t}-{o}' if o else t
    h, rem = ones[n // 100], n % 100
    return f'{h} hundred {three_digits(rem)}' if rem else f'{h} hundred'


def number_to_words(n: int) -> str:
    if not isinstance(n, int):
        raise TypeError('Integer required')
    if n == 0:
        return 'zero'
    if n < 0:
        return 'negative ' + number_to_words(-n)

    parts: list[str] = []
    i = 0
    while n > 0:
        group = n % 1000
        if group:
            chunk = three_digits(group)
            parts.insert(0, f'{chunk} {scales[i]}' if scales[i] else chunk)
        n //= 1000
        i += 1
    return ' '.join(parts)


print(number_to_words(0))           # zero
print(number_to_words(42))          # forty-two
print(number_to_words(1_042))       # one thousand forty-two
print(number_to_words(1_000_000))   # one million
print(number_to_words(-7))          # negative seven

Go

package main

import (
    "fmt"
    "strings"
)

var ones = []string{
    "", "one", "two", "three", "four", "five", "six",
    "seven", "eight", "nine", "ten", "eleven", "twelve",
    "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",
    "eighteen", "nineteen",
}
var tens = []string{
    "", "", "twenty", "thirty", "forty", "fifty",
    "sixty", "seventy", "eighty", "ninety",
}
var scales = []string{"", "thousand", "million", "billion", "trillion"}

func threeDigits(n int) string {
    switch {
    case n == 0:
        return ""
    case n < 20:
        return ones[n]
    case n < 100:
        t, o := tens[n/10], ones[n%10]
        if o != "" {
            return t + "-" + o
        }
        return t
    default:
        h, rem := ones[n/100], n%100
        if rem != 0 {
            return h + " hundred " + threeDigits(rem)
        }
        return h + " hundred"
    }
}

func numberToWords(n int) string {
    if n == 0 {
        return "zero"
    }
    if n < 0 {
        return "negative " + numberToWords(-n)
    }

    var parts []string
    for i := 0; n > 0; i++ {
        if group := n % 1000; group != 0 {
            chunk := threeDigits(group)
            if scales[i] != "" {
                chunk += " " + scales[i]
            }
            parts = append([]string{chunk}, parts...)
        }
        n /= 1000
    }
    return strings.Join(parts, " ")
}

func main() {
    fmt.Println(numberToWords(0))          // zero
    fmt.Println(numberToWords(42))         // forty-two
    fmt.Println(numberToWords(1042))       // one thousand forty-two
    fmt.Println(numberToWords(1_000_000))  // one million
    fmt.Println(numberToWords(-7))         // negative seven
}

PHP

<?php

$ones  = ['', 'one', 'two', 'three', 'four', 'five', 'six',
          'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve',
          'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen',
          'eighteen', 'nineteen'];
$tens  = ['', '', 'twenty', 'thirty', 'forty', 'fifty',
          'sixty', 'seventy', 'eighty', 'ninety'];
$scales = ['', 'thousand', 'million', 'billion', 'trillion'];

function threeDigits(int $n, array $ones, array $tens): string {
    if ($n === 0) return '';
    if ($n < 20)  return $ones[$n];
    if ($n < 100) {
        $t = $tens[(int)($n / 10)];
        $o = $ones[$n % 10];
        return $o ? "$t-$o" : $t;
    }
    $h   = $ones[(int)($n / 100)];
    $rem = $n % 100;
    return $rem
        ? "$h hundred " . threeDigits($rem, $ones, $tens)
        : "$h hundred";
}

function numberToWords(int $n, array $ones, array $tens, array $scales): string {
    if ($n === 0) return 'zero';
    if ($n < 0)   return 'negative ' . numberToWords(-$n, $ones, $tens, $scales);

    $parts = [];
    $i = 0;
    while ($n > 0) {
        $group = $n % 1000;
        if ($group !== 0) {
            $chunk = threeDigits($group, $ones, $tens);
            if ($scales[$i]) $chunk .= ' ' . $scales[$i];
            array_unshift($parts, $chunk);
        }
        $n = (int)($n / 1000);
        $i++;
    }
    return implode(' ', $parts);
}

echo numberToWords(0, $ones, $tens, $scales) . "\n";       // zero
echo numberToWords(42, $ones, $tens, $scales) . "\n";      // forty-two
echo numberToWords(1042, $ones, $tens, $scales) . "\n";    // one thousand forty-two
echo numberToWords(1000000, $ones, $tens, $scales) . "\n"; // one million
echo numberToWords(-7, $ones, $tens, $scales) . "\n";      // negative seven

Edge Cases to Handle

Input Expected output Common mistake
0 "zero" Returning empty string
-1 "negative one" Passing negative to abs without prefixing
100 "one hundred" "one hundred zero"
1000 "one thousand" "one thousand zero"
11 "eleven" "ten-one" (treating teen as ten + ones)
21 "twenty-one" "twenty one" (missing hyphen per AP/Chicago style)
1000000 "one million" "one thousand thousand"

Decimal numbers

The standard approach: convert integer and fractional parts separately.

42.50 → "forty-two and 50/100"    (cheque/legal style)
42.50 → "forty-two point five"    (spoken style)

For monetary amounts, cheque style ("and XX/100") is conventional in banking.


Scale Words Reference

Power Name
10³ thousand
10⁶ million
10⁹ billion
10¹² trillion
10¹⁵ quadrillion
10¹⁸ quintillion
10²¹ sextillion
10²⁴ septillion

For most practical purposes (invoices, cheques, voice UI) you only need up to trillion.


Hyphen Rules (AP Style)

  • Compound numbers twenty-one through ninety-nine always use a hyphen.
  • "One hundred" has no hyphen — "one hundred forty-two" not "one-hundred-forty-two".
  • Thousands and above: no hyphen between scale and group — "one thousand forty-two".

FAQ

Q: Why does "eleven" not follow the pattern?
English teens come from Old English and Proto-Germanic roots ("ain-lif" = "one left over ten"). They were established long before a regular system existed.

Q: Should I write "forty" or "fourty"?
Always "forty". "Fourty" is a common misspelling — there is no 'u' in forty.

Q: How do I handle ordinals (first, second, twenty-first)?
Convert to cardinal first, then apply the suffix: "one" → "first", "two" → "second", "three" → "third", everything else + "th" (with some adjustments: "five" → "fifth", "nine" → "ninth", "twelve" → "twelfth", "twenty" → "twentieth").

Q: What about "and" — "one hundred and two" vs "one hundred two"?
Both are valid. British English uses "and" after hundreds ("one hundred and two"). American English typically omits it ("one hundred two"). For international software, omitting "and" is safer.

Q: How large can I go?
With 64-bit integers (up to ~9.2 × 10¹⁸) you need up to "quintillion". JavaScript's Number type loses integer precision above 2⁵³ — use BigInt for larger values.


Try It Online

Use the Number to Words converter to instantly spell out any integer — including negative numbers and values up to trillions.

Related tools

Keep reading

All Toolmingotools are free & run in your browser

No sign-up, no upload, no watermark. Your files never leave your device.

Browse all tools