Task: Number names





Java: module NumberNames
    {
    void run()
        {
        @Inject Console console;

        Int[] tests = [0, 1, -1, 11, -17, 42, 99, 100, 101, -111, 1000, 1234, 10000, 100000,
                       123456789000, 0x123456789ABCDEF];
        for (Int test : tests)
            {
            console.print($"{test} = {toEnglish(test)}");
            }
        }

    static String[] digits = ["zero", "one", "two", "three", "four",
                              "five", "six", "seven", "eight", "nine"];
    static String[] teens  = ["ten", "eleven", "twelve", "thirteen", "fourteen",
                              "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
    static String[] tens   = ["zero", "ten", "twenty", "thirty", "forty",
                              "fifty", "sixty", "seventy", "eighty", "ninety"];
    static String[] ten3rd = ["?", "thousand", "million", "billion", "trillion",
                              "quadrillion", "quintillion"];

    static String toEnglish(Int n)
        {
        StringBuffer buf = new StringBuffer();
        if (n < 0)
            {
            "negative ".appendTo(buf);
            n = -n;
            }

        format3digits(n, buf);
        return buf.toString();
        }

    static void format3digits(Int n, StringBuffer buf, Int nested=0)
        {
        (Int left, Int right) = n /% 1000;
        if (left != 0)
            {
            format3digits(left, buf, nested+1);
            }

        if (right != 0 || (left == 0 && nested==0))
            {
            if (right >= 100)
                {
                (left, right) = (right /% 100);
                digits[left].appendTo(buf);
                " hundred ".appendTo(buf);
                if (right != 0)
                    {
                    format2digits(right, buf);
                    }
                }
            else
                {
                format2digits(right, buf);
                }

            if (nested > 0)
                {
                ten3rd[nested].appendTo(buf).add(' ');
                }
            }
        }

    static void format2digits(Int n, StringBuffer buf)
        {
        switch (n)
            {
            case 0..9:
                digits[n].appendTo(buf).add(' ');
                break;

            case 10..19:
                teens[n-10].appendTo(buf).add(' ');
                break;

            default:
                (Int left, Int right) = n /% 10;
                tens[left].appendTo(buf);
                if (right == 0)
                    {
                    buf.add(' ');
                    }
                else
                    {
                    buf.add('-');
                    digits[right].appendTo(buf).add(' ');
                    }
                break;
            }
        }
    }







Ada: with Ada.Text_IO;

procedure Integers_In_English is

   type Spellable is range -999_999_999_999_999_999..999_999_999_999_999_999;
   function Spell (N : Spellable) return String is
      function Twenty (N : Spellable) return String is
      begin
         case N mod 20 is
            when  0 => return "zero";
            when  1 => return "one";
            when  2 => return "two";
            when  3 => return "three";
            when  4 => return "four";
            when  5 => return "five";
            when  6 => return "six";
            when  7 => return "seven";
            when  8 => return "eight";
            when  9 => return "nine";
            when 10 => return "ten";
            when 11 => return "eleven";
            when 12 => return "twelve";
            when 13 => return "thirteen";
            when 14 => return "fourteen";
            when 15 => return "fifteen";
            when 16 => return "sixteen";
            when 17 => return "seventeen";
            when 18 => return "eighteen";
            when others => return "nineteen";
         end case;
      end Twenty;

      function Decade (N : Spellable) return String is
      begin
         case N mod 10 is
            when 2 => return "twenty";
            when 3 => return "thirty";
            when 4 => return "forty";
            when 5 => return "fifty";
            when 6 => return "sixty";
            when 7 => return "seventy";
            when 8 => return "eighty";
            when others => return "ninety";
         end case;
      end Decade;

      function Hundred (N : Spellable) return String is
      begin
         if N < 20 then
            return Twenty (N);
         elsif 0 = N mod 10 then
            return Decade (N / 10 mod 10);
         else
            return Decade (N / 10) & '-' & Twenty (N mod 10);
         end if;
      end Hundred;

      function Thousand (N : Spellable) return String is
      begin
         if N < 100 then
            return Hundred (N);
         elsif 0 = N mod 100 then
            return Twenty (N / 100) & " hundred";
         else
            return Twenty (N / 100) & " hundred and " & Hundred (N mod 100);
         end if;
      end Thousand;

      function Triplet
               (  N     : Spellable;
                  Order : Spellable;
                  Name  : String;
                  Rest  : not null access function (N : Spellable) return String
               )  return String is
         High : Spellable := N / Order;
         Low  : Spellable := N mod Order;
      begin
         if High = 0 then
            return Rest (Low);
         elsif Low = 0 then
            return Thousand (High) & ' ' & Name;
         else
            return Thousand (High) & ' ' & Name & ", " & Rest (Low);
         end if;
      end Triplet;

      function Million (N : Spellable) return String is
      begin
         return Triplet (N, 10**3, "thousand", Thousand'Access);
      end Million;

      function Milliard (N : Spellable) return String is
      begin
         return Triplet (N, 10**6, "million", Million'Access);
      end Milliard;

      function Billion (N : Spellable) return String is
      begin
         return Triplet (N, 10**9, "milliard", Milliard'Access);
      end Billion;

      function Billiard (N : Spellable) return String is
      begin
         return Triplet (N, 10**12, "billion", Billion'Access);
      end Billiard;

   begin
      if N < 0 then
         return "negative " & Spell(-N);
      else
        return Triplet (N, 10**15, "billiard", Billiard'Access);
      end if;
   end Spell;

   procedure Spell_And_Print(N: Spellable) is
      Number: constant String := Spellable'Image(N);
      Spaces: constant String(1 .. 20) := (others => ' '); 
   begin
      Ada.Text_IO.Put_Line(Spaces(Spaces'First .. Spaces'Last-Number'Length)
                             & Number & ' ' & Spell(N));
   end Spell_And_Print;

   Samples: constant array (Natural range <>) of Spellable
     := (99, 300, 310, 1_501, 12_609, 512_609, 43_112_609, 77_000_112_609,
         2_000_000_000_100, 999_999_999_999_999_999,
         0, -99, -1501, -77_000_112_609, -123_456_789_987_654_321);

begin
   for I in Samples'Range loop
      Spell_And_Print(Samples(I));
   end loop;
end Integers_In_English;