Click here to Skip to main content
15,867,568 members
Please Sign up or sign in to vote.
5.00/5 (3 votes)
See more:
The challenge for this week is, as always, a simple one.

Given a 64 bit integer create a method that will convert the value to it's spoken equivalent.

For example: 1,203 would result in "One thousand, two hundred and three"

The scope of making this needlessly convoluted is high. Go at it!.

What I have tried:

Simplifying my life.

The winner of last week's is Graeme_Grant, though the excel solutions came damn close. Send Sean your details and win a prize!
Posted
Updated 19-Jan-17 18:58pm
v3
Comments
Patrice T 13-Jan-17 15:19pm    
"though the excel solutions came damn close."
Grrrrr almost got it :-)
Graeme_Grant 13-Jan-17 15:40pm    
Thanks Chris. Hopefully I contacted Sean correctly. :)
Chris Maunder 13-Jan-17 18:45pm    
You're in Melbourne still, right? I'm there in a week if you want a coffee (or maybe something cold)
PIEBALDconsult 13-Jan-17 20:12pm    
He wants a T-shirt...
Graeme_Grant 13-Jan-17 21:23pm    
Have moved around a little... Been a while since I last checked my profile... time to refresh it. [edit] Looks like I have kept it up to date. :)

Really!? you should know how to use your own site by now! :)
C#
using System;
using System.Speech.Synthesis;

namespace SampleSynthesis
{
    class Program
    {
        static void Main(string[] args)
        {
            // Initialize a new instance of the SpeechSynthesizer.
            SpeechSynthesizer synth = new SpeechSynthesizer();

            // Configure the audio output. 
            synth.SetOutputToDefaultAudioDevice();

            // Speak a string.
            synth.Speak(NumberToWords(1234567890123));

            Console.WriteLine();
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }

        public static string NumberToWords(long number)
        {
            if (number == 0)
                return "zero";

            if (number < 0)
                return "minus " + NumberToWords(Math.Abs(number));

            string words = "";
            if ((number / 1000000000000) > 0)
            {
                words += NumberToWords(number / 1000000000000) + " trillion ";
                number %= 1000000000000;
            }

            if ((number / 1000000000) > 0)
            {
                words += NumberToWords(number / 1000000000) + " billion ";
                number %= 1000000000;
            }

            if ((number / 1000000) > 0)
            {
                words += NumberToWords(number / 1000000) + " million ";
                number %= 1000000;
            }

            if ((number / 1000) > 0)
            {
                words += NumberToWords(number / 1000) + " thousand ";
                number %= 1000;
            }

            if ((number / 100) > 0)
            {
                words += NumberToWords(number / 100) + " hundred ";
                number %= 100;
            }

            if (number > 0)
            {
                if (words != "")
                    words += "and ";

                var unitsMap = new[] { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
                var tensMap = new[] { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };

                if (number < 20)
                    words += unitsMap[number];
                else
                {
                    words += tensMap[number / 10];
                    if ((number % 10) > 0)
                        words += "-" + unitsMap[number % 10];
                }
            }

            return words;
        }


    }
}
 
Share this answer
 
Comments
Chris Maunder 13-Jan-17 8:57am    
Yeah - last minute change of mind + 3hrs sleep = doofus time.
Mehdi Gholam 13-Jan-17 9:02am    
part of it was from stackoverflow ;)
Chris Maunder 13-Jan-17 9:20am    
?
[no name] 13-Jan-17 10:22am    
Pitchforks! Get your pitchforks here!
We got torches too! 2 for $5.
:-)
PIEBALDconsult 13-Jan-17 16:29pm    
I'll take three of each.
You didn't specify the range of ints to be tested or the Scale Mode[^]. Back in my days of school, a billion[^] was not the same as some other parts of the world however luckily, the world is using the US standard.

So here is my version that supports both positive/negative ints from Int16 right through to UInt64 (now also BigInteger); short, 'traditional' British, and long scale numbers; totally scalable as value size indepenant; formal & informal rounding; and can be made to suport any language with no modification to the core.

UPDATE: Added support for BigIntegers & "Tradition" British english numbers... Also 4 levels of normal & informal rounding.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;

namespace NumToWords
{
    class Program
    {
        static void Main(string[] args)
        {
            Int64 testMin = Int64.MinValue;
            Int64 testMax = Int64.MaxValue;
            UInt64 testUMax = UInt64.MaxValue;
            Int64 testQMin = testMin / 1000;
            Int64 testQMax = testMax / 1000;
            UInt64 testQUMax = testUMax / 1000;

            BigInteger testNegBig = -BigInteger.Pow(testQUMax, 13);
            BigInteger testBig = BigInteger.Pow(testQUMax, 13);

            int[] tests =
                {
                  -1,
                  0,
                  1,
                  11,
                  101,
                  1234,
                  10001,
                  100001,
                  1100101,
                  10110011,
                  100011011,
                  1001010101,
                  -1001010101
                };

            Console.WriteLine("SHORT SCALE NUMBERS");
            Console.WriteLine("===================\r\n");
            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i]);

            ShowResult(testQMin);
            ShowResult(testMin);
            ShowResult(testQMax);
            ShowResult(testMax);
            ShowResult(testQUMax);
            ShowResult(testUMax);
            ShowResult(testNegBig);
            ShowResult(testBig);

