using System.Collections.Generic;
static string DollarsToWords(decimal value)
if (value < 0 || value >= 1000)
throw new ArgumentOutOfRangeException(nameof(value));
if (value == 0) return "zero dollars";
var output = new StringBuilder();
var dollars = (int) value;
var cents = (int) ((value - dollars) * 100);
IntToWords(dollars, output);
output.Append(" dollar");
IntToWords(cents, output);
return output.ToString();
static void IntToWords(int value, StringBuilder output)
if (NamedNumbers.TryGetValue(value, out var name))
var upper = (value - lower) / 100;
IntToWords(upper, output);
output.Append(" hundred");
IntToWords(lower, output);
var upper = value - lower;
IntToWords(upper, output);
IntToWords(lower, output);
static Dictionary<int, string> NamedNumbers = new Dictionary<int, string>
public static void Main()
Test(1.01m, "one dollar and one cent");
Test(1.63m, "one dollar and sixty three cents");
Test(0.12m, "twelve cents");
Test(10.55m, "ten dollars and fifty five cents");
Test(77.01m, "seventy seven dollars and one cent");
Test(70.40m, "seventy dollars and fourty cents");
Test(120, "one hundred and twenty dollars");
Test(999.99m, "nine hundred and ninety nine dollars and ninety nine cents");
static void Test(decimal number, string expected)
var actual = DollarsToWords(number);
Console.WriteLine($"{number}: PASS");
Console.WriteLine($"{number}: FAIL");
Console.WriteLine($" Expected: {expected}");
Console.WriteLine($" Actual: {actual}");