Task

Show how to spell out a number in English.

You can use a preexisting implementation or roll your own, but you should support inputs up to at least one million (or the maximum value of your language's default bounded integer type, if that's less).

Support for inputs other than positive integers (like zero, negative integers, and floating-point numbers) is optional.



Related task

   Spelling of ordinal numbers.


import std.stdio, std.array, std.algorithm, std.bigint, std.range;
 
immutable tens = ["", "", "twenty", "thirty", "forty",
                  "fifty", "sixty", "seventy", "eighty", "ninety"];
immutable small = ["zero", "one", "two", "three", "four", "five",
                   "six", "seven", "eight", "nine", "ten", "eleven",
                   "twelve", "thirteen", "fourteen", "fifteen",
                   "sixteen", "seventeen", "eighteen", "nineteen"];
immutable huge = ["", ""] ~ ["m", "b", "tr", "quadr", "quint",
                             "sext", "sept", "oct", "non", "dec"]
                            .map!q{ a ~ "illion" }.array;
 
string spellBigInt(BigInt n) pure /*nothrow @safe*/ {
    static string nonZero(string c, BigInt n, string connect="") pure /*nothrow @safe*/ {
        return (n == 0) ? "" : (connect ~ c ~ n.spellBigInt);
    }
 
    static string lastAnd(string num) pure /*nothrow*/ @safe {
        if (num.canFind(',')) {
            string pre = num.retro.find(',').retro[0 .. $ - 1];
            string last = num[pre.length + 1 .. $];
            if (!last.canFind(" and "))
                last = " and" ~ last;
            num = pre ~ ',' ~ last;
        }
        return num;
    }
 
    static string big(in uint e, in BigInt n) pure /*nothrow @safe*/ {
        switch (e) {
            case 0:  return n.spellBigInt;
            case 1:  return n.spellBigInt ~ " thousand";
            default: return n.spellBigInt ~ " " ~ huge[e];
        }
    }
 
    if (n < 0) {
        return "minus " ~ spellBigInt(-n);
    } else if (n < 20) {
        return small[n.toInt];
    } else if (n < 100) {
        immutable BigInt a = n / 10;
        immutable BigInt b = n % 10;
        return tens[a.toInt] ~ nonZero("-", b);
    } else if (n < 1_000) {
        immutable BigInt a = n / 100;
        immutable BigInt b = n % 100;
        return small[a.toInt] ~ " hundred" ~ nonZero(" ", b, " and");
    } else {
        string[] bigs;
        uint e = 0;
        while (n != 0) {
            immutable BigInt r = n % 1_000;
            n /= 1_000;
            if (r != 0)
                bigs ~= big(e, r);
            e++;
        }
 
        return lastAnd(bigs.retro.join(", "));
    }
}
 
version(number_names_main) {
    void main() {
        foreach (immutable n; [0, -3, 5, -7, 11, -13, 17, -19, 23, -29])
            writefln("%+4d -> %s", n, n.BigInt.spellBigInt);
        writeln;
 
        auto n = 2_0121_002_001;
        while (n) {
            writefln("%-12d -> %s", n, n.BigInt.spellBigInt);
            n /= -10;
        }
        writefln("%-12d -> %s", n, n.BigInt.spellBigInt);
        writeln;
    }
}