            Console.WriteLine();
            Console.WriteLine("TRADITIONAL BRITISH SCALE NUMBERS");
            Console.WriteLine("=================================\r\n");
            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i], ScaleType.TraditionalBritish);

            ShowResult(testQMin, ScaleType.TraditionalBritish);
            ShowResult(testMin, ScaleType.TraditionalBritish);
            ShowResult(testQMax, ScaleType.TraditionalBritish);
            ShowResult(testMax, ScaleType.TraditionalBritish);
            ShowResult(testQUMax, ScaleType.TraditionalBritish);
            ShowResult(testUMax, ScaleType.TraditionalBritish);
            ShowResult(testNegBig, ScaleType.TraditionalBritish);
            ShowResult(testBig, ScaleType.TraditionalBritish);

            Console.WriteLine();
            Console.WriteLine("LONG SCALE NUMBERS");
            Console.WriteLine("==================\r\n");
            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i], ScaleType.Long);

            ShowResult(testQMin, ScaleType.Long);
            ShowResult(testMin, ScaleType.Long);
            ShowResult(testQMax, ScaleType.Long);
            ShowResult(testMax, ScaleType.Long);
            ShowResult(testQUMax, ScaleType.Long);
            ShowResult(testUMax, ScaleType.Long);

            ShowResult(testNegBig, ScaleType.Long);

            ShowResult(testBig, ScaleType.Long);

            Console.WriteLine("-- Press any key to exit --");
            Console.ReadKey();

        }

        private static void ShowResult(Int16 value, ScaleType numberScale = ScaleType.Short)
        {
            Console.WriteLine(seperatorLine);
            Console.WriteLine($"VALUE: {value:N0}\r\nTEXT:  {value.ToWords(numberScale)}\r\n");
        }

        private static void ShowResult(UInt16 value, ScaleType numberScale = ScaleType.Short)
        {
            Console.WriteLine(seperatorLine);
            Console.WriteLine($"VALUE: {value:N0}\r\nTEXT:  {value.ToWords(numberScale)}\r\n");
        }

        private static void ShowResult(Int32 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((Int64)value, numberScale);
        }

        private static void ShowResult(UInt32 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((UInt64)value, numberScale);
        }

        private static void ShowResult(Int64 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((BigInteger)value, numberScale);
        }

        private static void ShowResult(UInt64 value, ScaleType numberScale = ScaleType.Short)
        {
            ShowResult((BigInteger)value, numberScale);
        }

        private static void ShowResult(BigInteger value, ScaleType numberScale = ScaleType.Short)
        {
            Console.WriteLine(seperatorLine);

            Console.Write($"VALUE: {value:N0}{spacer}TEXT:  {value.ToWords(numberScale).CaptalizeFirstLetter()}");

            if ((value < -999999 || value > 999999) && numberScale < ScaleType.TraditionalBritish)
            {
                Console.WriteLine($"{spacer}{spacer}{longMsgJoiner}{spacer}");

                Console.WriteLine($"{rounded}{value.ToRoundedWords(numberScale).CaptalizeFirstLetter()}");
                Console.WriteLine($"{roundedFraction1}{value.ToRoundedWords(numberScale, FractionType.Rounded).CaptalizeFirstLetter()}");
                Console.WriteLine($"{roundedFraction2}{value.ToRoundedWords(numberScale, FractionType.Short).CaptalizeFirstLetter()}");
                Console.WriteLine($"{roundedFraction3}{value.ToRoundedWords(numberScale, FractionType.Long).CaptalizeFirstLetter()}");

                Console.WriteLine($"{informal}{value.ToInformalRoundedWords(numberScale).CaptalizeFirstLetter()}");
                Console.WriteLine($"{informalFraction1}{value.ToInformalRoundedWords(numberScale, FractionType.Rounded).CaptalizeFirstLetter()}");
                Console.WriteLine($"{informalFraction1}{value.ToInformalRoundedWords(numberScale, FractionType.Short).CaptalizeFirstLetter()}");
                Console.WriteLine($"{informalFraction2}{value.ToInformalRoundedWords(numberScale, FractionType.Long).CaptalizeFirstLetter()}");
            }

            Console.WriteLine(spacer);
        }

        static string spacer = "\r\n";
        static string seperatorLine = "------------------------------------------------";
        static string longMsgJoiner = "... or, to simplify very large numbers ...";
        static string rounded = "Rounded................. : ";
        static string roundedFraction1 = "Rounded with fraction 1. : ";
        static string roundedFraction2 = "Rounded with fraction 2. : ";
        static string roundedFraction3 = "Rounded with fraction 3. : ";
        static string informal = "Informal rounding....... : ";
        static string informalFraction1 = "Informal with fraction 1 : ";
        static string informalFraction2 = "Informal with fraction 2 : ";
        static string informalFraction3 = "Informal with fraction 3 : ";
    }

    public enum ScaleType
    {
        Short,
        Long,
        TraditionalBritish
    }
    
    public enum FractionType
    {
        None,
        Rounded,
        Short,
        Long
    }

    public static class NumberToWordsExtension
    {
        static List<string> singlesScale = new List<string>() { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
        static List<string> tensScale = new List<string>() { "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
        static List<string> shortScale = new List<string>() { "hundred", "thousand", "million", "billion", "trillion", "quadrillion", "quintrillion", "sextillion", "septillion", "octillion", "nonillion", "decillion", "undecillion", "duodecillion", "tredecillion", "quattuordecillion", "quindecillion", "sexdecillion", "septendecillion", "octodecillion", "novemdecillion", "vigintillion", "unvigintillion", "duovigintillion", "tresvigintillion", "quattuorvigintillion", "quinquavigintillion", "sesvigintillion", "septemvigintillion", "octovigintillion", "novemvigintillion", "trigintillion", "untrigintillion", "duotrigintillion", "trestrigintillion", "quattuortrigintillion", "quinquatrigintillion", "sestrigintillion", "septentrigintillion", "octotrigintillion", "noventrigintillion", "quadragintillion", "quinquagintillion", "sexagintillion", "septuagintillion", "octogintillion", "nonagintillion", "centillion", "uncentillion", "duocentillion", "trescentillion", "decicentillion", "undecicentillion", "viginticentillion", "unviginticentillion", "trigintacentillion", "quadragintacentillion", "quinquagintacentillion", "sexagintacentillion", "septuagintacentillion", "octogintacentillion", "nonagintacentillion", "ducentillion", "trecentillion", "quadringentillion", "quingentillion", "sescentillion", "septingentillion", "octingentillion", "nongentillion", "millinillion" };
        static List<string> longScale = new List<string>() { "hundred", "thousand", "million", "millard", "billion", "billard", "trillion", "trilliard", "quadrillion", "quadrilliard", "quintillion", "quintilliard", "sextillion", "sextilliard", "septillion", "septilliard", "octillion", "octilliard", "nonillion", "nonilliard", "decillion", "decilliard", "undecillion", "undecilliard", "duodecillion", "duodecilliard", "tredecillion", "tredecilliard", "quattuordecillion", "quattuordecilliard", "quindecillion", "quindecilliard", "sedecillion", "sedecilliard", "septendecillion", "septendecilliard", "octodecillion", "octodecilliard", "novendecillion", "novendecilliard", "vigintillion", "vigintilliard", "quinquavigintilliard", "trigintilliard", "quinquatrigintilliard", "quadragintilliard", "quinquaquadragintilliard", "quinquagintilliard", "unquinquagintillion", "unquinquagintilliard", "duoquinquagintillion", "quinquaquinquagintilliard", "sesquinquagintillion", "sexagintilliard", "unsexagintillion", "quinquasexagintilliard", "septuagintilliard", "quinquaseptuagintilliard", "octogintilliard", "quinquaoctogintilliard", "nonagintilliard", "quinquanonagintilliard", "centilliard", "quinquagintacentilliard", "ducentilliard", "quinquagintaducentilliard", "trecentilliard", "quinquagintatrecentilliard", "quadringentilliard", "quinquagintaquadringentilliard", "quingentilliard" };
        static List<string> traditionalScale = new List<string>() { "hundred", "thousand", "million", "thousand million", "billion", "thousand billion", "trillion", "thousand trillion", "quadrillion", "thousand quadrillion", "quintillion", "thousand quintillion", "sextillion", "thousand sextillion", "septillion", "thousand septillion", "octillion", "thousand octillion", "nonillion", "thousand nonillion", "decillion", "thousand decillion", "undecillion", "thousand undecillion", "duodecillion", "thousand duodecillion", "tredecillion", "thousand tredecillion", "quattuordecillion", "thousand quattuordecillion", "quindecillion", "thousand quindecillion", "sedecillion", "thousand sedecillion", "septendecillion", "thousand septendecillion", "octodecillion", "thousand octodecillion", "novendecillion", "thousand novendecillion", "vigintillion", "thousand vigintillion", "thousand quinquavigintillion", "thousand trigintillion", "thousand quinquatrigintillion", "thousand quadragintillion", "thousand quinquaquadragintillion", "thousand quinquagintillion", "unquinquagintillion", "thousand unquinquagintillion", "duoquinquagintillion", "thousand quinquaquinquagintillion", "sesquinquagintillion", "thousand sexagintillion", "unsexagintillion", "thousand quinquasexagintillion", "thousand septuagintillion", "thousand quinquaseptuagintillion", "thousand octogintillion", "thousand quinquaoctogintillion", "thousand nonagintillion", "thousand quinquanonagintillion", "thousand centillion", "thousand quinquagintacentillion", "thousand ducentillion", "thousand quinquagintaducentillion", "thousand trecentillion", "thousand quinquagintatrecentillion", "thousand quadringentillion", "thousand quinquagintaquadringentillion", "thousand quingentillion" };
        static List<string> shortInformalLargeScale = new List<string>() { "hundred", "thousand", "million", "billion", "trillion", "dillion", "gagillion", "grillion", "hojillion", "jillion", "killion", "bajillion", "bazillion", "gadzillion", "kabillion", "kajillion", "katrillion", "kazillion", "robillion", "skillion", "squillion", "umpillion", "zillion", "bajivigintillion", "bazivigintillion", "gadzivigintillion", "kabvigintillion", "kajvigintillion", "katrivigintillion", "kazivigintillion", "robvigintillion", "skintillion", "squintillion", "umpintillion", "zintillion", "bajintillion", "bazintillion", "gadzintillion", "kabintillion", "kajintillion", "katrintillion", "kazintillion", "robintillion", "skiintillion", "squiintillion", "umpintillion", "zintillion", "bajcentillion", "bazcentillion", "gadzentillion", "kabentillion", "kajentillion", "katrentillion", "kazentillion", "robentillion", "skentillion", "squiagintacentillion", "umpagintacentillion", "ziagintacentillion", "bajagintacentillion", "bazagintacentillion", "gadzagintacentillion", "kabagintacentillion", "kajagintacentillion", "katragintacentillion", "kazgentillion", "robgentillion", "skigentillion", "squigentillion", "umpgentillion", "zinillion" };
        static List<string> longInformalLargeScale = new List<string>() { "hundred", "thousand", "million", "milliard", "billion", "billiard", "trillion", "trilliard", "dillion", "dilliard", "gagillion", "gagilliard", "grillion", "grilliard", "hojillion", "hojilliard", "jillion", "jilliard", "killion", "killiard", "bajillion", "bajilliard", "bazillion", "bazilliard", "gadzillion", "gadzilliard", "kabillion", "kabilliard", "kajillion", "kajilliard", "katrillion", "katrilliard", "kazillion", "kazilliard", "robillion", "robilliard", "skillion", "skilliard", "squillion", "squilliard", "umpillion", "umpilliard", "zillion", "zilliard", "bajivigintillion", "bajivigintilliard", "bazivigintillion", "bazivigintilliard", "gadzivigintillion", "gadzivigintilliard", "kabvigintillion", "kabvigintilliard", "kajvigintillion", "kajvigintilliard", "katrivigintillion", "katrivigintilliard", "kazivigintillion", "kazivigintilliard", "robvigintillion", "robvigintilliard", "skintillion", "skintilliard", "squintillion", "squintilliard", "umpintillion", "umpintilliard", "zintillion", "zintilliard", "bajintillion", "bajintilliard", "bazintillion", };

        static string zero = singlesScale[0];
        static string hundred = shortScale[0];

        public static string ToInformalRoundedWords(this Int32 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((Int64)num).ToInformalRoundedWords(numberScale, fractionType);
        }

        public static string ToInformalRoundedWords(this UInt32 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((UInt64)num).ToInformalRoundedWords(numberScale, fractionType);
        }

        public static string ToInformalRoundedWords(this Int64 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((BigInteger)num).ToInformalRoundedWords(numberScale, fractionType);
        }

        public static string ToInformalRoundedWords(this UInt64 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((BigInteger)num).ToInformalRoundedWords(numberScale, fractionType);
        }

        public static string ToInformalRoundedWords(this BigInteger num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ToRoundedScale(num, new Func<int, string>((c) =>
            {
                switch (numberScale)
                {
                    case ScaleType.Long:
                        return longInformalLargeScale[c];
                    case ScaleType.TraditionalBritish:
                    case ScaleType.Short:
                    default:
                        return shortInformalLargeScale[c];
                }
            }), numberScale, fractionType);
        }

        public static string ToRoundedWords(this Int32 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((Int64)num).ToRoundedWords(numberScale, fractionType);
        }

        public static string ToRoundedWords(this UInt32 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((UInt64)num).ToRoundedWords(numberScale, fractionType);
        }

        public static string ToRoundedWords(this Int64 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((BigInteger)num).ToRoundedWords(numberScale, fractionType);
        }

        public static string ToRoundedWords(this UInt64 num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ((BigInteger)num).ToRoundedWords(numberScale, fractionType);
        }

        public static string ToRoundedWords(this BigInteger num, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            return ToRoundedScale(num, new Func<int, string>((c) =>
                {
                    switch (numberScale)
                    {
                        case ScaleType.Long:
                            return longScale[c];
                        case ScaleType.TraditionalBritish:
                            return traditionalScale[c];
                        case ScaleType.Short:
                        default:
                            return shortScale[c];
                    }
                }), numberScale, fractionType);
        }

        private static String ToRoundedScale(BigInteger num, Func<int, string> getScaleText, ScaleType numberScale = ScaleType.Short, FractionType fractionType = FractionType.None)
        {
            // code can be used in UInt64 if BigInteger support not required (change BigInteget to UInt64 below)...
            if (num > -1000001 && num < 1000001)
                return num.ToWords(numberScale);

            var words = new StringBuilder();
            if (num < 0)
            {
                words.Append("minus ");
                num = -num;
            }

            //break up the number
            var s = String.Concat(num.ToString().Reverse());
            var groups = s.Select((x, i) => i)
                         .Where(i => i % 3 == 0)
                         .Select(i => s.Substring(i, s.Length - i >= 3 ? 3 : s.Length - i))
                         .ToArray();
            var count = (groups.Count() - 1) * 3;

            // integer part
            words.Append((num / (BigInteger)Math.Pow(10, count)).ToWords(numberScale));

            // Fraction part
            var fraction = String.Concat(groups[groups.Length - 2].Reverse());
            if (fractionType != FractionType.None)
                words.AppendFraction(fraction, fractionType);

            // scale
            FixSpace(words);
            words.Append(getScaleText(count / 3));
            
            // rounded fraction?
            if (fractionType == FractionType.Rounded && !fraction.Equals("000")) 
                words.Append(" plus");

            return words.ToString();
        }

        private static StringBuilder AppendFraction(this StringBuilder words, string fraction, FractionType fractionType = FractionType.None)
        {
            // safety check
            if (fraction == "000" || fractionType == FractionType.Rounded) return words;
            FixSpace(words);
            words.Append("point ");

            var part = fraction.TrimEnd(new[] { '0' });
            var c = part.ToArray();
            var value = int.Parse(part);

            if (fractionType == FractionType.Short && !c[0].Equals('0') && value > 9)
                words.Append(value.ToWords());

            else
                for (int i = 0; i < c.Length; i++)
                    words.Append(singlesScale[c[i] - 48]).Append(" ");

            return words;
        }

        public static string ToWords(this Int16 num, ScaleType numberScale = ScaleType.Short)
        {
            return ((Int64)num).ToWords(numberScale);
        }

        public static string ToWords(this UInt16 num, ScaleType numberScale = ScaleType.Short)
        {
            return ((Int64)num).ToWords(numberScale);
        }

        public static string ToWords(this Int32 num, ScaleType numberScale = ScaleType.Short)
        {
            return ((Int64)num).ToWords(numberScale);
        }

        public static string ToWords(this UInt32 num, ScaleType numberScale = ScaleType.Short)
        {
            return ((Int64)num).ToWords(numberScale);
        }

        public static string ToWords(this Int64 num, ScaleType numberScale = ScaleType.Short)
        {
            // uncomment if BigInteger support not required...
            //var sb = new StringBuilder();
            //if (num < 0)
            //{
            //    sb.Append("minus ");
            //    num = num != Int64.MinValue ? Math.Abs(num) : -num;
            //}
            //return sb.Append(((UInt64)num).ToWords(numberScale)).ToString();
            return ((BigInteger)num).ToWords();
        }

        public static string ToWords(this UInt64 num, ScaleType numberScale = ScaleType.Short)
        {
            return ((BigInteger)num).ToWords();
        }

        public static string ToWords(this BigInteger num, ScaleType numberScale = ScaleType.Short)
        {
            return ToWords(num, new Func<int, string>((c) =>
            {
                switch (numberScale)
                {
                    case ScaleType.Long:
                        return longScale[c];
                    case ScaleType.TraditionalBritish:
                        return traditionalScale[c];
                    case ScaleType.Short:
                    default:
                        return shortScale[c];
                }
            }), numberScale);
        }

        private static string ToWords(BigInteger num, Func<int, string> getScaleText, ScaleType numberScale = ScaleType.Short)
        {
            // note: code can be used "as is" in UInt64 if BigInteger support not required...
            // safety check
            if (num == 0) return zero;

            bool isEval = false;
            var words = new StringBuilder();
            if (num < 0)
            {
                words.Append("minus ");
                num = -num;
            }

            //break up the number
            var s = String.Concat(num.ToString().Reverse());
            var groups = s.Select((x, i) => i)
                          .Where(i => i % 3 == 0)
                          .Select(i => s.Substring(i, s.Length - i >= 3 ? 3 : s.Length - i))
                          .ToArray();

            // Set to 7 for Uint64 version
            if (groups.Length > 71)
                return "A friggin huge number!";

            for (int i = groups.Length; i > 0; i--)
            {
                bool isPart = false, isJoin = false, isHyphen = false;
                int[] digits = groups[i - 1].Select(o => Convert.ToInt32(o) - 48).ToArray();
                for (int j = digits.Length; j > 0; j--)
                {
                    var index = digits[j - 1];
                    if (index > 0)
                    {
                        if (!isHyphen && (isJoin || (i == 1 && isEval) && j < 3))
                        {
                            var c = words[words.Length - 1];
                            if (c.Equals(',')) words[words.Length - 1] = ' ';
                            else FixSpace(words);
                            words.Append("and ");
                            isJoin = false;
                        }

                        if (j == 3 || j == 1) // singles
                        {
                            if (words.Length > 0)
                            {
                                if (isHyphen) words.Append("-");
                                else FixSpace(words);
                            }
                            words.Append(singlesScale[index]).Append(" ");
                            isPart = true;
                        }

                        if (j == 3) // hundreds
                        {
                            words.Append(hundred);
                            isPart = isJoin = true;
                        }

                        if (j == 2) // tens
                        {
                            if (words.Length > 0)
                                FixSpace(words);

                            if (index == 1)
                                words.Append(singlesScale[10 + digits[j-- - 2]]).Append(" ");
                            else
                            {
                                words.Append(tensScale[index - 1]);
                                isHyphen = true;
                            }
                            isPart = true;
                        }
                    }
                    isPart = isPart && i > 1;
                }

                if (isPart) // number scale
                {
                    FixSpace(words);
                    words.Append(getScaleText(i - 1));
                }
                if (isPart) words.Append(",");
                isEval = isEval || isPart;
            }
            return words.ToString();
        }

        private static void FixSpace(StringBuilder words)
        {
            if (!words[words.Length - 1].Equals(' ')) words.Append(" ");
        }
    }

    public static class StringExtension
    {
        public static string CaptalizeFirstLetter(this string data)
        {
            var chars = data.ToCharArray();
            var i = data.IndexOf(data.First(char.IsLetter));
            chars[i] = char.ToUpper(chars[i]);
            return new string(chars);
        }
    }
}


and the Output:
SHORT SCALE NUMBERS
===================

------------------------------------------------
VALUE: -1
TEXT:  Minus one

------------------------------------------------
VALUE: 0
TEXT:  Zero

------------------------------------------------
VALUE: 1
TEXT:  One

------------------------------------------------
VALUE: 11
TEXT:  Eleven

------------------------------------------------
VALUE: 101
TEXT:  One hundred and one

------------------------------------------------
VALUE: 1,234
TEXT:  One thousand, two hundred and thirty-four

------------------------------------------------
VALUE: 10,001
TEXT:  Ten thousand and one

------------------------------------------------
VALUE: 100,001
TEXT:  One hundred thousand and one

------------------------------------------------
VALUE: 1,100,101
TEXT:  One million, one hundred thousand, one hundred and one

... or, to simplify very large numbers ...

Rounded................. : One million
Rounded with fraction 1. : One million plus
Rounded with fraction 2. : One point one million
Rounded with fraction 3. : One point one million
Informal rounding....... : One million
Informal with fraction 1 : One million plus
Informal with fraction 1 : One point one million
Informal with fraction 2 : One point one million


------------------------------------------------
VALUE: 10,110,011
TEXT:  Ten million, one hundred and ten thousand and eleven

... or, to simplify very large numbers ...

Rounded................. : Ten million
Rounded with fraction 1. : Ten million plus
Rounded with fraction 2. : Ten point eleven million
Rounded with fraction 3. : Ten point one one million
Informal rounding....... : Ten million
Informal with fraction 1 : Ten million plus
Informal with fraction 1 : Ten point eleven million
Informal with fraction 2 : Ten point one one million


------------------------------------------------
VALUE: 100,011,011
TEXT:  One hundred million, eleven thousand and eleven

... or, to simplify very large numbers ...

Rounded................. : One hundred million
Rounded with fraction 1. : One hundred million plus
Rounded with fraction 2. : One hundred point zero one one million
Rounded with fraction 3. : One hundred point zero one one million
Informal rounding....... : One hundred million
Informal with fraction 1 : One hundred million plus
Informal with fraction 1 : One hundred point zero one one million
Informal with fraction 2 : One hundred point zero one one million


------------------------------------------------
VALUE: 1,001,010,101
TEXT:  One billion, one million, ten thousand, one hundred and one

... or, to simplify very large numbers ...

Rounded................. : One billion
Rounded with fraction 1. : One billion plus
Rounded with fraction 2. : One point zero zero one billion
Rounded with fraction 3. : One point zero zero one billion
Informal rounding....... : One billion
Informal with fraction 1 : One billion plus
Informal with fraction 1 : One point zero zero one billion
Informal with fraction 2 : One point zero zero one billion


------------------------------------------------
VALUE: -1,001,010,101
TEXT:  Minus one billion, one million, ten thousand, one hundred and one

... or, to simplify very large numbers ...

Rounded................. : Minus one billion
Rounded with fraction 1. : Minus one billion plus
Rounded with fraction 2. : Minus one point zero zero one billion
Rounded with fraction 3. : Minus one point zero zero one billion
Informal rounding....... : Minus one billion
Informal with fraction 1 : Minus one billion plus
Informal with fraction 1 : Minus one point zero zero one billion
Informal with fraction 2 : Minus one point zero zero one billion


------------------------------------------------
VALUE: -9,223,372,036,854,775
TEXT:  Minus nine quadrillion, two hundred and twenty-three trillion, three hundred and seventy-two billion, thirty-six million, eight hundred and fifty-four thousand, seven hundred and seventy-five

... or, to simplify very large numbers ...

Rounded................. : Minus nine quadrillion
Rounded with fraction 1. : Minus nine quadrillion plus
Rounded with fraction 2. : Minus nine point two hundred and twenty-three quadrillion
Rounded with fraction 3. : Minus nine point two two three quadrillion
Informal rounding....... : Minus nine dillion
Informal with fraction 1 : Minus nine dillion plus
Informal with fraction 1 : Minus nine point two hundred and twenty-three dillion
Informal with fraction 2 : Minus nine point two two three dillion


------------------------------------------------
VALUE: -9,223,372,036,854,775,808
TEXT:  Minus nine quintrillion, two hundred and twenty-three quadrillion, three hundred and seventy-two trillion, thirty-six billion, eight hundred and fifty-four million, seven hundred and seventy-five thousand, eight hundred and eight

... or, to simplify very large numbers ...

Rounded................. : Minus nine quintrillion
Rounded with fraction 1. : Minus nine quintrillion plus
Rounded with fraction 2. : Minus nine point two hundred and twenty-three quintrillion
Rounded with fraction 3. : Minus nine point two two three quintrillion
Informal rounding....... : Minus nine gagillion
Informal with fraction 1 : Minus nine gagillion plus
Informal with fraction 1 : Minus nine point two hundred and twenty-three gagillion
Informal with fraction 2 : Minus nine point two two three gagillion


------------------------------------------------
VALUE: 9,223,372,036,854,775
TEXT:  Nine quadrillion, two hundred and twenty-three trillion, three hundred and seventy-two billion, thirty-six million, eight hundred and fifty-four thousand, seven hundred and seventy-five

... or, to simplify very large numbers ...

Rounded................. : Nine quadrillion
Rounded with fraction 1. : Nine quadrillion plus
Rounded with fraction 2. : Nine point two hundred and twenty-three quadrillion
Rounded with fraction 3. : Nine point two two three quadrillion
Informal rounding....... : Nine dillion
Informal with fraction 1 : Nine dillion plus
Informal with fraction 1 : Nine point two hundred and twenty-three dillion
Informal with fraction 2 : Nine point two two three dillion


------------------------------------------------
VALUE: 9,223,372,036,854,775,807
TEXT:  Nine quintrillion, two hundred and twenty-three quadrillion, three hundred and seventy-two trillion, thirty-six billion, eight hundred and fifty-four million, seven hundred and seventy-five thousand, eight hundred and seven

... or, to simplify very large numbers ...

Rounded................. : Nine quintrillion
Rounded with fraction 1. : Nine quintrillion plus
Rounded with fraction 2. : Nine point two hundred and twenty-three quintrillion
Rounded with fraction 3. : Nine point two two three quintrillion
Informal rounding....... : Nine gagillion
Informal with fraction 1 : Nine gagillion plus
Informal with fraction 1 : Nine point two hundred and twenty-three gagillion
Informal with fraction 2 : Nine point two two three gagillion


------------------------------------------------
VALUE: 18,446,744,073,709,551
TEXT:  Eighteen quadrillion, four hundred and forty-six trillion, seven hundred and forty-four billion, seventy-three million, seven hundred and nine thousand, five hundred and fifty-one

... or, to simplify very large numbers ...

Rounded................. : Eighteen quadrillion
Rounded with fraction 1. : Eighteen quadrillion plus
Rounded with fraction 2. : Eighteen point four hundred and forty-six quadrillion
Rounded with fraction 3. : Eighteen point four four six quadrillion
Informal rounding....... : Eighteen dillion
Informal with fraction 1 : Eighteen dillion plus
Informal with fraction 1 : Eighteen point four hundred and forty-six dillion
Informal with fraction 2 : Eighteen point four four six dillion


------------------------------------------------
VALUE: 18,446,744,073,709,551,615
TEXT:  Eighteen quintrillion, four hundred and forty-six quadrillion, seven hundred and forty-four trillion, seventy-three billion, seven hundred and nine million, five hundred and fifty-one thousand, six hundred and fifteen

... or, to simplify very large numbers ...

Rounded................. : Eighteen quintrillion
Rounded with fraction 1. : Eighteen quintrillion plus
Rounded with fraction 2. : Eighteen point four hundred and forty-six quintrillion
Rounded with fraction 3. : Eighteen point four four six quintrillion
Informal rounding....... : Eighteen gagillion
Informal with fraction 1 : Eighteen gagillion plus
Informal with fraction 1 : Eighteen point four hundred and forty-six gagillion
Informal with fraction 2 : Eighteen point four four six gagillion


------------------------------------------------
VALUE: -28,638,903,918,474,948,771,853,900,789,600,176,813,374,560,672,787,905,549,951,087,488,011,382,049,361,477,907,432,468,077,275,919,439,086,145,725,268,599,727,509,261,609,545,191,934,342,376,096,106,426,327,812,926,262,086,834,977,087,858,680,322,241,546,113,514,383,143,501,519,151
TEXT:  Minus twenty-eight millinillion, six hundred and thirty-eight nongentillion, nine hundred and three octingentillion, nine hundred and eighteen septingentillion, four hundred and seventy-four sescentillion, nine hundred and forty-eight quingentillion, seven hundred and seventy-one quadringentillion, eight hundred and fifty-three trecentillion, nine hundred ducentillion, seven hundred and eighty-nine nonagintacentillion, six hundred octogintacentillion, one hundred and seventy-six septuagintacentillion, eight hundred and thirteen sexagintacentillion, three hundred and seventy-four quinquagintacentillion, five hundred and sixty quadragintacentillion, six hundred and seventy-two trigintacentillion, seven hundred and eighty-seven unviginticentillion, nine hundred and five viginticentillion, five hundred and forty-nine undecicentillion, nine hundred and fifty-one decicentillion, eighty-seven trescentillion, four hundred and eighty-eight duocentillion, eleven uncentillion, three hundred and eighty-two centillion, forty-nine nonagintillion, three hundred and sixty-one octogintillion, four hundred and seventy-seven septuagintillion, nine hundred and seven sexagintillion, four hundred and thirty-two quinquagintillion, four hundred and sixty-eight quadragintillion, seventy-seven noventrigintillion, two hundred and seventy-five octotrigintillion, nine hundred and nineteen septentrigintillion, four hundred and thirty-nine sestrigintillion, eighty-six quinquatrigintillion, one hundred and forty-five quattuortrigintillion, seven hundred and twenty-five trestrigintillion, two hundred and sixty-eight duotrigintillion, five hundred and ninety-nine untrigintillion, seven hundred and twenty-seven trigintillion, five hundred and nine novemvigintillion, two hundred and sixty-one octovigintillion, six hundred and nine septemvigintillion, five hundred and forty-five sesvigintillion, one hundred and ninety-one quinquavigintillion, nine hundred and thirty-four quattuorvigintillion, three hundred and forty-two tresvigintillion, three hundred and seventy-six duovigintillion, ninety-six unvigintillion, one hundred and six vigintillion, four hundred and twenty-six novemdecillion, three hundred and twenty-seven octodecillion, eight hundred and twelve septendecillion, nine hundred and twenty-six sexdecillion, two hundred and sixty-two quindecillion, eighty-six quattuordecillion, eight hundred and thirty-four tredecillion, nine hundred and seventy-seven duodecillion, eighty-seven undecillion, eight hundred and fifty-eight decillion, six hundred and eighty nonillion, three hundred and twenty-two octillion, two hundred and forty-one septillion, five hundred and forty-six sextillion, one hundred and thirteen quintrillion, five hundred and fourteen quadrillion, three hundred and eighty-three trillion, one hundred and forty-three billion, five hundred and one million, five hundred and nineteen thousand, one hundred and fifty-one

... or, to simplify very large numbers ...

Rounded................. : Minus twenty-eight millinillion
Rounded with fraction 1. : Minus twenty-eight millinillion plus
Rounded with fraction 2. : Minus twenty-eight point six hundred and thirty-eight millinillion
Rounded with fraction 3. : Minus twenty-eight point six three eight millinillion
Informal rounding....... : Minus twenty-eight zinillion
Informal with fraction 1 : Minus twenty-eight zinillion plus
Informal with fraction 1 : Minus twenty-eight point six hundred and thirty-eight zinillion
Informal with fraction 2 : Minus twenty-eight point six three eight zinillion


------------------------------------------------
VALUE: 28,638,903,918,474,948,771,853,900,789,600,176,813,374,560,672,787,905,549,951,087,488,011,382,049,361,477,907,432,468,077,275,919,439,086,145,725,268,599,727,509,261,609,545,191,934,342,376,096,106,426,327,812,926,262,086,834,977,087,858,680,322,241,546,113,514,383,143,501,519,151
TEXT:  Twenty-eight millinillion, six hundred and thirty-eight nongentillion, nine hundred and three octingentillion, nine hundred and eighteen septingentillion, four hundred and seventy-four sescentillion, nine hundred and forty-eight quingentillion, seven hundred and seventy-one quadringentillion, eight hundred and fifty-three trecentillion, nine hundred ducentillion, seven hundred and eighty-nine nonagintacentillion, six hundred octogintacentillion, one hundred and seventy-six septuagintacentillion, eight hundred and thirteen sexagintacentillion, three hundred and seventy-four quinquagintacentillion, five hundred and sixty quadragintacentillion, six hundred and seventy-two trigintacentillion, seven hundred and eighty-seven unviginticentillion, nine hundred and five viginticentillion, five hundred and forty-nine undecicentillion, nine hundred and fifty-one decicentillion, eighty-seven trescentillion, four hundred and eighty-eight duocentillion, eleven uncentillion, three hundred and eighty-two centillion, forty-nine nonagintillion, three hundred and sixty-one octogintillion, four hundred and seventy-seven septuagintillion, nine hundred and seven sexagintillion, four hundred and thirty-two quinquagintillion, four hundred and sixty-eight quadragintillion, seventy-seven noventrigintillion, two hundred and seventy-five octotrigintillion, nine hundred and nineteen septentrigintillion, four hundred and thirty-nine sestrigintillion, eighty-six quinquatrigintillion, one hundred and forty-five quattuortrigintillion, seven hundred and twenty-five trestrigintillion, two hundred and sixty-eight duotrigintillion, five hundred and ninety-nine untrigintillion, seven hundred and twenty-seven trigintillion, five hundred and nine novemvigintillion, two hundred and sixty-one octovigintillion, six hundred and nine septemvigintillion, five hundred and forty-five sesvigintillion, one hundred and ninety-one quinquavigintillion, nine hundred and thirty-four quattuorvigintillion, three hundred and forty-two tresvigintillion, three hundred and seventy-six duovigintillion, ninety-six unvigintillion, one hundred and six vigintillion, four hundred and twenty-six novemdecillion, three hundred and twenty-seven octodecillion, eight hundred and twelve septendecillion, nine hundred and twenty-six sexdecillion, two hundred and sixty-two quindecillion, eighty-six quattuordecillion, eight hundred and thirty-four tredecillion, nine hundred and seventy-seven duodecillion, eighty-seven undecillion, eight hundred and fifty-eight decillion, six hundred and eighty nonillion, three hundred and twenty-two octillion, two hundred and forty-one septillion, five hundred and forty-six sextillion, one hundred and thirteen quintrillion, five hundred and fourteen quadrillion, three hundred and eighty-three trillion, one hundred and forty-three billion, five hundred and one million, five hundred and nineteen thousand, one hundred and fifty-one

... or, to simplify very large numbers ...

Rounded................. : Twenty-eight millinillion
Rounded with fraction 1. : Twenty-eight millinillion plus
Rounded with fraction 2. : Twenty-eight point six hundred and thirty-eight millinillion
Rounded with fraction 3. : Twenty-eight point six three eight millinillion
Informal rounding....... : Twenty-eight zinillion
Informal with fraction 1 : Twenty-eight zinillion plus
Informal with fraction 1 : Twenty-eight point six hundred and thirty-eight zinillion
Informal with fraction 2 : Twenty-eight point six three eight zinillion



TRADITIONAL BRITISH SCALE NUMBERS
=================================

------------------------------------------------
VALUE: -1
TEXT:  Minus one

------------------------------------------------
VALUE: 0
TEXT:  Zero

------------------------------------------------
VALUE: 1
TEXT:  One

------------------------------------------------
VALUE: 11
TEXT:  Eleven

------------------------------------------------
VALUE: 101
TEXT:  One hundred and one

------------------------------------------------
VALUE: 1,234
TEXT:  One thousand, two hundred and thirty-four

------------------------------------------------
VALUE: 10,001
TEXT:  Ten thousand and one

------------------------------------------------
VALUE: 100,001
TEXT:  One hundred thousand and one

------------------------------------------------
VALUE: 1,100,101
TEXT:  One million, one hundred thousand, one hundred and one

------------------------------------------------
VALUE: 10,110,011
TEXT:  Ten million, one hundred and ten thousand and eleven

------------------------------------------------
VALUE: 100,011,011
TEXT:  One hundred million, eleven thousand and eleven

------------------------------------------------
VALUE: 1,001,010,101
TEXT:  One thousand million, one million, ten thousand, one hundred and one

------------------------------------------------
VALUE: -1,001,010,101
TEXT:  Minus one thousand million, one million, ten thousand, one hundred and one

------------------------------------------------
VALUE: -9,223,372,036,854,775
TEXT:  Minus nine thousand billion, two hundred and twenty-three billion, three hundred and seventy-two thousand million, thirty-six million, eight hundred and fifty-four thousand, seven hundred and seventy-five

------------------------------------------------
VALUE: -9,223,372,036,854,775,808
TEXT:  Minus nine trillion, two hundred and twenty-three thousand billion, three hundred and seventy-two billion, thirty-six thousand million, eight hundred and fifty-four million, seven hundred and seventy-five thousand, eight hundred and eight

------------------------------------------------
VALUE: 9,223,372,036,854,775
TEXT:  Nine thousand billion, two hundred and twenty-three billion, three hundred and seventy-two thousand million, thirty-six million, eight hundred and fifty-four thousand, seven hundred and seventy-five

------------------------------------------------
VALUE: 9,223,372,036,854,775,807
TEXT:  Nine trillion, two hundred and twenty-three thousand billion, three hundred and seventy-two billion, thirty-six thousand million, eight hundred and fifty-four million, seven hundred and seventy-five thousand, eight hundred and seven

------------------------------------------------
VALUE: 18,446,744,073,709,551
TEXT:  Eighteen thousand billion, four hundred and forty-six billion, seven hundred and forty-four thousand million, seventy-three million, seven hundred and nine thousand, five hundred and fifty-one

------------------------------------------------
VALUE: 18,446,744,073,709,551,615
TEXT:  Eighteen trillion, four hundred and forty-six thousand billion, seven hundred and forty-four billion, seventy-three thousand million, seven hundred and nine million, five hundred and fifty-one thousand, six hundred and fifteen

------------------------------------------------
VALUE: -28,638,903,918,474,948,771,853,900,789,600,176,813,374,560,672,787,905,549,951,087,488,011,382,049,361,477,907,432,468,077,275,919,439,086,145,725,268,599,727,509,261,609,545,191,934,342,376,096,106,426,327,812,926,262,086,834,977,087,858,680,322,241,546,113,514,383,143,501,519,151
TEXT:  Minus twenty-eight thousand quingentillion, six hundred and thirty-eight thousand quinquagintaquadringentillion, nine hundred and three thousand quadringentillion, nine hundred and eighteen thousand quinquagintatrecentillion, four hundred and seventy-four thousand trecentillion, nine hundred and forty-eight thousand quinquagintaducentillion, seven hundred and seventy-one thousand ducentillion, eight hundred and fifty-three thousand quinquagintacentillion, nine hundred thousand centillion, seven hundred and eighty-nine thousand quinquanonagintillion, six hundred thousand nonagintillion, one hundred and seventy-six thousand quinquaoctogintillion, eight hundred and thirteen thousand octogintillion, three hundred and seventy-four thousand quinquaseptuagintillion, five hundred and sixty thousand septuagintillion, six hundred and seventy-two thousand quinquasexagintillion, seven hundred and eighty-seven unsexagintillion, nine hundred and five thousand sexagintillion, five hundred and forty-nine sesquinquagintillion, nine hundred and fifty-one thousand quinquaquinquagintillion, eighty-seven duoquinquagintillion, four hundred and eighty-eight thousand unquinquagintillion, eleven unquinquagintillion, three hundred and eighty-two thousand quinquagintillion, forty-nine thousand quinquaquadragintillion, three hundred and sixty-one thousand quadragintillion, four hundred and seventy-seven thousand quinquatrigintillion, nine hundred and seven thousand trigintillion, four hundred and thirty-two thousand quinquavigintillion, four hundred and sixty-eight thousand vigintillion, seventy-seven vigintillion, two hundred and seventy-five thousand novendecillion, nine hundred and nineteen novendecillion, four hundred and thirty-nine thousand octodecillion, eighty-six octodecillion, one hundred and forty-five thousand septendecillion, seven hundred and twenty-five septendecillion, two hundred and sixty-eight thousand sedecillion, five hundred and ninety-nine sedecillion, seven hundred and twenty-seven thousand quindecillion, five hundred and nine quindecillion, two hundred and sixty-one thousand quattuordecillion, six hundred and nine quattuordecillion, five hundred and forty-five thousand tredecillion, one hundred and ninety-one tredecillion, nine hundred and thirty-four thousand duodecillion, three hundred and forty-two duodecillion, three hundred and seventy-six thousand undecillion, ninety-six undecillion, one hundred and six thousand decillion, four hundred and twenty-six decillion, three hundred and twenty-seven thousand nonillion, eight hundred and twelve nonillion, nine hundred and twenty-six thousand octillion, two hundred and sixty-two octillion, eighty-six thousand septillion, eight hundred and thirty-four septillion, nine hundred and seventy-seven thousand sextillion, eighty-seven sextillion, eight hundred and fifty-eight thousand quintillion, six hundred and eighty quintillion, three hundred and twenty-two thousand quadrillion, two hundred and forty-one quadrillion, five hundred and forty-six thousand trillion, one hundred and thirteen trillion, five hundred and fourteen thousand billion, three hundred and eighty-three billion, one hundred and forty-three thousand million, five hundred and one million, five hundred and nineteen thousand, one hundred and fifty-one

------------------------------------------------
VALUE: 28,638,903,918,474,948,771,853,900,789,600,176,813,374,560,672,787,905,549,951,087,488,011,382,049,361,477,907,432,468,077,275,919,439,086,145,725,268,599,727,509,261,609,545,191,934,342,376,096,106,426,327,812,926,262,086,834,977,087,858,680,322,241,546,113,514,383,143,501,519,151
TEXT:  Twenty-eight thousand quingentillion, six hundred and thirty-eight thousand quinquagintaquadringentillion, nine hundred and three thousand quadringentillion, nine hundred and eighteen thousand quinquagintatrecentillion, four hundred and seventy-four thousand trecentillion, nine hundred and forty-eight thousand quinquagintaducentillion, seven hundred and seventy-one thousand ducentillion, eight hundred and fifty-three thousand quinquagintacentillion, nine hundred thousand centillion, seven hundred and eighty-nine thousand quinquanonagintillion, six hundred thousand nonagintillion, one hundred and seventy-six thousand quinquaoctogintillion, eight hundred and thirteen thousand octogintillion, three hundred and seventy-four thousand quinquaseptuagintillion, five hundred and sixty thousand septuagintillion, six hundred and seventy-two thousand quinquasexagintillion, seven hundred and eighty-seven unsexagintillion, nine hundred and five thousand sexagintillion, five hundred and forty-nine sesquinquagintillion, nine hundred and fifty-one thousand quinquaquinquagintillion, eighty-seven duoquinquagintillion, four hundred and eighty-eight thousand unquinquagintillion, eleven unquinquagintillion, three hundred and eighty-two thousand quinquagintillion, forty-nine thousand quinquaquadragintillion, three hundred and sixty-one thousand quadragintillion, four hundred and seventy-seven thousand quinquatrigintillion, nine hundred and seven thousand trigintillion, four hundred and thirty-two thousand quinquavigintillion, four hundred and sixty-eight thousand vigintillion, seventy-seven vigintillion, two hundred and seventy-five thousand novendecillion, nine hundred and nineteen novendecillion, four hundred and thirty-nine thousand octodecillion, eighty-six octodecillion, one hundred and forty-five thousand septendecillion, seven hundred and twenty-five septendecillion, two hundred and sixty-eight thousand sedecillion, five hundred and ninety-nine sedecillion, seven hundred and twenty-seven thousand quindecillion, five hundred and nine quindecillion, two hundred and sixty-one thousand quattuordecillion, six hundred and nine quattuordecillion, five hundred and forty-five thousand tredecillion, one hundred and ninety-one tredecillion, nine hundred and thirty-four thousand duodecillion, three hundred and forty-two duodecillion, three hundred and seventy-six thousand undecillion, ninety-six undecillion, one hundred and six thousand decillion, four hundred and twenty-six decillion, three hundred and twenty-seven thousand nonillion, eight hundred and twelve nonillion, nine hundred and twenty-six thousand octillion, two hundred and sixty-two octillion, eighty-six thousand septillion, eight hundred and thirty-four septillion, nine hundred and seventy-seven thousand sextillion, eighty-seven sextillion, eight hundred and fifty-eight thousand quintillion, six hundred and eighty quintillion, three hundred and twenty-two thousand quadrillion, two hundred and forty-one quadrillion, five hundred and forty-six thousand trillion, one hundred and thirteen trillion, five hundred and fourteen thousand billion, three hundred and eighty-three billion, one hundred and forty-three thousand million, five hundred and one million, five hundred and nineteen thousand, one hundred and fifty-one


LONG SCALE NUMBERS
==================

------------------------------------------------
VALUE: -1
TEXT:  Minus one

------------------------------------------------
VALUE: 0
TEXT:  Zero

------------------------------------------------
VALUE: 1
TEXT:  One

------------------------------------------------
VALUE: 11
TEXT:  Eleven

------------------------------------------------
VALUE: 101
TEXT:  One hundred and one

------------------------------------------------
VALUE: 1,234
TEXT:  One thousand, two hundred and thirty-four

------------------------------------------------
VALUE: 10,001
TEXT:  Ten thousand and one

------------------------------------------------
VALUE: 100,001
TEXT:  One hundred thousand and one

------------------------------------------------
VALUE: 1,100,101
TEXT:  One million, one hundred thousand, one hundred and one

... or, to simplify very large numbers ...

Rounded................. : One million
Rounded with fraction 1. : One million plus
Rounded with fraction 2. : One point one million
Rounded with fraction 3. : One point one million
Informal rounding....... : One million
Informal with fraction 1 : One million plus
Informal with fraction 1 : One point one million
Informal with fraction 2 : One point one million


------------------------------------------------
VALUE: 10,110,011
TEXT:  Ten million, one hundred and ten thousand and eleven

... or, to simplify very large numbers ...

Rounded................. : Ten million
Rounded with fraction 1. : Ten million plus
Rounded with fraction 2. : Ten point eleven million
Rounded with fraction 3. : Ten point one one million
Informal rounding....... : Ten million
Informal with fraction 1 : Ten million plus
Informal with fraction 1 : Ten point eleven million
Informal with fraction 2 : Ten point one one million


------------------------------------------------
VALUE: 100,011,011
TEXT:  One hundred million, eleven thousand and eleven

... or, to simplify very large numbers ...

Rounded................. : One hundred million
Rounded with fraction 1. : One hundred million plus
Rounded with fraction 2. : One hundred point zero one one million
Rounded with fraction 3. : One hundred point zero one one million
Informal rounding....... : One hundred million
Informal with fraction 1 : One hundred million plus
Informal with fraction 1 : One hundred point zero one one million
Informal with fraction 2 : One hundred point zero one one million


------------------------------------------------
VALUE: 1,001,010,101
TEXT:  One millard, one million, ten thousand, one hundred and one

... or, to simplify very large numbers ...

Rounded................. : One millard
Rounded with fraction 1. : One millard plus
Rounded with fraction 2. : One point zero zero one millard
Rounded with fraction 3. : One point zero zero one millard
Informal rounding....... : One milliard
Informal with fraction 1 : One milliard plus
Informal with fraction 1 : One point zero zero one milliard
Informal with fraction 2 : One point zero zero one milliard


------------------------------------------------
VALUE: -1,001,010,101
TEXT:  Minus one millard, one million, ten thousand, one hundred and one

... or, to simplify very large numbers ...

Rounded................. : Minus one millard
Rounded with fraction 1. : Minus one millard plus
Rounded with fraction 2. : Minus one point zero zero one millard
Rounded with fraction 3. : Minus one point zero zero one millard
Informal rounding....... : Minus one milliard
Informal with fraction 1 : Minus one milliard plus
Informal with fraction 1 : Minus one point zero zero one milliard
Informal with fraction 2 : Minus one point zero zero one milliard


------------------------------------------------
VALUE: -9,223,372,036,854,775
TEXT:  Minus nine billard, two hundred and twenty-three billion, three hundred and seventy-two millard, thirty-six million, eight hundred and fifty-four thousand, seven hundred and seventy-five

... or, to simplify very large numbers ...

Rounded................. : Minus nine billard
Rounded with fraction 1. : Minus nine billard plus
Rounded with fraction 2. : Minus nine point two hundred and twenty-three billard
Rounded with fraction 3. : Minus nine point two two three billard
Informal rounding....... : Minus nine billiard
Informal with fraction 1 : Minus nine billiard plus
Informal with fraction 1 : Minus nine point two hundred and twenty-three billiard
Informal with fraction 2 : Minus nine point two two three billiard


------------------------------------------------
VALUE: -9,223,372,036,854,775,808
TEXT:  Minus nine trillion, two hundred and twenty-three billard, three hundred and seventy-two billion, thirty-six millard, eight hundred and fifty-four million, seven hundred and seventy-five thousand, eight hundred and eight

... or, to simplify very large numbers ...

Rounded................. : Minus nine trillion
Rounded with fraction 1. : Minus nine trillion plus
Rounded with fraction 2. : Minus nine point two hundred and twenty-three trillion
Rounded with fraction 3. : Minus nine point two two three trillion
Informal rounding....... : Minus nine trillion
Informal with fraction 1 : Minus nine trillion plus
Informal with fraction 1 : Minus nine point two hundred and twenty-three trillion
Informal with fraction 2 : Minus nine point two two three trillion


------------------------------------------------
VALUE: 9,223,372,036,854,775
TEXT:  Nine billard, two hundred and twenty-three billion, three hundred and seventy-two millard, thirty-six million, eight hundred and fifty-four thousand, seven hundred and seventy-five

... or, to simplify very large numbers ...

Rounded................. : Nine billard
Rounded with fraction 1. : Nine billard plus
Rounded with fraction 2. : Nine point two hundred and twenty-three billard
Rounded with fraction 3. : Nine point two two three billard
Informal rounding....... : Nine billiard
Informal with fraction 1 : Nine billiard plus
Informal with fraction 1 : Nine point two hundred and twenty-three billiard
Informal with fraction 2 : Nine point two two three billiard


------------------------------------------------
VALUE: 9,223,372,036,854,775,807
TEXT:  Nine trillion, two hundred and twenty-three billard, three hundred and seventy-two billion, thirty-six millard, eight hundred and fifty-four million, seven hundred and seventy-five thousand, eight hundred and seven

... or, to simplify very large numbers ...

Rounded................. : Nine trillion
Rounded with fraction 1. : Nine trillion plus
Rounded with fraction 2. : Nine point two hundred and twenty-three trillion
Rounded with fraction 3. : Nine point two two three trillion
Informal rounding....... : Nine trillion
Informal with fraction 1 : Nine trillion plus
Informal with fraction 1 : Nine point two hundred and twenty-three trillion
Informal with fraction 2 : Nine point two two three trillion


------------------------------------------------
VALUE: 18,446,744,073,709,551
TEXT:  Eighteen billard, four hundred and forty-six billion, seven hundred and forty-four millard, seventy-three million, seven hundred and nine thousand, five hundred and fifty-one

... or, to simplify very large numbers ...

Rounded................. : Eighteen billard
Rounded with fraction 1. : Eighteen billard plus
Rounded with fraction 2. : Eighteen point four hundred and forty-six billard
Rounded with fraction 3. : Eighteen point four four six billard
Informal rounding....... : Eighteen billiard
Informal with fraction 1 : Eighteen billiard plus
Informal with fraction 1 : Eighteen point four hundred and forty-six billiard
Informal with fraction 2 : Eighteen point four four six billiard


------------------------------------------------
VALUE: 18,446,744,073,709,551,615
TEXT:  Eighteen trillion, four hundred and forty-six billard, seven hundred and forty-four billion, seventy-three millard, seven hundred and nine million, five hundred and fifty-one thousand, six hundred and fifteen

... or, to simplify very large numbers ...

Rounded................. : Eighteen trillion
Rounded with fraction 1. : Eighteen trillion plus
Rounded with fraction 2. : Eighteen point four hundred and forty-six trillion
Rounded with fraction 3. : Eighteen point four four six trillion
Informal rounding....... : Eighteen trillion
Informal with fraction 1 : Eighteen trillion plus
Informal with fraction 1 : Eighteen point four hundred and forty-six trillion
Informal with fraction 2 : Eighteen point four four six trillion


------------------------------------------------
VALUE: -28,638,903,918,474,948,771,853,900,789,600,176,813,374,560,672,787,905,549,951,087,488,011,382,049,361,477,907,432,468,077,275,919,439,086,145,725,268,599,727,509,261,609,545,191,934,342,376,096,106,426,327,812,926,262,086,834,977,087,858,680,322,241,546,113,514,383,143,501,519,151
TEXT:  Minus twenty-eight quingentilliard, six hundred and thirty-eight quinquagintaquadringentilliard, nine hundred and three quadringentilliard, nine hundred and eighteen quinquagintatrecentilliard, four hundred and seventy-four trecentilliard, nine hundred and forty-eight quinquagintaducentilliard, seven hundred and seventy-one ducentilliard, eight hundred and fifty-three quinquagintacentilliard, nine hundred centilliard, seven hundred and eighty-nine quinquanonagintilliard, six hundred nonagintilliard, one hundred and seventy-six quinquaoctogintilliard, eight hundred and thirteen octogintilliard, three hundred and seventy-four quinquaseptuagintilliard, five hundred and sixty septuagintilliard, six hundred and seventy-two quinquasexagintilliard, seven hundred and eighty-seven unsexagintillion, nine hundred and five sexagintilliard, five hundred and forty-nine sesquinquagintillion, nine hundred and fifty-one quinquaquinquagintilliard, eighty-seven duoquinquagintillion, four hundred and eighty-eight unquinquagintilliard, eleven unquinquagintillion, three hundred and eighty-two quinquagintilliard, forty-nine quinquaquadragintilliard, three hundred and sixty-one quadragintilliard, four hundred and seventy-seven quinquatrigintilliard, nine hundred and seven trigintilliard, four hundred and thirty-two quinquavigintilliard, four hundred and sixty-eight vigintilliard, seventy-seven vigintillion, two hundred and seventy-five novendecilliard, nine hundred and nineteen novendecillion, four hundred and thirty-nine octodecilliard, eighty-six octodecillion, one hundred and forty-five septendecilliard, seven hundred and twenty-five septendecillion, two hundred and sixty-eight sedecilliard, five hundred and ninety-nine sedecillion, seven hundred and twenty-seven quindecilliard, five hundred and nine quindecillion, two hundred and sixty-one quattuordecilliard, six hundred and nine quattuordecillion, five hundred and forty-five tredecilliard, one hundred and ninety-one tredecillion, nine hundred and thirty-four duodecilliard, three hundred and forty-two duodecillion, three hundred and seventy-six undecilliard, ninety-six undecillion, one hundred and six decilliard, four hundred and twenty-six decillion, three hundred and twenty-seven nonilliard, eight hundred and twelve nonillion, nine hundred and twenty-six octilliard, two hundred and sixty-two octillion, eighty-six septilliard, eight hundred and thirty-four septillion, nine hundred and seventy-seven sextilliard, eighty-seven sextillion, eight hundred and fifty-eight quintilliard, six hundred and eighty quintillion, three hundred and twenty-two quadrilliard, two hundred and forty-one quadrillion, five hundred and forty-six trilliard, one hundred and thirteen trillion, five hundred and fourteen billard, three hundred and eighty-three billion, one hundred and forty-three millard, five hundred and one million, five hundred and nineteen thousand, one hundred and fifty-one

... or, to simplify very large numbers ...

Rounded................. : Minus twenty-eight quingentilliard
Rounded with fraction 1. : Minus twenty-eight quingentilliard plus
Rounded with fraction 2. : Minus twenty-eight point six hundred and thirty-eight quingentilliard
Rounded with fraction 3. : Minus twenty-eight point six three eight quingentilliard
Informal rounding....... : Minus twenty-eight bazintillion
Informal with fraction 1 : Minus twenty-eight bazintillion plus
Informal with fraction 1 : Minus twenty-eight point six hundred and thirty-eight bazintillion
Informal with fraction 2 : Minus twenty-eight point six three eight bazintillion


------------------------------------------------
VALUE: 28,638,903,918,474,948,771,853,900,789,600,176,813,374,560,672,787,905,549,951,087,488,011,382,049,361,477,907,432,468,077,275,919,439,086,145,725,268,599,727,509,261,609,545,191,934,342,376,096,106,426,327,812,926,262,086,834,977,087,858,680,322,241,546,113,514,383,143,501,519,151
TEXT:  Twenty-eight quingentilliard, six hundred and thirty-eight quinquagintaquadringentilliard, nine hundred and three quadringentilliard, nine hundred and eighteen quinquagintatrecentilliard, four hundred and seventy-four trecentilliard, nine hundred and forty-eight quinquagintaducentilliard, seven hundred and seventy-one ducentilliard, eight hundred and fifty-three quinquagintacentilliard, nine hundred centilliard, seven hundred and eighty-nine quinquanonagintilliard, six hundred nonagintilliard, one hundred and seventy-six quinquaoctogintilliard, eight hundred and thirteen octogintilliard, three hundred and seventy-four quinquaseptuagintilliard, five hundred and sixty septuagintilliard, six hundred and seventy-two quinquasexagintilliard, seven hundred and eighty-seven unsexagintillion, nine hundred and five sexagintilliard, five hundred and forty-nine sesquinquagintillion, nine hundred and fifty-one quinquaquinquagintilliard, eighty-seven duoquinquagintillion, four hundred and eighty-eight unquinquagintilliard, eleven unquinquagintillion, three hundred and eighty-two quinquagintilliard, forty-nine quinquaquadragintilliard, three hundred and sixty-one quadragintilliard, four hundred and seventy-seven quinquatrigintilliard, nine hundred and seven trigintilliard, four hundred and thirty-two quinquavigintilliard, four hundred and sixty-eight vigintilliard, seventy-seven vigintillion, two hundred and seventy-five novendecilliard, nine hundred and nineteen novendecillion, four hundred and thirty-nine octodecilliard, eighty-six octodecillion, one hundred and forty-five septendecilliard, seven hundred and twenty-five septendecillion, two hundred and sixty-eight sedecilliard, five hundred and ninety-nine sedecillion, seven hundred and twenty-seven quindecilliard, five hundred and nine quindecillion, two hundred and sixty-one quattuordecilliard, six hundred and nine quattuordecillion, five hundred and forty-five tredecilliard, one hundred and ninety-one tredecillion, nine hundred and thirty-four duodecilliard, three hundred and forty-two duodecillion, three hundred and seventy-six undecilliard, ninety-six undecillion, one hundred and six decilliard, four hundred and twenty-six decillion, three hundred and twenty-seven nonilliard, eight hundred and twelve nonillion, nine hundred and twenty-six octilliard, two hundred and sixty-two octillion, eighty-six septilliard, eight hundred and thirty-four septillion, nine hundred and seventy-seven sextilliard, eighty-seven sextillion, eight hundred and fifty-eight quintilliard, six hundred and eighty quintillion, three hundred and twenty-two quadrilliard, two hundred and forty-one quadrillion, five hundred and forty-six trilliard, one hundred and thirteen trillion, five hundred and fourteen billard, three hundred and eighty-three billion, one hundred and forty-three millard, five hundred and one million, five hundred and nineteen thousand, one hundred and fifty-one

... or, to simplify very large numbers ...

Rounded................. : Twenty-eight quingentilliard
Rounded with fraction 1. : Twenty-eight quingentilliard plus
Rounded with fraction 2. : Twenty-eight point six hundred and thirty-eight quingentilliard
Rounded with fraction 3. : Twenty-eight point six three eight quingentilliard
Informal rounding....... : Twenty-eight bazintillion
Informal with fraction 1 : Twenty-eight bazintillion plus
Informal with fraction 1 : Twenty-eight point six hundred and thirty-eight bazintillion
Informal with fraction 2 : Twenty-eight point six three eight bazintillion


-- Press any key to exit --
 
Share this answer
 
v11
Comments
PIEBALDconsult 13-Jan-17 16:29pm    
"You didn't specify the range of ints to be tested or the Scale Mode[^]. "

If'n I recall correctly, my version supports both scales, but I'll have to review it when I get home.
Graeme_Grant 13-Jan-17 21:24pm    
Really ...
PIEBALDconsult 13-Jan-17 21:31pm    
Seriously. And multiple languages and stuff. Seems I wrote it more than three years ago and haven't touched it since. It needs work.
Graeme_Grant 14-Jan-17 23:18pm    
I guess that it would not be hard to add languages. This version is not hard-coded, so very easy to add support for any number naming system including languages - I have two different number formats each with its own set of naming types.
PIEBALDconsult 16-Jan-17 16:56pm    
Except languages (e.g. German) that use four-and-twenty (vier-und-zwanzig) -- mine can't do that.
In our main application we have a feature to print payment vouchers, which have to contain the amount in numbers and words too (by law)...
First I thought to bring here one of the older versions (we have COBOL, C++, VB6 and C#), but I found that the my quick JavaScript version is so ugly, that can satisfy the masochism of Chris an Co.
JavaScript
var minus = 'minus ';
var ones = ['zero', 'one', 'two', ' three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
var tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety', 'hundred'];
var scales = ['', '', 'thousand', 'million', 'billion', 'trillion', 'quadrillion', 'quintillion', 'sextillion', 'septillion', 'octillion', 'nonillion', 'decillion', 'undecillion', 'duodecillion', 'tredecillion']; // 10^42

function run() {
    var inEl = document.getElementById('in');
    var outEl = document.getElementById('out');

    outEl.innerHTML = convert(inEl.value);
}

function convert(num) {
    if (isNaN(num)) {
        return ('NaN');
    }
    else if (num == 0) {
        return (ones[0])
    }
    else {
        var len = num.toString().length;
        if (len > 0) {
            var word = '';

            if (num[0] == '-') {
                word += minus;
                num = num.substr(1);
                len--;
            }

            var str = Array.apply(null, Array((Math.ceil(len / 3) * 3) - len)).map(Number.prototype.valueOf, 0).join('') + num;
            var part = str.match(/([0-9]{3})/g);

            for (var i = 0; i < part.length; i++) {
                var n = part[i].match(/([0-9])/g);

                word += n[0] > 0 ? ones[n[0]] + ' ' + tens[10] + ' ' : '';
                word += n[1] > 1 ? tens[n[1]] + ' ' : n[1] > 0 ? ones[n[1] + n[2]] + ' ' : '';
                word += n[1] != 1 && n[2] != 0 ? ones[n[2]] + ' ' : '';

                word += scales[part.length - i] + ' ';
            }

            return (word);
        }
        else {
            return ('NaN');
        }
    }
}


In theory it can handle any size of number, but it depends on the array of scale names, which I created up to 1042 - Tredecillion...
And yes, I did string manipulation to handle any size... and yes I used string indexes... and regular expressions... and in most cases I used deliberately complicated syntax... Enjoy...

[EDIT]
Graeme_Grant is so pedant, that I had to update my code to support negative and zero too... :-)
 
Share this answer
 
v5
Comments
Graeme_Grant 15-Jan-17 7:19am    
Try using these numbers: -1,001,010,101, 0 - all valid Int64 values.
Kornfeld Eliyahu Peter 15-Jan-17 7:25am    
I do not care for - (minus), but for the number it prints: one billion one million ten thousand one hundred one
Graeme_Grant 15-Jan-17 7:32am    
Using the code posted I got: one hundred million one hundred one thousand ten instead of minus one billion one million ten thousand one hundred one
Kornfeld Eliyahu Peter 15-Jan-17 7:41am    
As I told - I DO NOT CARE for minus (-) - I'm unsigned :-)
Kornfeld Eliyahu Peter 15-Jan-17 7:26am    
For 9,223,372,036,854,775 it returns: nine quadrillion two hundred twenty three trillion three hundred seventy two billion thirty six million eight hundred fifty four thousand seven hundred seventy five
Assuming the range is from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807.
I modified the code last minute to include Unsigned 64-bit integer. Show below are the codes and output.

Output:
------------ Text Data ------------------
Input: 9223372036854775807
Output: Nine Quintillion, Two Hundred Twenty-Three Quadrillion, Three Hundred Seventy-Two Trillion, Thirty-Six Billion, Eight Hundred Fifty-Four Million, Seven Hundred Seventy-Five Thousand, Eight Hundred and Seven
------------------------------------------
Input: 9
Output: Nine
------------------------------------------
Input: -890008509
Output: Minus Eight Hundred Ninety Million, Eight Thousand, Five Hundred and Nine
------------------------------------------
Input: 10000000001001
Output: Ten Trillion, One Thousand and One
------------------------------------------
Input: 18446744073709551615
Output: Eighteen Quintillion, Four Hundred Forty-Six Quadrillion, Seven Hundred Forty-Four Trillion, Seventy-Three Billion, Seven Hundred Nine Million, Five Hundred Fifty-One Thousand, Six Hundred and Fifteen
------------ End Text Data ------------------

Enter some integer:
18,446,744,073,709,551,615
Eighteen Quintillion, Four Hundred Forty-Six Quadrillion, Seven Hundred Forty-Four Trillion, Seventy-Three Billion, Seven Hundred Nine Million, Five Hundred Fifty-One Thousand, Six Hundred and Fifteen
Enter some integer:
1,023
One Thousand and Twenty-Three
Enter some integer:
10010
Ten Thousand and Ten
Enter some integer:
100100
One Hundred  Thousand, One Hundred
Enter some integer:
-9001001
Minus Nine Million, One Thousand and One
Enter some integer:
8,000,000,001
Eight Billion and One
Enter some integer:
8,000,080,001
Eight Billion, Eighty Thousand and One
Enter some integer:
0
Zero
Enter some integer:
001
One


C#
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Speech.Synthesis;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static IList<string> singleNumber = new List<string>()
            {
                "", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"
            };

        static IList<string> twoNumber = new List<string>()
            {
               "", "Eleven","Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"
            };

        static IList<string> multipleOfTen = new List<string>()
            {
               "", "Ten","Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"
            };

        static IList<string> numberScales = new List<string>()
            {
                "Hundred","Thousand", "Million", "Billion", "Trillion", "Quadrillion", "Quintillion", "Seven", "Sextillion", "Septillion"
            };


        static void Main(string[] args)
        {
            CultureInfo provider = new CultureInfo("en-US"); ;

            Console.WriteLine("------------ Text Data ------------------");
            Console.WriteLine("Input: " + Int64.MaxValue.ToString());
            Console.WriteLine("Output: " + IntegerToSentence(Int64.MaxValue));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + 9);
            Console.WriteLine("Output: " + IntegerToSentence(9));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + -890008509);
            Console.WriteLine("Output: " + IntegerToSentence(-890008509));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + "10000000001001");
            Console.WriteLine("Output: " + IntegerToSentence(10000000001001));
            Console.WriteLine("------------------------------------------");
            Console.WriteLine("Input: " + UInt64.MaxValue.ToString());
            Console.WriteLine("Output: " + IntegerToSentence(UInt64.MaxValue));
            Console.WriteLine("------------ End Text Data ------------------");
            Console.WriteLine();

            bool exit = false;
            Int64 userInput = 0;
            UInt64 userInputUnsigned = 0;
            do
            {
                Console.WriteLine("Enter some integer:");

                string result = Console.ReadLine();
                if (string.IsNullOrEmpty(result))
                {
                    exit = true;
                }
                else
                {

                    if (Int64.TryParse(result, NumberStyles.AllowThousands | NumberStyles.AllowLeadingSign, provider, out userInput))
                    {
                        Console.WriteLine(IntegerToSentence(userInput));
                    }
                    else if (UInt64.TryParse(result, NumberStyles.AllowThousands, provider, out userInputUnsigned))
                    {
                        Console.WriteLine(IntegerToSentence(userInputUnsigned));
                    }
                    else
                    {
                        Console.WriteLine("Integer only!");
                    }
                }

            } while (!exit);
        }

        //handle case 2, remove code redundancy
        static string IntegerToSentenceHelper(int firstElement, int secondElement, ref string output, ref IEnumerable<string> subGroupIntegers)
        {
            if (subGroupIntegers.ElementAt(firstElement) == "1")
            {
                if (subGroupIntegers.ElementAt(secondElement) == "0")
                {
                    output += multipleOfTen.ElementAt(int.Parse(subGroupIntegers.ElementAt(firstElement))) + " ";
                }
                else
                {
                    output += twoNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(secondElement))) + " ";
                }
            }
            else
            {
                //twenty
                output += multipleOfTen.ElementAt(int.Parse(subGroupIntegers.ElementAt(firstElement)));

                if (int.Parse(subGroupIntegers.ElementAt(1)) > 1 && int.Parse(subGroupIntegers.ElementAt(secondElement)) > 0)
                {
                    output += "-";
                }

                //three
                output += singleNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(secondElement)));
            }

            return output;
        }

        static string IntegerToSentence<T>(T input, bool unsigned = false)
        {
            string output = string.Empty;
            var listInteger = input.GroupInteger<T>();

            int j = 0;
            //minus sign
            if (listInteger.Item1)
            {
                output += "Minus ";
            }
            //number of group
            j = listInteger.Item2.Count - 1;

            //loop over the List
            while (j >= 0)
            {
                //group the integer into 1 number per group and return as Tuple<bool,List>
                var subGroup = Convert.ToInt64(listInteger.Item2[j]).GroupInteger(1);

                //example: 123
                var subGroupIntegers = subGroup.Item2.Reverse();

                //handle 100
                if (int.Parse(string.Join("", subGroupIntegers.ToArray())) > 0 && j != listInteger.Item2.Count - 1)
                {
                    //make sure the last three integer are in the hundreds before appending a comma
                    if (j == 0)
                    {
                        if (int.Parse(string.Join("", subGroupIntegers.ToArray())) > 99)
                        {
                            output += ", ";
                        }
                    }
                    else
                    {
                        output += ", ";
                    }
                }

                switch (subGroupIntegers.Count())
                {
                    case 3:
                        //one
                        output += singleNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(0))) + " ";

                        //hundred
                        output += numberScales[0] + " ";

                        if (j == 0 && int.Parse(subGroupIntegers.ElementAt(1) + subGroupIntegers.ElementAt(2)) > 0)
                        {
                            output += " and ";
                        }

                        if (subGroupIntegers.ElementAt(1) == "0")
                        {
                            output += singleNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(2))) + " ";
                        }
                        else
                        {
                            IntegerToSentenceHelper(1, 2, ref output, ref subGroupIntegers);
                        }

                        if (j > 0)
                        {
                            output += " " + numberScales[j] + " ";
                        }

                        break;
                    case 2:
                        //avoid "and Integer"
                        if (j == 0 && listInteger.Item2.Count > 1)
                        {
                            output += " and ";
                        }

                        IntegerToSentenceHelper(0, 1, ref output, ref subGroupIntegers);

                        if (j > 0)
                        {
                            output += " " + numberScales[j] + " ";
                        }

                        break;
                    default:
                        if (int.Parse(subGroupIntegers.ElementAt(0)) > 0)
                        {
                            if (j == 0 && listInteger.Item2.Count > 1)
                            {
                                output += " and ";
                            }

                            output += singleNumber.ElementAt(int.Parse(subGroupIntegers.ElementAt(0)));

                            if (j > 0)
                            {
                                output += " " + numberScales[j] + " ";
                            }
                        }

                        //zero hack
                        //user enter 0
                        if (int.Parse(subGroupIntegers.ElementAt(0)) == 0 && listInteger.Item2.Count == 1)
                        {
                            output = "Zero";
                        }

                        break;
                }

                j--;
            }
            //cleanup extra spaces
            return output.Replace("  ", " ").Replace(" ,", ",");
        }

    }
}


Extension class

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    public static class Utility
    {
        /// <summary>
        /// Group the integer from right to left, save it to a List
        /// </summary>
        /// <param name="input"></param>
        /// <param name="groupLength"></param>
        /// <returns></returns>
        public static Tuple<bool, IList<string>> GroupInteger<T>(this T input, int groupLength = 3)
        {
            string userInput = input.ToString().Trim();
            bool isNegative = userInput.Contains("-");

            //remove negative
            userInput = userInput.Replace("-", "");

            int inputLength = userInput.Length;
            int startIndex = 0, length = 0;

            IList<string> groupNumbers = new List<string>();

            string inputGroup = string.Empty;

            //read from right to left
            //group 3 digit from right to left
            while (inputLength > 0)
            {
                inputLength = inputLength - groupLength;

                if (inputLength < 0)
                {
                    startIndex = 0;
                    length = groupLength + inputLength;
                }
                else
                {
                    startIndex = inputLength;
                    length = groupLength;
                }

                inputGroup = userInput.Substring(startIndex, length);

                groupNumbers.Add(inputGroup);
            }

            Tuple<bool, IList<string>> listNumbers = new Tuple<bool, IList<string>>(isNegative, groupNumbers);

            return listNumbers;
 
        }
    }
}
 
Share this answer
 
v6
Here is a Word 2010+ (tested on Word 2013) VBA macro that will handle positive and negative Int64 numbers.

As the VBA Macro works with a word document, it is designed to check that a number is under/beside the cursor or is selected. It will correctly identify if the number is denoted as negative (NOTE: '-' dash, not minus, is a separate word entity and not part of the number) and replace the whole number (including the dash, if present) with a worded version. If a word is selected, not a number, then the macro will do nothing.

The VBA Macro has several entry points depending on if the number is to be worded in full or rounded. There are 3 scale modes: (Short/modern/US, Long, or British Traditional); plus 4 versions of rounding: None (nearest whole scale - eg: one million), Rounded (same as none or plus - eg: one million plus), Short (eg: one point one hundred and one million), or Long (eg: one point one zero one million).

Instructions on how to use the macro are at the end of the VBA Macro source code. If you want to run it quickly, then use the method NumberToWords after entering and selecting the number in your word document.

Enjoy!

VB
' NOTE: Requires Word 2010 or newer due to LongLong (64-bit integer) support
'
' Instructions are at the end of the source code.
'
Dim singleScale() As String
Dim tensScale() As String
Dim shortScale() As String
Dim longScale() As String
Dim traditionalScale() As String

Dim zero As String
Dim hundred As String

Enum ScaleType
    Short
    [Long]
    TraditionalBritish
End Enum

Enum FractionType
    None
    Rounded
    Short
    [Long]
End Enum

'---------------------------------------
' NUMBER TO WORDS
'
Public Sub NumberToWords()
    Call NumToWords(ScaleType.Short)
End Sub

Public Sub NumberToLongWords()
    Call NumToWords(ScaleType.Long)
End Sub

Public Sub NumberToTraditionalBritishWords()
    Call NumToWords(ScaleType.TraditionalBritish)
End Sub

Private Sub NumToWords(mode As ScaleType)
    Dim num As LongLong
    If (TryParseNumber(num)) Then
        Selection = ToWords(num, mode)
        'Selection = CaptalizeFirstLetter(ToWords(num, mode))
    End If
End Sub

Private Function ToWords(num As LongLong, mode As ScaleType) As String
    
    Call InitWords

    If num = 0 Then
        ToWords = "zero"
        Exit Function
    End If
    
    isEval = False
    words = ""
    
    If num < 0 Then
        words = words & "minus "
        num = -num
    End If
    
    ' break up the number
    Dim groups() As String
    groups = Split(StrReverse(Format(num, "#,##0")), ",")
    If UBound(groups) > 7 Then
        ToWords = "A friggin huge number!"
        Exit Function
    End If
    
    ' spell it out
    Dim i As Integer
    maxGroups = UBound(groups) - LBound(groups)
    For i = maxGroups To LBound(groups) Step -1
        
        isPart = False: isJoin = False: isHyphen = False
        digits = GetDigits(groups(i))
        maxdigits = UBound(digits) - LBound(digits)
        
        For J = maxdigits To LBound(digits) Step -1
            
            index = digits(J)
            If index > 0 Then
                
                If (Not isHyphen) And (isJoin Or (i = 0 And isEval) And J < 2) Then
                    If Right(words, 1) = "," Then
                        Mid(words, Len(words) - 1, 1) = " "
                    Else
                        words = FixSpace(words)
                    End If
                    words = words & "and "
                    isJoin = False
                End If
                
                If J = 2 Or J = 0 Then ' singles
                    If words <> "" Then
                        If isHyphen Then words = words & "-"
                    Else
                        words = FixSpace(words)
                    End If
                    words = words & singleScale(index) & " "
                    isPart = True
                End If
                
                If J = 2 Then ' hundreds
                    words = words & hundred
                    isPart = True
                    isJoin = True
                End If
                
                If J = 1 Then ' tens
                    If words <> "" Then
                        words = FixSpace(words)
                    End If
                    If index = 1 Then
                        words = words & singleScale(10 + digits(J - 1)) & " "
                        J = J - 1 ' single handled
                    Else
                        words = words & tensScale(index - 1)
                        isHyphen = True
                    End If
                    isPart = True
                End If
            
            End If
            isPart = isPart And i > 0
        Next
        
        If isPart Then ' number scale
            words = FixSpace(words) & GetScaleText(i, mode) & ", "
        End If
        isEval = isEval Or isPart
        
    Next
    
    ToWords = Trim(words)

End Function

'---------------------------------------
' ABBREVIATED/ROUNDED NUMBER TO WORDS
'
Public Sub ToRoundedWords()
    Call RoundedWords(ScaleType.Short, FractionType.Rounded)
End Sub

Public Sub ToShortRoundedWords()
    Call RoundedWords(ScaleType.Short, FractionType.Short)
End Sub

Public Sub ToLongRoundedWords()
    Call RoundedWords(ScaleType.Short, FractionType.Long)
End Sub

Public Sub ToRoundedLongWords()
    Call RoundedWords(ScaleType.Long, FractionType.Rounded)
End Sub

Public Sub ToShortRoundedLongWords()
    Call RoundedWords(ScaleType.Long, FractionType.Short)
End Sub

Public Sub ToLongRoundedLongWords()
    Call RoundedWords(ScaleType.Long, FractionType.Long)
End Sub

Public Sub ToRoundedTradBritishWords()
    Call RoundedWords(ScaleType.TraditionalBritish, FractionType.Rounded)
End Sub

Public Sub ToShortRoundedTradBritishWords()
    Call RoundedWords(ScaleType.TraditionalBritish, FractionType.Short)
End Sub

Public Sub ToLongRoundedTradBritishWords()
    Call RoundedWords(ScaleType.TraditionalBritish, FractionType.Long)
End Sub

Private Sub RoundedWords(mode As ScaleType, rounding As FractionType)
    Dim num As LongLong
    If (TryParseNumber(num)) Then
        Selection = ToRoundedScale(num, mode, rounding)
        'Selection = CaptalizeFirstLetter(ToRoundedScale(num, mode, rounding))
    End If
End Sub

Private Function ToRoundedScale(num As LongLong, mode As ScaleType, rounding As FractionType)

    ' Is the number big enough to abbreviate?
    If (num > -1000001 And num < 1000001) Then
        ToRoundedScale = ToWords(num, mode)
        Exit Function
    End If
    
    Call InitWords
    
    words = ""
    If num < 0 Then
        words = words & "minus "
        num = -num
    End If

    ' Break up the number
    Dim groups() As String
    groups = Split(StrReverse(Format(num, "#,##0")), ",")
    If UBound(groups) > 6 Then
        ToRoundedScale = "A friggin huge number!"
        Exit Function
    End If
    Count = (UBound(groups)) * 3
    
    ' integer part
    words = words & ToWords(CInt(num / (10 ^ Count)), mode)

    ' fraction part
    fraction = StrReverse(groups(UBound(groups) - 1))
    If rounding <> FractionType.None Then
        words = words & AppendFraction(fraction, rounding)
    End If
    
    ' scale
    words = FixSpace(words) & GetScaleText(Count / 3, mode)
    
    ' rounded fraction?
    If rounding = FractionType.Rounded And Not fraction = "000" Then
        words = words & " plus"
    End If

   ToRoundedScale = words

End Function

'---------------------------------------
' SUPPORTING METHODS
'

Private Function TryParseNumber(ByRef num As LongLong)

    If Trim(Selection) = "" Or Selection = vbCr Then
        ' Check to see if we are just to the
        ' right of the number...
        Selection.MoveLeft unit:=wdCharacter, Count:=1
        If IsNumeric(Selection) Then
            ' Process the number
            TryParseNumber = TryParseNumber(num)
        Else
            ' Not a number, so put the cursor back
            ' where we found it... Move along, nothing to see...
            Selection.MoveRight unit:=wdCharacter, Count:=1
        End If
        
    ElseIf IsNumeric(Selection) Then
        ' We have a number to process...
        Application.Selection.words(1).Select
        num = CLngLng(Selection)
        Selection = ""
        ' check to see if the number is negative
        Selection.MoveLeft unit:=wdCharacter, Count:=1
        If Selection = "-" Then
            num = -num
            Application.Selection.words(1).Select
            Selection = ""
        Else
            ' Not negative, so move cursor back...
            Selection.MoveRight unit:=wdCharacter, Count:=1
        End If
        
        ' We have a valid number...
        TryParseNumber = True

    ElseIf Selection = "-" Then
        ' Do we have a negative number?
        Selection.MoveRight unit:=wdCharacter, Count:=1
        If IsNumeric(Selection) Then
            ' Process the negative number
            TryParseNumber = TryParseNumber(num)
        Else
            ' Not a number, so put the cursor back
            ' where we found it... Move along, nothing to see...
            Selection.MoveLeft unit:=wdCharacter, Count:=1
        End If
    End If

End Function

Private Sub InitWords()
    
    If zero = "" Then
        singleScale = Split("zero,one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen,fifteen,sixteen,seventeen,eighteen,nineteen", ",")
        tensScale = Split(",twenty,thirty,forty,fifty,sixty,seventy,eighty,ninety", ",")
        shortScale = Split("hundred,thousand,million,billion,trillion,quadrillion,quintillion", ",")
        longScale = Split("hundred,thousand,million,millard,billion,billard,trillion", ",")
        traditionalScale = Split("hundred,thousand,million,thousand million,billion,thousand billion,trillion", ",")

        zero = singleScale(0)
        hundred = shortScale(0)
    End If

End Sub

Private Function GetScaleText(index As Integer, mode As ScaleType) As String

    Select Case mode
        Case ScaleType.Long
            GetScaleText = longScale(index)
        Case ScaleType.TraditionalBritish
            GetScaleText = traditionalScale(index)
        Case Else
            GetScaleText = shortScale(index)
    End Select
    
End Function

Private Function AppendFraction(ByVal fraction As String, rounding As FractionType) As String

    ' safety check
    If fraction = "000" Or rounding = FractionType.Rounded Then
        AppendFraction = words
        Exit Function
    End If
    words = FixSpace(words) & "point "
    
    Dim part As String
    part = TrimEnd(fraction, "0")
    value = CInt(part)
    c = GetDigits(part)
    
    If rounding = FractionType.Short And c(0) <> 0 And value > 9 Then
        words = words & ToWords(CLngLng(value), ScaleType.Short)
    Else
        For i = LBound(c) To UBound(c)
            words = words & singleScale(c(i)) & " "
        Next
    End If
    
    AppendFraction = words

End Function

'---------------------------------------
' UTILITY METHODS
'

Private Function TrimEnd(text As String, remove As String)
    TrimEnd = text
    tLen = Len(remove)
    If Right(text, tLen) = remove Then
        TrimEnd = Left(text, Len(text) - tLen)
    End If
End Function

Private Function FixSpace(ByVal words As String) As String
    
    If Right(words, 1) <> " " Then
        FixSpace = words & " "
    Else
        FixSpace = words
    End If

End Function

Private Function GetDigits(value As String) As Integer()
    GetDigits = IntArray(charArray(value))
End Function

Private Function IntArray(chars() As String) As Integer()
    
    max = UBound(chars) - LBound(chars)
    
    Dim ints() As Integer
    ReDim ints(max)
    
    For i = LBound(chars) To max
        ints(i) = CInt(chars(i))
    Next
    IntArray = ints

End Function

Private Function charArray(value As String) As String()
    value = StrConv(value, vbUnicode)
    Dim vals() As String
    vals = Split(Left(value, Len(value) - 1), vbNullChar)
    charArray = vals
End Function

Private Function StrReverse(text As String) As String
    textout = ""
    For J = 1 To Len(text)
        textout = Mid(text, J, 1) & textout
    Next
    StrReverse = textout
End Function

Private Function CaptalizeFirstLetter(words As String) As String
    CaptalizeFirstLetter = UCase(Mid(words, 1, 1)) & LCase(Mid(words, 2))
End Function

'---------------------------------------
' INSTRUCTIONS
'
' To try out:
' 1. Run MS Word
' 2. Copy & paste this macro into a new
'     module (View > Macros >
'     View Macros > Edit)
' 3. Go to a document, enter a valid
'     Int64 number with no commas
'     (-9,223,372,036,854,775,808 to
'      9,223,372,036,854,775)
' 4. Click on (cursor anywhere in number
'     text) or select the number
' 5. Run a Macro (View > Macros >
'     View Macros > "select a macro" >
'     Run)
'
' There are 3 normal formats:
'     * NumberToWords (short)
'     * NumberToLongWords
'     * NumberToTraditionalBritishWords
'
' There are 9 rounded formats:
'     * ToRoundedWords
'     * ToShortRoundedWords
'     * ToLongRoundedWords
'     * ToRoundedLongWords
'     * ToShortRoundedLongWords
'     * ToLongRoundedLongWords
'     * ToRoundedTradBritishWords
'     * ToShortRoundedTradBritishWords
'     * ToLongRoundedTradBritishWords
'
' When executed the number will be
'  replaced with words. Enjoy! :)


Download Link: NumberToWord[^] MS Word Document
 
Share this answer
 
v2
Numbers to French letters. Clipper (FoxPro) once again.
VB
*   CCCP Code Challenge Code Project
* Chiffres en lettres
local scan
clear
test= {-1, 0, 1, 61, 71, 81, 91, 180, 200, 3000, 3000000, 1234, 12345, 1234567890123456}

for scan= 1 to len(test)
	? test[scan]
	? i2l(test[scan])
next
return

function i2l(nb)
	private rep, set
	rep=""
	sep=" "
	if nb < 0
		concat("moins")
		nb= abs(nb)
	endif
	if nb = 0
		concat("zéro")
	endif
	
	tranche= int(nb/1000000000000)
	nb= nb % 1000000000000
	if tranche != 0
		concat(i2lm(tranche))
		if tranche > 1 .and. nb=0
			concat("billions")
		else
			concat("billion")
		endif
	endif
	
	tranche= int(nb/1000000000)
	nb= nb % 1000000000
	if tranche != 0
		concat(i2lm(tranche))
		if tranche > 1 .and. nb=0
			concat("milliards")
		else
			concat("milliard")
		endif
	endif
	
	tranche= int(nb/1000000)
	nb= nb % 1000000
	if tranche != 0
		concat(i2lm(tranche))
		if tranche > 1 .and. nb=0
			concat("millions")
		else
			concat("million")
		endif
	endif
	
	tranche= int(nb/1000)
	nb= nb % 1000
	if tranche != 0
		if tranche != 1
			concat(i2lm(tranche))
		endif
		concat("mille")
	endif
	
	tranche= nb 
	if tranche != 0
		concat(i2lm(tranche))
		if tranche >= 200 .and. tranche % 100 = 0
			rep +="s"
		endif
		if tranche % 100 = 80
			rep +="s"
		endif
	endif
	return rep
	
function i2lm(nb)
	private rep, sep
	rep=""
	sep="-"
	du= nb % 100
	c= int(nb / 100)
	if c > 0
		if c > 1
			i2lv(c)
		endif
		concat("cent")
	endif
	do case
	case du >= 80
		concat("Quatre")
		concat("vingt")
		i2lv(du-80)
	case du >= 60
		concat("soixante")
		if du= 61 .or. du= 71
			concat("et")
		endif
		i2lv(du-60)
	case du >= 50
		concat("cinqante")
		if du= 51
			concat("et")
		endif
		i2lv(du-50)
	case du >= 40
		concat("quarante")
		if du= 41
			concat("et")
		endif
		i2lv(du-40)
	case du >= 30
		concat("trente")
		if du= 31
			concat("et")
		endif
		i2lv(du-30)
	case du >= 20
		concat("vingt")
		if du= 21
			concat("et")
		endif
		i2lv(du-20)
	otherwise
		i2lv(du)
	endcase
	return rep
	
procedure i2lv(nb)
	do case
	case nb= 0
	case nb= 1
		concat("un")
	case nb= 2
		concat("deux")
	case nb= 3
		concat("trois")
	case nb= 4
		concat("quatre")
	case nb= 5
		concat("cinq")
	case nb= 6
		concat("six")
	case nb= 7
		concat("sept")
	case nb= 8
		concat("huit")
	case nb= 9
		concat("neuf")
	case nb=10
		concat("dix")
	case nb=11
		concat("onze")
	case nb=12
		concat("douze")
	case nb=13
		concat("treize")
	case nb=14
		concat("quatorze")
	case nb=15
		concat("quinze")
	case nb=16
		concat("seize")
	otherwise
		i2lv(10)
		i2lv(nb-10)
	endcase
	return

procedure concat(st)
	if len(rep) != 0
		rep += sep
	endif
	rep += st
	return


-1
moins un
         0
zéro
         1
un
        61
soixante-et-un
        71
soixante-et-onze
        81
Quatre-vingt-un
        91
Quatre-vingt-onze
       180
cent-Quatre-vingts
       200
deux-cents
      3000
trois mille
   3000000
trois millions
      1234
mille deux-cent-trente-quatre
     12345
douze mille trois-cent-quarante-cinq
 1234567890123456
douze-cent-trente-quatre billion cinq-cent-soixante-sept milliard huit-cent-Quatre-vingt-dix million cent-vingt-trois mille quatre-cent-cinqante-six
 
Share this answer
 
v2
As ppolymorphe posted a French language version, I thought that I might have a go at Japanese.

Japanese is a bit different to English. To quote an extract from wikipedia.org[^]: "The Japanese numerals in writing are entirely based on the Chinese numerals and the grouping of large numbers follow the Chinese tradition of grouping by 10,000."

Update : Added Fluent support for ToPhonetic Extension Method to make the Japanese "characters" English phonetic readable.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Num2Japanese
{
    static class Program
    {
        static void Main(string[] args)
        {
            int[] tests =
                {
                -1,
                0,
                17,
                1001,
                151,
                302,
                469,
                1234,
                10001,
                2025,
                10000,
                100001,
                1100101,
                -9836703,
                9836703,
                10110011,
                100011011,
                1001010101,
                2036521801,
                -1001010101
                };

            Int64 testMin = Int64.MinValue;
            Int64 testMax = Int64.MaxValue;

            Console.OutputEncoding = Encoding.Unicode;

            for (int i = 0; i < tests.Length; i++)
                ShowResult(tests[i]);

            ShowResult(testMin);
            ShowResult(testMax);

            Console.WriteLine("-- Press any key to exit --");
            Console.ReadKey();
        }

        private static void ShowResult(Int16 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(UInt16 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(Int32 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(UInt32 value)
        {
            ShowResult((Int64)value);
        }

        private static void ShowResult(Int64 value)
        {
            var msg = value.ToJapanese();
            Console.WriteLine(seperatorLine);
            Console.WriteLine($"VALUE: {value:N0}{spacer}TEXT:  {msg}{spacer}Phonetic:  {msg.ToPhonetic()}{spacer}");
        }

        static string spacer = "\r\n";
        static string seperatorLine = "------------------------------------------------";
    }

    public static class NumberToWordsExtension
    {
        static List<string> singlesJScale = new List<string>() { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九" };
        static List<string> tensJScale = new List<string>() { "", "二十", "三十", "四十", "五十", "六十", "七十", "八十", "九十" };
        static List<string> shortJScale = new List<string>() { "百", "千", "万", "億", "兆", "京" };

        static List<string> singlesPhonetic = new List<string>() { "rei", "ichi", "ni", "san", "yon", "go", "roku", "nana", "hachi", "kyū", "jū", "jū-ichi", "jū-ni", "jū-san", "jū-yon", "jū-go", "jū-roku", "jū-nana", "jū-hachi", "jū-kyū" };
        static List<string> scalePhonetic = new List<string>() { "hyaku", "sen", "man", "oku", "chō", "kei", "gai", "jo" };
        static Dictionary<string, string> specialPhonetic = new Dictionary<string, string>() { { "三百", "san-byaku" }, { "六百", "rop-pyaku" }, { "八百", "hap-pyaku" }, { "千", "is-sen" }, { "三千", "san-zen" }, { "八千", "hassen" }, { "兆", "it-chō" }, { "八兆", "hat-chō" }, { "京", "ik-kei" }, { "六京", "rok-kei" }, { "八京", "hak-kei" } };
        static string zeroJ = singlesJScale[0];

        public static JString ToJapanese(this Int32 num)
            => ((Int64)num).ToJapanese();

        public static JString ToJapanese(this Int64 num)
        {
            // safety check
            if (num == 0) return new JString(zeroJ);

            var words = new StringBuilder();
            if (num < 0)
            {
                words.Append("− ");
                num = -num;
            }

            //break up the number
            var s = string.Concat(num.ToString().Reverse());
            var groups = s.Select((x, i) => i)
                          .Where(i => i % 4 == 0)
                          .Select(i => s.Substring(i, s.Length - i >= 4 ? 4 : s.Length - i))
                          .ToArray();

            if (groups.Length > 5)
                return new JString("申し訳ありませんが、数字が大きすぎます。"); // sorry the number is too big.

            for (int i = groups.Length; i > 0; i--)
            {
                bool isPart = false;
                int[] digits = groups[i - 1].Select(o => Convert.ToInt32(o) - 48).ToArray();
                for (int j = digits.Length; j > 0; j--)
                {
                    var index = digits[j - 1];
                    if (index > 0)
                    {
                        if ((index != 1 && j > 2) || j == 1)  // singles
                        {
                            words.Append(singlesJScale[index]);
                        }

                        if (j == 2) // tens
                        {
                            if (index == 1)
                                words.Append(singlesJScale[10 + digits[j-- - 2]]);
                            else
                                words.Append(tensJScale[index - 1]);
                        }

                        if (j == 3) // hundreds
                        {
                            words.Append(shortJScale[0]);
                        }

                        if (j == 4) // thousands
                        {
                            words.Append(shortJScale[1]);
                        }

                        isPart = true;
                    }
                    isPart = isPart && i > 1;
                }

                if (isPart) // number scale
                {
                    words.Append(shortJScale[i]).Append("  ");
                }
            }
            return new JString(words);
        }

        public static JString ToPhonetic(this JString jText)
        {
            if (string.IsNullOrEmpty(jText?.Value)) return new JString();
            if (jText.Value == singlesJScale[0]) return new JString(singlesPhonetic[0]);

            var words = new StringBuilder();
            var specialSingles = singlesJScale.Skip(1).Take(9);
            var chars = jText.Value.ToCharArray();

            var ndx = chars[0].Equals('−') ? 1 : 0;
            if (ndx > 0) words.Append("Mainasu "); // マイナス

            for (int i = ndx; i < chars.Length; i++)
            {
                var key = chars[i].ToString();
                var isHyphen = !(i == 0 || words.Length == 0 || words[words.Length - 1] == ' ');
                var hyphenate = isHyphen ? "-" : "";

                if (!"-,. ".Contains(key))
                {
                    if (i < chars.Length - 1 && key.Equals(singlesJScale[10]) && specialSingles.Any(c => c.Equals(chars[i + 1])))
                    {
                        words.Append($"{singlesPhonetic[singlesJScale.IndexOf(chars[i + 1].ToString()) + 10]} ");
                    }
                    else
                    {
                        if (specialSingles.Any(c => c.Equals(key)))
                        {
                            if (i < chars.Length - 1)
                            {
                                var sKey = jText.Value.Substring(i, 2);
                                if (specialPhonetic.ContainsKey(sKey))
                                {
                                    words.Append($"{specialPhonetic[sKey]} ");
                                    i++;
                                }
                                else
                                    words.Append($"{singlesPhonetic[singlesJScale.IndexOf(key)]}");
                            }
                            else
                                words.Append($"{singlesPhonetic[singlesJScale.IndexOf(key)]} ");
                        }
                        else if (key.Equals(singlesJScale[10]))
                        {
                            var sKey = jText.Value.Substring(i, 2);
                            if (i < chars.Length - 1 && !isHyphen && singlesJScale.Any(t => t.Equals(sKey)))
                            {
                                words.Append($"{singlesPhonetic[singlesJScale.IndexOf(sKey)]} ");
                                i++;
                            }
                            else
                                words.Append($"{hyphenate}{singlesPhonetic[10]} ");

                        }
                        else if (shortJScale.Any(c => c.Equals(key)))
                        {
                            var isSingle = words.Length > 0 && words[i - 1] == singlesJScale[1][0];
                            if (((i == 0 || words.Length == 0) || (i > 0 && isSingle)) && specialPhonetic.ContainsKey(key))
                            {
                                if (isSingle) words.Remove(words.Length - 1, 1);
                                words.Append($"{specialPhonetic[key]} ");
                            }
                            else
                                words.Append($"{hyphenate}{scalePhonetic[shortJScale.IndexOf(key)]} ");
                        }
                    }
                }
            }
            return new JString(words);
        }
    }

    public class JString
    {
        public JString() {}
        public JString(string value) { Value = value; }
        public JString(StringBuilder value) { Value = value?.ToString(); }
        public string Value { get; set; }
        public override string ToString() => Value;
        public static implicit operator string(JString js) => js.Value;
    }
}

To view Unicode Japanese characters in the console, we need to enable Unicode display. I found setting to MS Gothic font did the trick.
------------------------------------------------
VALUE: -1
TEXT:  − 一
Phonetic:  Mainasu ichi

------------------------------------------------
VALUE: 0
TEXT:  〇
Phonetic:  rei

------------------------------------------------
VALUE: 17
TEXT:  十七
Phonetic:  jū-nana

------------------------------------------------
VALUE: 1,001
TEXT:  千一
Phonetic:  is-sen ichi

------------------------------------------------
VALUE: 151
TEXT:  百五十一
Phonetic:  hyaku go-jū ichi

------------------------------------------------
VALUE: 302
TEXT:  三百二
Phonetic:  san-byaku ni

------------------------------------------------
VALUE: 469
TEXT:  四百六十九
Phonetic:  yon-hyaku roku-jū kyū

------------------------------------------------
VALUE: 1,234
TEXT:  千二百三十四
Phonetic:  is-sen ni-hyaku san-jū yon

------------------------------------------------
VALUE: 10,001
TEXT:  一万  一
Phonetic:  ichi-man ichi

------------------------------------------------
VALUE: 2,025
TEXT:  二千二十五
Phonetic:  ni-sen ni-jū go

------------------------------------------------
VALUE: 10,000
TEXT:  一万
Phonetic:  ichi-man

------------------------------------------------
VALUE: 100,001
TEXT:  十万  一
Phonetic:  jū man ichi

------------------------------------------------
VALUE: 1,100,101
TEXT:  百十万  百一
Phonetic:  hyaku jū man hyaku ichi

------------------------------------------------
VALUE: -9,836,703
TEXT:  − 九百八十三万  六千七百三
Phonetic:  Mainasu kyū-hyaku hachi-jū san-man roku-sen nana-hyaku san

------------------------------------------------
VALUE: 9,836,703
TEXT:  九百八十三万  六千七百三
Phonetic:  kyū-hyaku hachi-jū san-man roku-sen nana-hyaku san

------------------------------------------------
VALUE: 10,110,011
TEXT:  千十一万  十一
Phonetic:  is-sen jū-ichi man jū-ichi

------------------------------------------------
VALUE: 100,011,011
TEXT:  一億  一万  千十一
Phonetic:  ichi-oku ichi-man sen jū-ichi

------------------------------------------------
VALUE: 1,001,010,101
TEXT:  十億  百一万  百一
Phonetic:  jū oku hyaku ichi-man hyaku ichi

------------------------------------------------
VALUE: 2,036,521,801
TEXT:  二十億  三千六百五十二万  千八百一
Phonetic:  ni-jū oku san-zen rop-pyaku go-jū ni-man sen hap-pyaku ichi

------------------------------------------------
VALUE: -1,001,010,101
TEXT:  − 十億  百一万  百一
Phonetic:  Mainasu jū oku hyaku ichi-man hyaku ichi

------------------------------------------------
VALUE: -9,223,372,036,854,775,808
TEXT:  − 九百二十二京  三千三百七十二兆  三百六十八億  五千四百七十七万  五千八百八
Phonetic:  Mainasu kyū-hyaku ni-jū ni-kei san-zen san-byaku nana-jū ni-chō san-byaku roku-jū hachi-oku go-sen yon-hyaku nana-jū nana-man go-sen hap-pyaku hachi

------------------------------------------------
VALUE: 9,223,372,036,854,775,807
TEXT:  九百二十二京  三千三百七十二兆  三百六十八億  五千四百七十七万  五千八百七
Phonetic:  kyū-hyaku ni-jū ni-kei san-zen san-byaku nana-jū ni-chō san-byaku roku-jū hachi-oku go-sen yon-hyaku nana-jū nana-man go-sen hap-pyaku nana

-- Press any key to exit --

You can check the output at sci.lang.japan FAQ: Convert western numbers to kanji[^] web page.

Enjoy!
 
Share this answer
 
v2
Comments
Jon McKee 19-Jan-17 14:23pm    
Yon (4) and nana (7) can also be shi (4) or shichi (7). Kyuu (9) can also be ku (9) as well though I don't think I've ever heard someone use ku. Depends on the context.
Graeme_Grant 19-Jan-17 19:09pm    
Yes, they sure can. There is a Wikipedia link in the introduction to the solution that has a few more phonetic variations... ;)

[edit:] For example the number 600. You don't pronounce it roku-hyaku, instead the "Rendaku" (morphophonology or sequential voicing) is rop-pyaku. The code is aware of this and uses it correctly. :)

Note: I do not speak Japanese, and just thought it would be an interesting challenge to code after comments from PIEBALDconsult & ppolymorphe's submission...
Jon McKee 20-Jan-17 1:01am    
Oh yea, I just didn't see shi/shichi in your array and was making a comment :) I took 4 years of Japanese and can speak it... "ok" haha. There's a lot of little "gotchas" just like English but more centered around how words combine.
Graeme_Grant 20-Jan-17 2:39am    
Yes, I learned basic French, German, and Japanese numbers in early high school several decades ago. I too was taught shi/shichi. However, I based my choice from the link above - Yon & nana are listed as "Preferred reading", shi & shichi as "On reading".

Also, I know from doing business with Japanese businessmen, that yon & nana back then were more commonly used.
Jon McKee 20-Jan-17 2:52am    
That's awesome! I miss the Japanese community where I went for college; Iida-sensei was a great teacher. My Japanese has gotten pretty rusty over the years because of where I live now in mid-west US.

I used to know a good bit of Tagalog (Filipino) and some French as well but I've basically forgotten both of those :(
Getting this one in late. Was really sick this week :( Simple, to the point, and within specification with the addition of unsigned support! Could easily be expanded for BigInteger support since the algorithm breaks up the number and the Thousands enum can be easily added to.

C#
public static class Extensions
{
    public static string ToPhonetic(this long number)
    {
        ulong temp = (ulong)Math.Abs(number);
        if (number < 0)
            return "Negative " + temp.ToPhonetic();
        return temp.ToPhonetic();
    }

    public static string ToPhonetic(this ulong number)
    {
        if (number == 0) return "Zero";
        byte index = 0;
        Dictionary<byte, int> numberSets = new Dictionary<byte, int>();
        do
        {
            numberSets.Add(index++, (int)(number % 1000));
            number /= 1000;
        } while (number > 0);

        return numberSets.Keys.Aggregate(new StringBuilder(),
                (phoneticString, key) =>
                {
                    if (key > 0)
                        phoneticString.Insert(0, " " +
                            Enum.GetName(typeof(Thousands), key) + ", ");
                    GetHundredsPhonetic(phoneticString,
                        numberSets[key]);
                    return phoneticString;
                },
                phoneticString => phoneticString.ToString()
            );
    }

    private static void GetHundredsPhonetic(StringBuilder phonetic, int number)
    {
        byte hundreds = (byte)(number / 100);
        byte tens = (byte)(number % 100 / 10 * 10);
        byte ones = (byte)(number % 10);
        switch (tens)
        {
            case 0:
                phonetic.Insert(0, Enum.GetName(typeof(Hundreds), ones));
                break;
            case 10:
                phonetic.Insert(0, Enum.GetName(typeof(Hundreds), tens + ones));
                break;
            default:
                phonetic.Insert(0, Enum.GetName(typeof(Hundreds), tens) + " " +
                    Enum.GetName(typeof(Hundreds), ones));
                break;
        }
        if (hundreds > 0)
            phonetic.Insert(0, Enum.GetName(typeof(Hundreds), hundreds) + " Hundred ");
    }

    private enum Hundreds : short
    {
        One = 1,
        Two,
        Three,
        Four,
        Five,
        Six,
        Seven,
        Eight,
        Nine,
        Ten,
        Eleven,
        Twelve,
        Thirteen,
        Fourteen,
        Fifteen,
        Sixteen,
        Seventeen,
        Eighteen,
        Nineteen,
        Twenty = 20,
        Thirty = 30,
        Fourty = 40,
        Fifty = 50,
        Sixty = 60,
        Seventy = 70,
        Eighty = 80,
        Ninety = 90,
    }

    private enum Thousands : byte
    {
        None = 0,
        Thousand = 1,
        Million = 2,
        Billion = 3,
        Trillion = 4,
        Quadrillion = 5,
        Quintillion = 6
    }
}
 
Share this answer
 
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900