package main

import (
    "fmt"
    "strings"
    "time"
)

func main() {
    watches := []string{
        "First", "Middle", "Morning", "Forenoon",
        "Afternoon", "Dog", "First",
    }
    for {
        t := time.Now()
        h := t.Hour()
        m := t.Minute()
        s := t.Second()
        if (m == 0 || m == 30) && s == 0 {
            bell := 0
            if m == 30 {
                bell = 1
            }
            bells := (h*2 + bell) % 8
            watch := h/4 + 1
            if bells == 0 {
                bells = 8
                watch--
            }
            sound := strings.Repeat("\a", bells)
            pl := "s"
            if bells == 1 {
                pl = " "
            }
            w := watches[watch] + " watch"
            if watch == 5 {
                if bells < 5 {
                    w = "First " + w
                } else {
                    w = "Last " + w
                }
            }
            fmt.Printf("%s%02d:%02d = %d bell%s : %s\n", sound, h, m, bells, pl, w)
        }
        time.Sleep(1 * time.Second)
    }
}


import Control.Concurrent
import Control.Monad
import Data.Time
import Text.Printf

type Microsecond = Int
type Scheduler = TimeOfDay -> Microsecond

-- Scheduling
--------------

getTime :: TimeZone -> IO TimeOfDay
getTime tz = do
    t  <- getCurrentTime
    return $ localTimeOfDay $ utcToLocalTime tz t

getGMTTime   = getTime utc
getLocalTime = getCurrentTimeZone >>= getTime

-- Returns the difference between 'y' and the closest higher multiple of 'x'
nextInterval x y
    | x > y = x - y
    | mod y x > 0 = x - mod y x
    | otherwise = 0

-- Given a interval in seconds, this function returns time delta in microseconds.
onInterval :: Int -> Scheduler
onInterval interval time = toNext dMS
  where
    toNext = nextInterval (1000000 * interval)
    tDelta = timeOfDayToTime time
    dMS    = truncate $ 1000000 * tDelta

doWithScheduler :: Scheduler -> (Int -> IO ()) -> IO ThreadId
doWithScheduler sched task = forkIO $ forM_ [0..] exec
  where
    exec n = do
        t <- getLocalTime
        threadDelay $ sched t
        task n

-- Output
---------

watchNames = words "Middle Morning Forenoon Afternoon Dog First"
countWords = words "One Two Three Four Five Six Seven Eight"

-- Executes IO action and then waits for n microseconds
postDelay n fn = fn >> threadDelay n

termBell        = putStr "\a"
termBells n     = replicateM_ n $ postDelay 100000 termBell
termBellSeq seq = forM_ seq $ postDelay 500000 . termBells

toNoteGlyph 1 = "♪"
toNoteGlyph 2 = "♫"
toNoteGlyph _ = ""

ringBells :: Int -> IO ()
ringBells n = do
    t <- getLocalTime
    let numBells    = 1 + (mod n 8)
        watch       = watchNames!!(mod (div n 8) 8)
        count       = countWords!!(numBells - 1)
        (twos,ones) = quotRem numBells 2
        pattern     = (replicate twos 2) ++ (replicate ones 1)
        notes       = unwords $ map toNoteGlyph pattern
        plural       = if numBells > 1 then "s" else ""
        strFMT      = show t ++ ": %s watch, %5s bell%s:  " ++ notes ++ "\n"
    printf strFMT watch count plural
    termBellSeq pattern

-- Usage
---------

bellRinger :: IO ThreadId
bellRinger = doWithScheduler (onInterval (30*60)) ringBells


require 'strings printf'

WATCH        =:  <;._1 ' Middle Morning Forenoon Afternoon Dog First'
ORDINAL      =:  <;._1 ' One Two Three Four Five Six Seven Eight'
BELL         =:  7{a.  NB. Terminal bell code (\a or ^G)

time         =:  6!:0
sleep        =:  6!:3
print        =:  ucp 1!:2 4:

shipsWatch   =:  verb define
	PREV_MARK =.  _1 _1
	while. do. NB. Loop forever
		now  =.  3 4 { time ''  NB. Current hour & minute

		NB. If we just flipped over to a new half-hour mark
		if. (0 30 e.~ {: now) > now -: PREV_MARK do.
			PREV_MARK  =. now
			'allsWell notes'=.callWatch now

			print allsWell
			(ringBell"0~ [email protected]# {. 2|#) notes
			print CRLF
		end.

		sleep 15.0
	end.
)

callWatch    =:  verb define
	'watch bells' =. clock2ship y

	NB. Plural for 0~:bells ordinals are origin-1, not origin-0
	NB. (and similarly 1+bells for notes).
	fields=.(0{y);(1{y);(watch{::WATCH);(bells{::ORDINAL);('s'#~0~:bells)
	notes =. ; (0 2#:1+bells) #&.> u:16b266b 16b266a NB. ♫♪

	notes ;~ '%02d:%02d %s watch, %s Bell%s Gone: \t' sprintf fields
)

clock2ship   =: verb define"1
	NB. Convert from "24 hours of 60 minutes" to
	NB. "6 watches of 8 bells", and move midnight
	NB. from index-origin 0 (0 hrs, 0 minutes)
	NB. index-origin 1 (0 watches, 1 bell).
	6 8 #: 48 | _1 + 24 2 #. (, (30-1)&I.)/ y
)

ringBell     =:  dyad define
	print BELL,y

	NB. x indicates two rings (0) or just one (1)
	if. 0=x do.
		sleep 0.75
		print BELL
		sleep 0.25
	else.
		sleep 1.0
	end.
	y
)


import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

public class NauticalBell extends Thread {

    public static void main(String[] args) {
        NauticalBell bells = new NauticalBell();
        bells.setDaemon(true);
        bells.start();
        try {
            bells.join();
        } catch (InterruptedException e) {
            System.out.println(e);
        }
    }

    @Override
    public void run() {
        DateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        sdf.setTimeZone(TimeZone.getTimeZone("UTC"));

        int numBells = 0;
        long time = System.currentTimeMillis();
        long next = time - (time % (24 * 60 * 60 * 1000)); // midnight

        while (next < time) {
            next += 30 * 60 * 1000; // 30 minutes
            numBells = 1 + (numBells % 8);
        }

        while (true) {
            long wait = 100L;
            time = System.currentTimeMillis();
            if (time - next >= 0) {
                String bells = numBells == 1 ? "bell" : "bells";
                String timeString = sdf.format(time);
                System.out.printf("%s : %d %s\n", timeString, numBells, bells);
                next += 30 * 60 * 1000;
                wait = next - time;
                numBells = 1 + (numBells % 8);
            }
            try {
                Thread.sleep(wait);
            } catch (InterruptedException e) {
                return;
            }
        }
    }
}


using Dates

"""
    nauticalbells(DateTime)

    Return a string according to the "simpler system" of nautical bells
    listed in the table in Wikipedia at
    en.wikipedia.org/wiki/Ship%27s_bell#Simpler_system.
    Note the traditional time zone was determined by local sun position
    and so should be local time without daylight savings time.
"""
function nauticalbells(dt::DateTime)
    hr = hour(dt)
    mn = minute(dt)
    if hr in [00, 12, 4, 8, 16, 20]
        return mn == 00 ? "2 2 2 2" : "1"
    elseif hr in [1, 5, 9, 13, 17, 21]
        return  mn == 00 ? "2" : "2 1"
    elseif hr in [2, 6, 10, 14, 18, 22]
        return mn == 00 ? "2 2" : "2 2 1"
    elseif hr in [3, 7, 11, 15, 19, 23]
        return mn == 00 ? "2 2 2" : "2 2 2 1"
    else
        return "Gong pattern error: time $dt, hour $hr, minutes $mn"
    end
end

function nauticalbelltask()
    untilnextbell = ceil(now(), Dates.Minute(30)) - now()
    delay = untilnextbell.value / 1000
    println("Nautical bell task starting -- next bell in $delay seconds.")
    # The timer wakes its task every half hour. May drift very slightly so restart yearly.
    timer = Timer(delay; interval=1800)
    while true
        wait(timer)
        gong = nauticalbells(now())
        println("Nautical bell gong strikes ", gong)
    end
end

nauticalbelltask()


// version 1.1.3

import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.TimeZone

class NauticalBell: Thread() {

    override fun run() {
        val sdf = SimpleDateFormat("HH:mm:ss")
        sdf.timeZone = TimeZone.getTimeZone("UTC")
        var numBells = 0
        var time = System.currentTimeMillis()
        var next = time - (time % (24 * 60 * 60 * 1000)) // midnight

        while (next < time) {
            next += 30 * 60 * 1000 // 30 minutes
            numBells = 1 + (numBells % 8)
        }

        while (true) {
            var wait = 100L
            time = System.currentTimeMillis()
            if ((time - next) >= 0) {
                val bells = if (numBells == 1) "bell" else "bells"
                val timeString = sdf.format(time)
                println("%s : %d %s".format(timeString, numBells, bells))
                next += 30 * 60 * 1000
                wait = next - time
                numBells = 1 + (numBells % 8)
            }
            try {
                Thread.sleep(wait)
            }
            catch (ie: InterruptedException) {
                return
            }
        }
    }
}

fun main(args: Array<String>) {
    val bells = NauticalBell()
    with (bells) {
        setDaemon(true)
        start()
        try {
            join()
        }
        catch (ie: InterruptedException) {
            println(ie.message)
        }
    }
}


import os, strformat, times

const
  Watches = ["First", "Middle", "Morning", "Forenoon", "Afternoon", "First dog", "Last dog", "First"]
  WatchEnds = [(0, 0), (4, 0), (8, 0), (12, 0), (16, 0), (18, 0), (20, 0), (23, 59)]
  Bells = array[1..8, string](["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"])
  Ding = "ding!"

proc nb(h, m: Natural) =
  var bell = (h * 60 + m) div 30 mod 8
  if bell == 0: bell = 8
  let hm = (h, m)
  var watch = 0
  while hm > WatchEnds[watch]: inc watch
  let plural = if bell == 1: ' ' else: 's'
  var dings = Ding
  for i in 2..bell:
    if i mod 2 != 0: dings.add ' '
    dings.add Ding
  echo &"{h:02d}:{m:02d} {Watches[watch]:>9} watch {Bells[bell]:>5} bell{plural}  {dings}"

proc simulateOneDay() =
  for h in 0..23:
    for m in [0, 30]:
      nb(h, m)
  nb(0, 0)

when isMainModule:

  simulateOneDay()

  while true:
    let d = getTime().utc()
    var m = d.second + (d.minute mod 30) * 60
    if m == 0:
      nb(d.hour, d.minute)
    sleep((1800 - m) * 1000)  # In milliseconds.


/*REXX pgm beep's "bells" (using PC speaker) when running (perpetually).*/
  Parse Arg msg
  If msg='?' Then Do
    Say 'Ring a nautical bell'
    Exit
    End
  Signal on Halt                   /* allow a clean way to stop prog.*/
  Do Forever
    Parse Value time() With hh ':' mn ':' ss
    ct=time('C')
    hhmmc=left(right(ct,7,0),5)        /* HH:MM (leading zero).      */
    If msg>'' Then
      Say center(arg(1) ct time(),79)  /* echo arg1 with time ?      */
    If ss==00 & ( mn==00 | mn==30 ) Then Do /*It's time to ring bell */
      dd=dd(hhmmc)                     /* compute number of times    */
      If msg>'' Then
        Say center(dd "bells",79)      /* echo bells?                */
      Do k=1 For dd
        Call beep 650,500
        Call syssleep 1+(k//2==0)
        End
      Call syssleep 60                 /* ensure don't re-peel.      */
      End
    Else
      Call syssleep (60-ss)
    End
/* test
time:
If arg(1)='C' Then
  res='8:30am'
Else
  res='08:30:00'
Return res
*/

dd: Parse Arg hhmmc
Parse Var hhmmc hh +2 ':' mm .
h=hh//4
If h=0 Then
  If mm=00 Then res=8
  Else res=1
Else
  res=2*h+(mm=30)
Return res

halt:


use utf8;
binmode STDOUT, ":utf8";
use DateTime;

$| = 1; # to prevent output buffering

my @watch = <Middle Morning Forenoon Afternoon Dog First>;
my @ordinal = <One Two Three Four Five Six Seven Eight>;

my $thishour;
my $thisminute = '';

while () {
    my $utc = DateTime->now( time_zone => 'UTC' );
    if ($utc->minute =~ /^(00|30)$/ and $utc->minute != $thisminute) {
        $thishour   = $utc->hour;
        $thisminute = $utc->minute;
        bell($thishour, $thisminute);
    }
    printf "%s%02d:%02d:%02d", "\r", $utc->hour, $utc->minute, $utc->second;
    sleep(1);
}

sub bell {
    my($hour, $minute) = @_;

    my $bells = (($hour % 4) * 2 + int $minute/30) || 8;
    printf "%s%02d:%02d%9s watch,%6s Bell%s Gone: \t", "\b" x 9, $hour, $minute,
       $watch[(int($hour/4) - (0==($minute + $hour % 4)) + 6) % 6],
       $ordinal[$bells - 1], $bells == 1 ? '' : 's';
    chime($bells);
}

sub chime {
    my($count) = shift;
    for (1..int($count/2)) {
        print "\a♫ "; sleep .25;
        print "\a";   sleep .75;
    }
    if ($count % 2) {
        print "\a♪";  sleep 1;
    }
    print "\n";
}


with javascript_semantics
constant watches = {"First","Middle","Morning","Forenoon","Afternoon","First dog","Last dog","First"},
         watch_ends = {"00:00", "04:00", "08:00", "12:00", "16:00", "18:00", "20:00", "23:59"},
         bells = {"One","Two","Three","Four","Five","Six","Seven","Eight"},
         ding = "ding!"

procedure nb(integer h,m)
    integer bell = mod(floor((h*60+m)/30),8)
    if bell==0 then bell = 8 end if
    string hm = sprintf("%02d:%02d",{h,m})
    integer watch=1
    while hm>watch_ends[watch] do watch += 1 end while
    string plural = iff(bell==1?" ":"s")
    string dings = ding
    for i=2 to bell do dings &= iff(mod(i,2)?" ":"")&ding end for
    printf(1,"%s %9s watch %5s bell%s  %s\n",
             {hm,watches[watch],bells[bell],plural,dings})
end procedure

procedure simulate1day()
    for h=0 to 23 do
      for m=0 to 30 by 30 do
        nb(h,m)
      end for
    end for
    nb(0,0) -- (again)
end procedure

simulate1day()

if platform()!=JS then -- (no sleep() function)
    while 1 do
        sequence d = date(DT_GMT)
        integer m = d[DT_SECOND] + mod(d[DT_MINUTE],30)*60
        if m=0 then
            nb(d[DT_HOUR],d[DT_MINUTE])
        end if
        sleep(30*60-m)
    end while
end if


nautical: procedure options (main);      /* 29 October 2013 */
   declare (hour, t, i) fixed binary;

   do until (substr(time(), 3, 4) = '0000'); delay (1000); end;
   hour = substr(time(), 1, 2);

   do while ('1'b);
      do i = 1 to hour;
         put edit ('07'X) (a); put skip edit ('gong ') (a); delay (500);
      end;
      t = substr(time(), 5);
      delay (60*60*1000 - t);
   end;
end nautical;


function Get-Bell
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
                   Position=0)]
        [ValidateRange(1,12)]
        [int]
        $Hour,

        [Parameter(Mandatory=$true,
                   Position=1)]
        [ValidateSet(0,30)]
        [int]
        $Minute
    )

    $bells = @{
        OneBell    =          1
        TwoBells   =          2
        ThreeBells =       2, 1
        FourBells  =       2, 2
        FiveBells  =    2, 2, 1
        SixBells   =    2, 2, 2
        SevenBells = 2, 2, 2, 1
        EightBells = 2, 2, 2, 2
    }

    filter Invoke-Bell
    {
        if ($_ -eq 1)
        {
            [System.Media.SystemSounds]::Asterisk.Play()
            Write-Host -NoNewline "♪"
        }
        else
        {
            [System.Media.SystemSounds]::Exclamation.Play()
            Write-Host -NoNewline "♪♪  "
        }

        Start-Sleep -Milliseconds 500
    }

    $time = New-TimeSpan -Hours $Hour -Minutes $Minute

    switch ($time.Hours)
    {
         1 {if ($time.Minutes -eq 0) {$bells.TwoBells   | Invoke-Bell} else {$bells.ThreeBells | Invoke-Bell}; break}
         2 {if ($time.Minutes -eq 0) {$bells.FourBells  | Invoke-Bell} else {$bells.FiveBells  | Invoke-Bell}; break}
         3 {if ($time.Minutes -eq 0) {$bells.SixBells   | Invoke-Bell} else {$bells.SevenBells | Invoke-Bell}; break}
         4 {if ($time.Minutes -eq 0) {$bells.EightBells | Invoke-Bell} else {$bells.OneBell    | Invoke-Bell}; break}
         5 {if ($time.Minutes -eq 0) {$bells.TwoBells   | Invoke-Bell} else {$bells.ThreeBells | Invoke-Bell}; break}
         6 {if ($time.Minutes -eq 0) {$bells.FourBells  | Invoke-Bell} else {$bells.FiveBells  | Invoke-Bell}; break}
         7 {if ($time.Minutes -eq 0) {$bells.SixBells   | Invoke-Bell} else {$bells.SevenBells | Invoke-Bell}; break}
         8 {if ($time.Minutes -eq 0) {$bells.EightBells | Invoke-Bell} else {$bells.OneBell    | Invoke-Bell}; break}
         9 {if ($time.Minutes -eq 0) {$bells.TwoBells   | Invoke-Bell} else {$bells.ThreeBells | Invoke-Bell}; break}
        10 {if ($time.Minutes -eq 0) {$bells.FourBells  | Invoke-Bell} else {$bells.FiveBells  | Invoke-Bell}; break}
        11 {if ($time.Minutes -eq 0) {$bells.SixBells   | Invoke-Bell} else {$bells.SevenBells | Invoke-Bell}; break}
        12 {if ($time.Minutes -eq 0) {$bells.EightBells | Invoke-Bell} else {$bells.OneBell    | Invoke-Bell}}
    }

    Write-Host
}

Write-Host "Time Bells`n---- -----`n"

1..12 | ForEach-Object {

    $date = Get-Date -Hour $_ -Minute  0
    Write-Host -NoNewline "$($date.ToString("hh:mm")) "
    Get-Bell -Hour $_ -Minute  0

    $date = $date.AddMinutes(30)
    Write-Host -NoNewline "$($date.ToString("hh:mm")) "
    Get-Bell -Hour $_ -Minute 30
}


import time, calendar, sched, winsound

duration = 750      # Bell duration in ms
freq = 1280         # Bell frequency in hertz
bellchar = "\u2407"
watches = 'Middle,Morning,Forenoon,Afternoon,First/Last dog,First'.split(',')

def gap(n=1):
    time.sleep(n * duration / 1000)
off = gap

def on(n=1):
    winsound.Beep(freq, n * duration)

def bong():
    on(); off(0.5)

def bongs(m):
    for i in range(m):
        print(bellchar, end=' ')
        bong()
        if i % 2:
            print('  ', end='')
            off(0.5)
    print('')

scheds =  sched.scheduler(time.time, time.sleep)

def ships_bell(now=None):
    def adjust_to_half_hour(atime):
        atime[4] = (atime[4] // 30) * 30
        atime[5] = 0
        return atime

    debug = now is not None
    rightnow = time.gmtime()
    if not debug:
        now = adjust_to_half_hour( list(rightnow) )
    then = now[::]
    then[4] += 30
    hr, mn = now[3:5]
    watch, b = divmod(int(2 * hr + mn // 30 - 1), 8)
    b += 1
    bells = '%i bell%s' % (b, 's' if b > 1 else ' ')
    if debug:
        print("%02i:%02i, %-20s %s" % (now[3], now[4], watches[watch] + ' watch', bells), end=' ')
    else:
        print("%02i:%02i, %-20s %s" % (rightnow[3], rightnow[4], watches[watch] + ' watch', bells), end=' ')
    bongs(b)
    if not debug:
        scheds.enterabs(calendar.timegm(then), 0, ships_bell)
        #print(time.struct_time(then))
        scheds.run()

def dbg_tester():
    for h in range(24):
        for m in (0, 30):
            if (h,m) == (24,30): break
            ships_bell( [2013, 3, 2, h, m, 15, 5, 61, 0] )

if __name__ == '__main__':
    ships_bell()


#lang racket

(require racket/date)

(define HALF-HOUR-SECS (* 60 30))

;; given a date, return the seconds corresponding to the beginning
;; of that day (in local time)
(define (beginning-of-date d)
  (find-seconds 0 0 0 (date-day d) (date-month d) (date-year d)))

;; the seconds at the beginning of today:
(define today-secs
  (beginning-of-date
    (seconds->date (current-seconds))))

;; hours -> watch : given an hour, return the watch name
(define (hours->watch hours)
  (cond [(= 0 hours) "first"]
        [(< 0 hours 4.5) "middle"]
        [(< 4 hours 8.5) "morning"]
        [(< 8 hours 12.5) "forenoon"]
        [(< 12 hours 16.5) "afternoon"]
        [(< 16 hours 20.5) "dog"]
        [(< 20 hours 24.5) "first"]))

;; wait until current-seconds is the given number
(define (wait-til secs)
  (sleep (- secs (current-seconds))))

;; display the appropriate message
(define (format-and-print hours bells)
  (define int-hours (floor hours))
  (define minutes (cond [(integer? hours) "00"]
                        [else "30"]))
  (display
   (~a
    (~a (floor hours) #:min-width 2 #:pad-string "0"
        #:align 'right)
    ":" minutes ", " bells " bell(s) of the "
    (hours->watch hours) " watch "))
  ;; play the bells, if possible:
  (for ([i bells])
    (display "\a♪")
    (flush-output)
    (cond [(even? i) (sleep 0.5)]
          [(odd? i) (display " ") (sleep 1)]))
  (display "\n"))

;; start the loop:
(for ([s (in-range today-secs +inf.0 HALF-HOUR-SECS)]
      [bells (sequence-tail (in-cycle (in-range 8)) 7)]
      [hours (in-cycle (in-range 0 24 1/2))])
  ;; ignore the ones that have already happened:
  (when (< (current-seconds) s)
    (wait-til s)
    (format-and-print hours (add1 bells))))


my @watch = <Middle Morning Forenoon Afternoon Dog First>;
my @ordinal = <One Two Three Four Five Six Seven Eight>;

my $thishour;
my $thisminute = '';

loop {
    my $utc = DateTime.new(time);
    if $utc.minute ~~ any(0,30) and $utc.minute != $thisminute {
        $thishour   = $utc.hour;
        $thisminute = $utc.minute;
        bell($thishour, $thisminute);
    }
    printf "%s%02d:%02d:%02d", "\r", $utc.hour, $utc.minute, $utc.second;
    sleep(1);
}

sub bell ($hour, $minute) {

    my $bells = (($hour % 4) * 2 + $minute div 30) || 8;

    printf "%s%02d:%02d %9s watch, %6s Bell%s Gone: \t", "\b" x 9, $hour, $minute,
      @watch[($hour div 4 - !?($minute + $hour % 4) + 6) % 6],
      @ordinal[$bells - 1], $bells == 1 ?? '' !! 's';

    chime($bells);

    sub chime ($count) {
	for 1..$count div 2 {
		print "\a♫ ";
		sleep .25;
		print "\a";
		sleep .75;
	}
	if $count % 2 {
	     print "\a♪";
	     sleep 1;
        }
        print "\n";
    }
}


/*REXX program sounds "ship's bells"  (using PC speaker)  when executing  (perpetually).*/
echo= ( arg()\==0 )                              /*echo time and bells if any arguments.*/
signal on halt                                   /*allow a clean way to stop the program*/
                   t.1=  '00:30   01:00   01:30   02:00   02:30   03:00   03:30   04:00'
                   t.2=  '04:30   05:00   05:30   06:00   06:30   07:00   07:30   08:00'
                   t.3=  '08:30   09:00   09:30   10:00   10:30   11:00   11:30   12:00'

      do forever;  t=time();   ss=right(t, 2);   mn=substr(t, 4, 2)  /*the current time.*/
      ct=time('C')                               /*[↓]  maybe add leading zero to time. */
      hhmmc=left( right( ct, 7, 0),  5)          /*HH:MM   (maybe with a leading zero). */
      if echo  then say center(arg(1) ct, 79)    /*echo the 1st argument with the time? */
      if ss\==00 & mn\==00 & mn\==30  then do;  call delay  60-ss;   iterate
                                           end   /* [↑]  delay for fraction of a minute.*/
                                                 /* [↓]  the number of bells to peel {$}*/
                     do j=1  for 3  until $\==0;   $=wordpos(hhmmc, t.j)
                     end   /*j*/

      if $\==0 & echo  then say center($ "bells", 79)       /*echo the number of bells? */

                     do k=1 for $;  call sound 650,1;  call delay 1 + (k//2==0)
                     end   /*k*/                 /*[↑]  peel, and then pause for effect.*/
      call delay 60;       if rc\==0  then leave /*ensure we don't re─peel.             */
      end   /*forever*/
halt:                                            /*stick a fork in it,  we're all done. */


watches = [ "First", "Middle", "Morning", "Forenoon", "Afternoon", "First dog", "Last dog", "First" ]
watch_ends = [ "00:00", "04:00", "08:00", "12:00", "16:00", "18:00", "20:00", "23:59" ]
words = ["One","Two","Three","Four","Five","Six","Seven","Eight"]
sound = "ding!"

loop do
  time = Time.now
  if time.sec == 0 and time.min % 30 == 0
    num = (time.hour * 60 + time.min) / 30 % 8
    num = 8 if num == 0
    hr_min = time.strftime "%H:%M"
    idx = watch_ends.find_index {|t| hr_min <= t}
    text = "%s - %s watch, %s bell%s gone" % [
        hr_min,
        watches[idx],
        words[num-1],
        num==1 ? "" : "s"
    ]
    bells = (sound * num).gsub(sound + sound) {|dd| dd + ' '}
    puts "%-45s %s" % [text, bells]
  end
  sleep 1
end


$ include "seed7_05.s7i";
  include "time.s7i";
  include "duration.s7i";
  include "keybd.s7i";

const array string: watch is [] ("Middle", "Morning", "Forenoon", "Afternoon", "Dog", "First");
const array string: bells is [] ("One Bell", "Two Bells", "Three Bells", "Four Bells", "Five Bells", "Six Bells", "Seven Bells", "Eight Bells");

const func time: truncToHalfHour (in time: aTime) is func
  result
    var time: truncatedTime is time.value;
  begin
    truncatedTime := aTime;
    truncatedTime.minute := aTime.minute div 30 * 30;
    truncatedTime.second := 0;
    truncatedTime.micro_second := 0;
  end func;

const proc: main is func
  local
    var time: nextTime is time.value;
    var time: midnight is time.value;
    var integer: minutes is 0;
  begin
    writeln;
    nextTime := truncToHalfHour(time(NOW));
    midnight := truncToDay(nextTime);
    while TRUE do
      nextTime +:= 30 . MINUTES;
      await(nextTime);
      minutes := toMinutes(nextTime - midnight);
      writeln(str_hh_mm(nextTime, ":") <& " - " <&
              watch[succ((minutes - 30) mdiv 240 mod 6)] <& " watch - " <&
              bells[succ((minutes - 30) mdiv 30 mod 8)] <& " Gone.");
      flush(OUT);
    end while;
  end func;


# More sophisticated versions are possible, such as playing a bell sample
# using the Snack library.
proc ringTheBell {} {
    puts -nonewline "\a"
}

# The code to convert the (parsed) time into rings of the ship's bell and
# printing of the name of the bell.
proc strikeBell {hour minute} {
    global suppressNormalOutput
    set watches {
	Middle Middle Morning Morning Forenoon Forenoon
	Afternoon Afternoon {First dog} {Last dog} First First
    }
    set cardinals {one two three four five six seven eight}
    set bells [expr {(($hour % 4) * 2 + $minute / 30)}]
    if {!$bells} {set bells 8}
    puts -nonewline [format "%02d:%02d %9s watch, %6s bell%s gone: \t" \
	    $hour $minute [lindex $watches [expr {
		($hour/2 - ($minute==0 && $hour%2==0)) % 12
	    }]] [lindex $cardinals [expr {$bells - 1}]] \
	    [expr {$bells == 1 ? "" : "s"}]]

    # Set up the ringing of the bells to be done asynchronously
    set t 0
    set suppressNormalOutput 1
    for {set i 0} {$i < $bells-1} {incr i 2} {
	after $t {
	    ringTheBell
	    puts -nonewline "\u266b "
	}
	incr t 250
	after $t {
	    ringTheBell
	}
	incr t 750
    }
    if {$bells % 2} {
	after $t {
	    ringTheBell
	    puts -nonewline "\u266a\n"
	    set suppressNormalOutput 0
	}
    } else {
	after $t {
	    puts ""
	    set suppressNormalOutput 0
	}
    }
}

# Main handler; designed to be called every second, which is plenty.
proc nauticalBell {} {
    global last suppressNormalOutput
    scan [clock format [clock seconds] -format "%H:%M" -gmt 1] "%d:%d" h m
    if {$last != $m} {
	set last $m
	if {$m%30 == 0} {
	    strikeBell $h $m
	} elseif {!$suppressNormalOutput} {
	    puts -nonewline [format "%02d:%02d\r" $h $m]
	}
    }
}

# Set things up, using Tcl's event loop to do the processing
proc every {delay script} {
    after $delay [list every $delay $script]
    uplevel #0 $script
}
set last ""
set suppressNormalOutput 0
fconfigure stdout -buffering none
every 1000 nauticalBell
vwait forever;   # Only needed if not running an event loop otherwise


import "os" for Process
import "timer" for Timer
import "/date" for Date
import "/fmt" for Fmt

var watches = ["First", "Middle", "Morning", "Forenoon", "Afternoon", "Dog", "First"]

var args = Process.arguments
if (args.count == 0) {
    System.print("Please enter current time in the format (24 hour clock): hh:mm:ss.")
    return
}

var now = Date.parse(args[0], Date.isoTime)

while (true) {
    var h = now.hour
    var m = now.minute
    var s = now.second
    if ((m == 0 || m == 30) && s == 0) {
        var bell = (m == 30) ? 1 : 0
        var bells = (h*2 + bell) % 8
        var watch = (h/4).floor + 1
        if (bells == 0) {
            bells = 8
            watch = watch - 1
        }
        var sound = "\a" * bells
        var pl = (bells != 1) ? "s" : ""
        var w = watches[watch] + " watch"
        if (watch == 5) {
            if (bells < 5) {
                w = "First " + w
            } else {
                w = "Last " + w
            }
        }
        Fmt.lprint("$s$02d:$02d = $d bell$s : $s", [sound, h, m, bells, pl, w])
    }
    Timer.sleep(1000)
    now = now.addSeconds(1)
}


*        Number names              20/02/2017
NUMNAME  CSECT
         USING  NUMNAME,R13
         B      72(R15)
         DC     17F'0'
         STM    R14,R12,12(R13)
         ST     R13,4(R15)
         ST     R15,8(R13)
         LR     R13,R15            end of prolog
         LA     R6,1               i=1
       DO WHILE=(C,R6,LE,=A(NG))   do i=1 to hbound(g)
         LR     R1,R6              i
         SLA    R1,2
         L      R2,G-4(R1)         g(i)
         ST     R2,N               n=g(i)
         L      R4,N
       IF LTR,R4,Z,R4 THEN         if n=0 then
         MVC    R,=CL256'zero'     r='zero'
       ELSE     ,                  else
         MVC    R,=CL256' '        r=''
         MVC    D,=F'10'           d=10
         MVC    C,=F'100'          c=100
         MVC    K,=F'1000'         k=1000
         L      R2,N               n
         LPR    R2,R2              abs(n)
         ST     R2,A               a=abs(n)
         SR     R7,R7              j=0
       DO WHILE=(C,R7,LE,D)        do j=0 to d
         L      R4,A               a
         SRDA   R4,32
         D      R4,C               /c
         M      R4,C               *a
         L      R8,A               a
         SR     R8,R5              h=a-c*a/c
       IF C,R8,GT,=F'0',AND,C,R8,LT,D THEN  if h>0 & h<d then
         LR     R1,R8                h
         MH     R1,=H'10'
         LA     R4,S(R1)             @s(h+1)
         MVC    PG(10),0(R4)         s(h+1)
         MVC    PG+10(246),R         !!r
         MVC    R,PG                 r=s(h+1)!!' '!!r
       ENDIF    ,                  endif
       IF C,R8,GT,=F'9',AND,C,R8,LT,=F'20' THEN  if h>9 & h<20 then
         LR     R1,R8                h
         S      R1,D                 -d
         MH     R1,=H'10'
         LA     R4,T(R1)             @t(h-d+1)
         MVC    PG(10),0(R4)         t(h-d+1)
         MVC    PG+10(246),R         !!r
         MVC    R,PG                 r=t(h-d+1)!!' '!!r
       ENDIF    ,                  endif
       IF C,R8,GT,=F'19',AND,C,R8,LT,C THEN  if h>19 & h<c then
         LR     R4,R8                h
         SRDA   R4,32
         D      R4,D                 /d
         M      R4,D                 *d
         LR     R1,R8                h
         SR     R1,R5                h-d*(h/d)
         ST     R1,X                 x=h-d*(h/d)
         L      R4,X                 x
       IF LTR,R4,NZ,R4 THEN          if x^=0 then
         MVI    Y,C'-'                 y='-'
       ELSE     ,                    else
         MVI    Y,C' '                 y=' '
       ENDIF    ,                    endif
         LR     R4,R8                h
         SRDA   R4,32
         D      R4,D                 /d
         MH     R5,=H'10'
         LA     R4,U(R5)             @u(h/d+1)
         MVC    PG(10),0(R4)         u(h/d+1)
         MVC    PG+10(1),Y           y
         L      R1,X                 x
         MH     R1,=H'10'
         LA     R4,S(R1)             @s(x+1)
         MVC    PG+11(10),0(R4)      s(x+1)
         MVC    PG+21(235),R         !!r
         MVC    R,PG                 r=u(h/d+1)!!y!!s(x+1)!!r
       ENDIF    ,                  endif
         L      R4,A               a
         SRDA   R4,32
         D      R4,K               a/k
         M      R4,K               *k
         L      R8,A               a
         SR     R8,R5              h=a-k*(a/k)
         LR     R4,R8              h
         SRDA   R4,32
         D      R4,C               /c
         LR     R8,R5              h=h/c
       IF LTR,R8,NZ,R8 THEN        if h^=0 then
         LR     R1,R8                h
         MH     R1,=H'10'
         LA     R4,S(R1)             @s(h+1)
         MVC    PG(10),0(R4)         s(h+1)
         MVC    PG+10(10),=CL10' hundred '
         MVC    PG+20(236),R         !!r
         MVC    R,PG                 r=s(h+1)!!' hundred '!!r
       ENDIF    ,                  endif
         L      R4,A               a
         SRDA   R4,32
         D      R4,K               /k
         ST     R5,A               a=a/k
         L      R4,A
       IF LTR,R4,P,R4 THEN         if a>0 then
         L      R4,A                 a
         SRDA   R4,32
         D      R4,K                 /k
         M      R4,K                 *k
         L      R8,A                 a
         SR     R8,R5                h=a-k*(a/k)
       IF LTR,R8,NZ,R8 THEN          if h^=0 then
         LR     R1,R7                  j
         MH     R1,=H'10'
         LA     R4,V(R1)               @v(j+1)
         MVC    PG(10),0(R4)           v(j+1)
         MVC    PG+10(246),R           !!r
         MVC    R,PG                   r=v(j+1)!!' '!!r
       ENDIF    ,                    endif
       ENDIF    ,                  endif
         LA     R3,1               l=0
         LA     R9,256             jr=256
         LA     R10,R              ir=0
         LA     R11,R-1            irr=-1
LOOP     CLI    0(R10),C' '        if r[ii]=' '  .....+
         BNE    OPT                                   |
         CLI    1(R10),C' '        if r[ii+1]=' '     |
         BE     ITER                                  |
         CLI    1(R10),C'-'        if r[ii+1]='-'     |
         BE     ITER                                  |
OPT      LA     R11,1(R11)         irr=irr+1          |
         MVC    0(1,R11),0(R10)    rr=rr!!ci          |
         LA     R3,1(R3)           l=l+1              |
ITER     LA     R10,1(R10)         ir=ir+1            |
         BCT    R9,LOOP            ...................+
         LA     R1,R-1             @r
         AR     R1,R3              +lr
         MVC    0(80,R1),=CL80' '  clean the end
         L      R4,A               a
       IF LTR,R4,NP,R4 THEN        if a<=0 then
         B      LEAVEJ             leave
       ENDIF    ,                  endif a<=0
         LA     R7,1(R7)           j++
       ENDDO    ,                  enddo j
LEAVEJ   L      R4,N               n
       IF LTR,R4,M,R4 THEN         if n<0 then
         MVC    PG(6),=C'minus '   'minus '
         MVC    PG+6(250),R        !!r
         MVC    R,PG               r='minus '!!r
       ENDIF    ,                  endif n<0
       ENDIF    ,                  endif n=0
         MVC    PG,=CL132' '       clear buffer
         L      R1,N               n
         XDECO  R1,PG              edit n
         MVC    PG+13(256),R       r
         XPRNT  PG,132             print buffer
         LA     R6,1(R6)           i++
       ENDDO    ,                  enddo i
         L      R13,4(0,R13)       epilog
         LM     R14,R12,12(R13)
         XR     R15,R15
         BR     R14                exit
S        DC   CL10' ',CL10'one',CL10'two',CL10'three',CL10'four'
         DC   CL10'five',CL10'six',CL10'seven',CL10'eight',CL10'nine'
T        DC   CL50'ten       eleven    twelve    thirteen  fourteen'
         DC   CL50'fifteen   sixteen   seventeen eighteen  nineteen'
U        DC   CL50'                    twenty    thirty    forty'
         DC   CL50'fifty     sixty     seventy   eighty    ninety'
V        DC   CL50'thousand  million   billion   trillion'
G        DC   F'0',F'2',F'19',F'20',F'21',F'99',F'100',F'101',F'-123'
         DC   F'9123',F'467889',F'1234567',F'2147483647'
NG       EQU    (*-G)/4
N        DS     F
D        DS     F
C        DS     F
K        DS     F
A        DS     F
X        DS     F
Y        DS     CL1
R        DS     CL256
XDEC     DS     CL12
PG       DS     CL256
         YREGS
         END    NUMNAME


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 => ' '); -- 20 * ' '
   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;


PROC number words = (INT n)STRING:(
  # returns a string representation of n in words. Currently
  deals with anything from 0 to 999 999 999. #
    []STRING digits = []STRING
      ("zero","one","two","three","four","five","six","seven","eight","nine")[@0];
    []STRING teens = []STRING
      ("ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen")[@0];
    []STRING decades = []STRING
      ("twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety")[@2];

    PROC three digits = (INT n)STRING: (
      # does the conversion for n from 0 to 999. #
        INT tens = n MOD 100 OVER 10;
        INT units = n MOD 10;
        (n >= 100|digits[n OVER 100] + " " + "hundred" + (n MOD 100 /= 0|" and "|"")|"") +
        (tens /= 0|(tens = 1|teens[units]|decades[tens] + (units /= 0|"-"|""))|"") +
        (units /= 0 AND tens /= 1 OR n = 0|digits[units]|"")
      );
    INT m = n OVER 1 000 000;
    INT k = n MOD 1 000 000 OVER 1000;
    INT u = n MOD 1000;
    (m /= 0|three digits(m) + " million"|"") +
    (m /= 0 AND (k /= 0 OR u >= 100)|", "|"") +
    (k /= 0|three digits(k) + " thousand"|"") +
    ((m /= 0 OR k /= 0) AND u > 0 AND u < 100|" and " |: k /= 0 AND u /= 0|", "|"") +
    (u /= 0 OR n = 0|three digits(u)|"")
  );

on logical file end(stand in, (REF FILE f)BOOL: GOTO stop iteration);
on value error(stand in, (REF FILE f)BOOL: GOTO stop iteration);
DO # until user hits EOF #
  INT n;
  print("n? ");
  read((n, new line));
  print((number words(n), new line))
OD;
stop iteration:
  SKIP


spell←{⎕IO←0
     small←'' 'one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight'
     small,←'nine' 'ten' 'eleven' 'twelve' 'thirteen' 'fourteen'
     small,←'fifteen' 'sixteen' 'seventeen' 'eighteen' 'nineteen'
     teens←'twenty' 'thirty' 'forty' 'fifty' 'sixty' 'seventy'
     teens,←'eighty' 'ninety'
     orders←'m' 'b' 'tr' 'quadr',¨⊂'illion'
     orders←(⊂¨,¨10*6+3×⍳∘≢)orders
     orders←('hundred' 100)('thousand' 1000),orders

     ⍵=0:'zero'
     {  ⍵<0:'minus ',∇-⍵
        ⍵<20:⍵⊃small
        ⍵<100:{
            ty←((⌊⍵÷10)-2)⊃teens
            0=n←10|⍵:ty
            ty,'-',n⊃small
        }⍵
        (⊃⊃∇{
            name size←⍺
            cur n←⍵
            rest←size|n
            n≥size:(⊂cur,(⍺⍺⌊n÷size),' ',name,((0≠rest)↑'')),rest
            (⊂cur),rest
        }/orders,⊂(''⍵)),∇100|⍵
    }⍵
}


use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"

on numberToWords(n)
    return (current application's class "NSNumberFormatter"'s localizedStringFromNumber:(n) numberStyle:(current application's NSNumberFormatterSpellOutStyle)) as text
end numberToWords

numberToWords(-3.6028797018963E+10)
--> "minus thirty-six billion twenty-eight million seven hundred ninety-seven thousand eighteen point nine six three"


10 INPUT "GIMME A NUMBER! "; N
20 GOSUB 100"NUMBER NAME
30 PRINT R$
40 END

100 REMNUMBER NAME
110 IF R$ = "" THEN FOR I = 0 TO 10 : READ S$(I), T$(I), U$(I), V$(I) : NEXT
120 IF N = 0 THEN R$ = "ZERO" : RETURN
130 R$ = "" : D = 10 : C = 100 : M = 1E3
140 A = ABS(N)
150 FOR U = 0 TO D
160     H = A - C * INT(A / C)
170     IF H > 0 AND H < D THEN R$ = S$(H) + " " + R$
180     IF H > 9 AND H < 20 THEN R$ = T$(H - D) + " " + R$
190     IF H > 19 AND H < C THEN S = H - D * INT(H / D) : R$ = U$(INT(H / D)) + MID$("-",1+(S=0),1) + S$(S) +  " " + R$
200     H = A - M * INT(A / M)
210     H = INT (H / C)
220     IF H THEN R$ = S$(H) + " HUNDRED " + R$
230     A = INT(A / M)
240     IF A > 0 THEN H = A - M * INT(A / M) : IF H THEN R$ = V$(U) + " " + R$
250     IF A > 0 THEN NEXT U
260 IF N < 0 THEN R$ = "NEGATIVE " + R$
270 RETURN

280 DATA "", "TEN", "", "THOUSAND"
281 DATA "ONE", "ELEVEN", "", "MILLION"
282 DATA "TWO", "TWELVE", "TWENTY", "BILLION"
283 DATA "THREE", "THIRTEEN", "THIRTY", "TRILLION"
284 DATA "FOUR", "FOURTEEN", "FORTY", "QUADRILLION"
285 DATA "FIVE", "FIFTEEN", "FIFTY", "QUINTILLION"
286 DATA "SIX", "SIXTEEN", "SIXTY", "SEXTILLION"
287 DATA "SEVEN", "SEVENTEEN", "SEVENTY", "SEPTILLION"
288 DATA "EIGHT", "EIGHTEEN", "EIGHTY", "OCTILLION"
289 DATA "NINE", "NINETEEN", "NINETY", "NONILLION"
290 DATA "", "", "", "DECILLION"


Loop {                                 ; TEST LOOP
    n =
    Random Digits, 1, 36               ; random number with up to 36 digits
    Loop %Digits% {
        Random Digit, 0, 9             ; can have leading 0s
        n .= Digit
    }
    MsgBox 1, Number Names, % PrettyNumber(n) "`n`n" Spell(n) "`n`n"
    IfMsgBox Cancel, Break
}

Spell(n) { ; recursive function to spell out the name of a max 36 digit integer, after leading 0s removed
    Static p1=" thousand ",p2=" million ",p3=" billion ",p4=" trillion ",p5=" quadrillion ",p6=" quintillion "
         , p7=" sextillion ",p8=" septillion ",p9=" octillion ",p10=" nonillion ",p11=" decillion "
         , t2="twenty",t3="thirty",t4="forty",t5="fifty",t6="sixty",t7="seventy",t8="eighty",t9="ninety"
         , o0="zero",o1="one",o2="two",o3="three",o4="four",o5="five",o6="six",o7="seven",o8="eight"
         , o9="nine",o10="ten",o11="eleven",o12="twelve",o13="thirteen",o14="fourteen",o15="fifteen"
         , o16="sixteen",o17="seventeen",o18="eighteen",o19="nineteen"

    n :=RegExReplace(n,"^0+(\d)","$1") ; remove leading 0s from n

    If  (11 < d := (StrLen(n)-1)//3)   ; #of digit groups of 3
        Return "Number too big"

    If (d)                             ; more than 3 digits
        Return Spell(SubStr(n,1,-3*d)) p%d% ((s:=SubStr(n,1-3*d)) ? ", " Spell(s) : "")

    i := SubStr(n,1,1)
    If (n > 99)                        ; 3 digits
        Return o%i% " hundred" ((s:=SubStr(n,2)) ? " and " Spell(s) : "")

    If (n > 19)                        ; n = 20..99
        Return t%i% ((o:=SubStr(n,2)) ? "-" o%o% : "")

    Return o%n%                        ; n = 0..19
}

PrettyNumber(n) { ; inserts thousands separators into a number string
    Return RegExReplace( RegExReplace(n,"^0+(\d)","$1"), "\G\d+?(?=(\d{3})+(?:\D|$))", "$0,")
}


# syntax: GAWK -f NUMBER_NAMES.AWK
BEGIN {
    init_numtowords()
    n = split("-10 0 .1 8 100 123 1001 99999 100000 9123456789 111000000111",arr," ")
    for (i=1; i<=n; i++) {
      printf("%s = %s\n",arr[i],numtowords(arr[i]))
    }
    exit(0)
}
# source: The AWK Programming Language, page 75
function numtowords(n,  minus,str) {
    if (n < 0) {
      n = n * -1
      minus = "minus "
    }
    if (n == 0) {
      str = "zero"
    }
    else {
      str = intowords(n)
    }
    gsub(/  /," ",str)
    gsub(/ $/,"",str)
    return(minus str)
}
function intowords(n) {
    n = int(n)
    if (n >= 1000000000000) {
      return intowords(n/1000000000000) " trillion " intowords(n%1000000000000)
    }
    if (n >= 1000000000) {
      return intowords(n/1000000000) " billion " intowords(n%1000000000)
    }
    if (n >= 1000000) {
      return intowords(n/1000000) " million " intowords(n%1000000)
    }
    if (n >= 1000) {
      return intowords(n/1000) " thousand " intowords(n%1000)
    }
    if (n >= 100) {
      return intowords(n/100) " hundred " intowords(n%100)
    }
    if (n >= 20) {
      return tens[int(n/10)] " " intowords(n%10)
    }
    return(nums[n])
}
function init_numtowords() {
    split("one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen",nums," ")
    split("ten twenty thirty forty fifty sixty seventy eighty ninety",tens," ")
}


DECLARE FUNCTION int2Text$ (number AS LONG)

'small
DATA "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"
DATA "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
'tens
DATA "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
'big
DATA "thousand", "million", "billion"

DIM SHARED small(1 TO 19) AS STRING, tens(7) AS STRING, big(2) AS STRING

DIM tmpInt AS INTEGER

FOR tmpInt = 1 TO 19
    READ small(tmpInt)
NEXT
FOR tmpInt = 0 TO 7
    READ tens(tmpInt)
NEXT
FOR tmpInt = 0 TO 2
    READ big(tmpInt)
NEXT

DIM n AS LONG

INPUT "Gimme a number! ", n
PRINT int2Text$(n)

FUNCTION int2Text$ (number AS LONG)
    DIM num AS LONG, outP AS STRING, unit AS INTEGER
    DIM tmpLng1 AS LONG

    IF 0 = number THEN
        int2Text$ = "zero"
        EXIT FUNCTION
    END IF

    num = ABS(number)

    DO
        tmpLng1 = num MOD 100
        SELECT CASE tmpLng1
            CASE 1 TO 19
                outP = small(tmpLng1) + " " + outP
            CASE 20 TO 99
                SELECT CASE tmpLng1 MOD 10
                    CASE 0
                        outP = tens((tmpLng1 \ 10) - 2) + " " + outP
                    CASE ELSE
                        outP = tens((tmpLng1 \ 10) - 2) + "-" + small(tmpLng1 MOD 10) + " " + outP
                END SELECT
        END SELECT

        tmpLng1 = (num MOD 1000) \ 100
        IF tmpLng1 THEN
            outP = small(tmpLng1) + " hundred " + outP
        END IF

        num = num \ 1000
        IF num < 1 THEN EXIT DO

        tmpLng1 = num MOD 1000
        IF tmpLng1 THEN outP = big(unit) + " " + outP

        unit = unit + 1
    LOOP

    IF number < 0 THEN outP = "negative " + outP

    int2Text$ = RTRIM$(outP)
END FUNCTION


::Number Names Task from Rosetta Code Wiki
::Batch File Implementation

@echo off
setlocal enabledelayedexpansion

if "%~1"=="iterate" goto num_name

::Define the words
set "small=One Two Three Four Five Six Seven Eight Nine Ten"
set "small=%small% Eleven Twelve Thirteen Fourteen Fifteen Sixteen Seventeen Eighteen Nineteen"
set "decade=Twenty Thirty Forty Fifty Sixty Seventy Eighty Ninety"
set "big=Thousand Million Billion"

::Seperating each word...
set cnt=0
for %%X in (%small%) do (set /a "cnt+=1"&set small!cnt!=%%X)
set cnt=0
for %%Y in (%decade%) do (set decade!cnt!=%%Y&set /a "cnt+=1")
set cnt=0
for %%Z in (%big%) do (set big!cnt!=%%Z&set /a "cnt+=1")

::The Main Thing
for %%. in (42,27,1090,230000,1001100,-40309,0,123456789) do (
	set input=%%.
	if %%. lss 0 (set /a input*=-1)
	if !input! equ 0 (set TotalOut=Zero) else (
		call :num_word %%.
	)
	echo "!TotalOut!"
)
exit /b
::/The Main Thing

::The Procedure
:num_word
	set outP=
	set unit=0
	set num=!input!
:num_loop
set /a tmpLng1 = num %% 100
set /a tmpLng2 = tmpLng1 %% 10
set /a tmpNum1 = tmpLng1/10 - 2

if !tmpLng1! geq 1 if !tmpLng1! leq 19 (
	set "outP=!small%tmpLng1%! !outP!"
)
if !tmpLng1! geq 20 if !tmpLng1! leq 99 (
	if !tmpLng2! equ 0 (
		set "outP=!decade%tmpNum1%! !outP!"
	) else (
		set "outP=!decade%tmpNum1%!-!small%tmpLng2%! !outP!"
	)
)

set /a tmpLng1 = (num %% 1000)/100
if not !tmpLng1! equ 0 (
	set "outP=!small%tmpLng1%! Hundred !outP!"
)

set /a num/=1000
if !num! lss 1 goto :break_loop

set /a tmpLng1 = num %% 1000
if not !tmpLng1! equ 0 (
	set "outP=!big%unit%! !outP!"
)
set /a unit+=1
goto :num_loop

:break_loop
set "TotalOut=!outP!"
if %1 lss 0 set "TotalOut=Negative !outP!"

set TotalOut=%TotalOut:~0,-1%
goto :EOF


      DIM test%(20)
      test%() = 0, 1, 2, 19, 20, 21, 99, 100, 101, 300, 310, 1001, -1327, 1501, \
      \         10203, 12609, 101104, 102003, 467889, 1005006, -123000789
      FOR i% = 0 TO DIM(test%(),1)
        PRINT FNsaynumber(test%(i%))
      NEXT
      END

      DEF FNsaynumber(n%)
      LOCAL number%(), number$(), i%, t%, a$
      DIM number%(29), number$(29)
      number%() = 1000000000, 1000000, 1000, 100, 90, 80, 70, 60, 50, 40, 30, 20, \
      \           19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2
      number$() = "billion", "million", "thousand", "hundred", "ninety", "eighty", \
      \           "seventy", "sixty", "fifty", "forty", "thirty", "twenty", \
      \           "nineteen", "eighteen", "seventeen", "sixteen", "fifteen", \
      \           "fourteen", "thirteen", "twelve", "eleven", "ten", "nine", \
      \           "eight", "seven", "six", "five", "four", "three", "two"

      IF n% < 0 THEN = "minus " + FNsaynumber(-n%)
      IF n% = 0 THEN = "zero"
      IF n% = 1 THEN = "one "

      FOR i% = 0 TO DIM(number%(),1)
        IF n% >= number%(i%) THEN
          t% = n% DIV number%(i%)
          IF t%=1 AND i%<4 a$ += "one " ELSE IF t%<>1 a$ += FNsaynumber(t%)
          a$ += number$(i%)
          t% = n% MOD number%(i%)
          CASE TRUE OF
            WHEN i%>3 AND i%<12 AND t%<>0: a$ += "-"
            WHEN i%<=3 AND t%>=100: a$ += ", "
            WHEN i%<=3 AND t%<>0 AND t%<100: a$ += " and "
            OTHERWISE: a$ += " "
          ENDCASE
          IF t% a$ += FNsaynumber(t%) ELSE IF i%<12 a$ += " "
          EXIT FOR
        ENDIF
      NEXT i%
      = a$


get "libhdr"
manifest $( MAXLEN = 256/BYTESPERWORD $)

let append(v1, v2) be
$(  for i=1 to v2%0 do
        v1%(v1%0+i) := v2%i
    v1%0 := v1%0 + v2%0
$)

let spell(n, v) = valof
$(  let small(n) =
        n=0 -> "",          n=1 -> "one",       n=2 -> "two",
        n=3 -> "three",     n=4 -> "four",      n=5 -> "five",
        n=6 -> "six",       n=7 -> "seven",     n=8 -> "eight",
        n=9 -> "nine",      n=10 -> "ten",      n=11 -> "eleven",
        n=12 -> "twelve",   n=13 -> "thirteen", n=14 -> "fourteen",
        n=15 -> "fifteen",  n=16 -> "sixteen",  n=17 -> "seventeen",
        n=18 -> "eighteen", n=19 -> "nineteen", valof finish

    let teens(n) =
        n=2 -> "twenty",    n=3 -> "thirty",    n=4 -> "forty",
        n=5 -> "fifty",     n=6 -> "sixty",     n=7 -> "seventy",
        n=8 -> "eighty",    n=9 -> "ninety",    valof finish

    let less100(n, v) be
    $(  if n >= 20
        $(  append(v, teens(n/10))
            n := n rem 10
            unless n=0 append(v, "-")
        $)
        append(v, small(n))
    $)

    let inner(n, v) be
    $(  let step(n, val, name, v) = valof
        $(  if n>=val
            $(  inner(n/val, v)
                append(v, name)
                unless n=val do append(v, " ")
            $)
            resultis n rem val
        $)
        test n<0
        $(  append(v, "minus ")
            inner(-n, v)
        $)
        or
        $(  n := step(n, 1000, " thousand", v)
            n := step(n, 100, " hundred", v)
            less100(n, v)
        $)
    $)

    v%0 := 0
    test n=0 do append(v, "zero") or inner(n, v)
    resultis v
$)

let reads(v) be
$(  v%0 := 0
    $(  let c = rdch()
        if c='*N' | c=endstreamch break
        v%0 := v%0 + 1
        v%(v%0) := c
    $) repeat
$)

let atoi(v) = valof
$(  let r = 0 and neg = false and i = 1
    if v%1 = '-' then
    $(  i := 2
        neg := true
    $)
    while '0' <= v%i <= '9' & i <= v%0
    $(  r := r*10 + v%i-'0'
        i := i+1
    $)
    resultis neg -> -r, r
$)

let start() be
$(  let instr = vec MAXLEN and numstr = vec MAXLEN
    $(  writes("Number? ")
        reads(instr)
        if instr%0=0 finish
        writef("%N: %S*N", atoi(instr), spell(atoi(instr), numstr))
    $) repeat
$)


SuperStrict

Framework BRL.StandardIO

spellIt(        99)
spellIt(       300)
spellIt(       310)
spellIt(      1501)
spellIt(     12609)
spellIt(    512609)
spellIt(  43112609)
spellIt(1234567890)

Type TSpell

	Field smallNumbers:String[] = ["zero", "one", "two", "three", "four", "five", ..
		"six", "seven", "eight", "nine", "ten", ..
		"eleven", "twelve", "thirteen", "fourteen", "fifteen", ..
		"sixteen", "seventeen", "eighteen", "nineteen" ]

	Field decades:String[] = [ "", "", "twenty", "thirty", "forty", ..
		"fifty", "sixty", "seventy", "eighty", "ninety" ]

	Field thousandPowers:String[] = [ " billion", " million",  " thousand", "" ]

	Method spellHundreds:String(number:Int)
		Local result:String
		If number > 99 Then
			result = smallNumbers[number / 100]
			result :+ " hundred"
			number = number Mod 100
			If number Then
				result :+ " and "
			End If
		End If

		If number >= 20 Then
			result :+ decades[number / 10]
			number = number Mod 10
			If number Then
				result :+ "-"
			End If
		End If
		If number > 0 And number < 20 Then
			result :+ smallNumbers[number]
		End If

		Return result
	End Method

	Method spell:String(number:Long)
		If number < 20 Then
			Return smallNumbers[number]
		End If
		Local result:String

		Local scaleIndex:Int = 0
		Local scaleFactor:Long = 1000000000:Long ' 1 billion
		While scaleFactor > 0
			If number >= scaleFactor
				Local h:Long = number / scaleFactor
				result :+ spellHundreds(h) + thousandPowers[scaleIndex]
				number = number Mod scaleFactor
				If number Then
					result :+ ", "
				End If
			End If
			scaleFactor :/ 1000
			scaleIndex :+ 1
		Wend

		Return result
	End Method

End Type

Function spellIt(number:Long)
	Local numberSpell:TSpell = New TSpell
	Print number + " " + numberSpell.spell(number)
End Function


#include <stdio.h>
#include <string.h>

const char *ones[] = { 0, "one", "two", "three", "four",
	"five", "six", "seven", "eight", "nine",
	"ten", "eleven", "twelve", "thirteen", "fourteen",
	"fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
const char *tens[] = { 0, "ten", "twenty", "thirty", "forty",
	"fifty", "sixty", "seventy", "eighty", "ninety" };
const char *llions[] = { 0, "thousand", "million", "billion", "trillion",
//	"quadrillion", "quintillion", "sextillion", "septillion",
//	"octillion", "nonillion", "decillion"
	};
const int maxillion = sizeof(llions) / sizeof(llions[0]) * 3 - 3;

int say_hundred(const char *s, int len, int depth, int has_lead)
{
	int c[3], i;
	for (i = -3; i < 0; i++) {
		if (len + i >= 0) c[i + 3] = s[len + i] - '0';
		else c[i + 3] = 0;
	}
	if (!(c[0] + c[1] + c[2])) return 0;

	if (c[0]) {
		printf("%s hundred", ones[c[0]]);
		has_lead = 1;
	}

	if (has_lead && (c[1] || c[2]))
		printf((!depth || c[0]) && (!c[0] || !c[1]) ? "and " :
			c[0] ? " " : "");

	if (c[1] < 2) {
		if (c[1] || c[2]) printf("%s", ones[c[1] * 10 + c[2]]);
	} else {
		if (c[1]) {
			printf("%s", tens[c[1]]);
			if (c[2]) putchar('-');
		}
		if (c[2]) printf("%s", ones[c[2]]);
	}

	return 1;
}

int say_maxillion(const char *s, int len, int depth, int has_lead)
{
	int n = len / 3, r = len % 3;
	if (!r) {
		n--;
		r = 3;
	}
	const char *e = s + r;
	do {
		if (say_hundred(s, r, n, has_lead) && n) {
			has_lead = 1;
			printf(" %s", llions[n]);
			if (!depth) printf(", ");
			else printf(" ");
		}
		s = e; e += 3;
	} while (r = 3, n--);

	return 1;
}

void say_number(const char *s)
{
	int len, i, got_sign = 0;

	while (*s == ' ') s++;
	if (*s < '0' || *s > '9') {
		if (*s == '-') got_sign = -1;
		else if (*s == '+') got_sign = 1;
		else goto nan;
		s++;
	} else
		got_sign = 1;

	while (*s == '0') {
		s++;
		if (*s == '\0') {
			printf("zero\n");
			return;
		}
	}

	len = strlen(s);
	if (!len) goto nan;

	for (i = 0; i < len; i++) {
		if (s[i] < '0' || s[i] > '9') {
			printf("(not a number)");
			return;
		}
	}
	if (got_sign == -1) printf("minus ");

	int n = len / maxillion;
	int r = len % maxillion;
	if (!r) {
		r = maxillion;
		n--;
	}

	const char *end = s + len - n * maxillion;
	int has_lead = 0;
	do {
		if ((has_lead = say_maxillion(s, r, n, has_lead))) {
			for (i = 0; i < n; i++)
				printf(" %s", llions[maxillion / 3]);
			if (n) printf(", ");
		}
		n--;
		r = maxillion;
		s = end;
		end += r;
	} while (n >= 0);

	printf("\n");
	return;

nan:	printf("not a number\n");
	return;
}

int main()
{
	say_number("-42");
	say_number("1984");
	say_number("10000");
	say_number("1024");
	say_number("1001001001001");
	say_number("123456789012345678901234567890123456789012345678900000001");
	return 0;
}


using System;

class NumberNamer {
    static readonly string[] incrementsOfOne =
            { "zero",    "one",     "two",       "three",    "four",
              "five",    "six",     "seven",     "eight",    "nine",
              "ten",     "eleven",  "twelve",    "thirteen", "fourteen",
              "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };

    static readonly string[] incrementsOfTen =
            { "",      "",      "twenty",  "thirty", "fourty",
              "fifty", "sixty", "seventy", "eighty", "ninety" };

    const string millionName = "million",
                 thousandName = "thousand",
                 hundredName = "hundred",
                 andName = "and";

    public static string GetName( int i ) {
        string output = "";
        if( i >= 1000000 ) {
            output += ParseTriplet( i / 1000000 ) + " " + millionName;
            i %= 1000000;
            if( i == 0 ) return output;
        }

        if( i >= 1000 ) {
            if( output.Length > 0 ) {
                output += ", ";
            }
            output += ParseTriplet( i / 1000 ) + " " + thousandName;
            i %= 1000;
            if( i == 0 ) return output;
        }

        if( output.Length > 0 ) {
            output += ", ";
        }
        output += ParseTriplet( i );
        return output;
    }

    static string ParseTriplet( int i ) {
        string output = "";
        if( i >= 100 ) {
            output += incrementsOfOne[i / 100] + " " + hundredName;
            i %= 100;
            if( i == 0 ) return output;
        }

        if( output.Length > 0 ) {
            output += " " + andName + " ";
        }
        if( i >= 20 ) {
            output += incrementsOfTen[i / 10];
            i %= 10;
            if( i == 0 ) return output;
        }

        if( output.Length > 0 ) {
            output += " ";
        }
        output += incrementsOfOne[i];
        return output;
    }
}

class Program { // Test class
    static void Main( string[] args ) {
        Console.WriteLine( NumberNamer.GetName( 1 ) );
        Console.WriteLine( NumberNamer.GetName( 234 ) );
        Console.WriteLine( NumberNamer.GetName( 31337 ) );
        Console.WriteLine( NumberNamer.GetName( 987654321 ) );
    }
}


#include <string>
#include <iostream>
using std::string;

const char* smallNumbers[] = {
  "zero", "one", "two", "three", "four", "five",
  "six", "seven", "eight", "nine", "ten",
  "eleven", "twelve", "thirteen", "fourteen", "fifteen",
  "sixteen", "seventeen", "eighteen", "nineteen"
};

string spellHundreds(unsigned n) {
  string res;
  if (n > 99) {
    res = smallNumbers[n/100];
    res += " hundred";
    n %= 100;
    if (n) res += " and ";
  }
  if (n >= 20) {
    static const char* Decades[] = {
      "", "", "twenty", "thirty", "forty",
      "fifty", "sixty", "seventy", "eighty", "ninety"
    };
    res += Decades[n/10];
    n %= 10;
    if (n) res += "-";
  }
  if (n < 20 && n > 0)
    res += smallNumbers[n];
  return res;
}

const char* thousandPowers[] = {
  " billion", " million",  " thousand", "" };

typedef unsigned long Spellable;

string spell(Spellable n) {
  if (n < 20) return smallNumbers[n];
  string res;
  const char** pScaleName = thousandPowers;
  Spellable scaleFactor = 1000000000;	// 1 billion
  while (scaleFactor > 0) {
    if (n >= scaleFactor) {
      Spellable h = n / scaleFactor;
      res += spellHundreds(h) + *pScaleName;
      n %= scaleFactor;
      if (n) res += ", ";
    }
    scaleFactor /= 1000;
    ++pScaleName;
  }
  return res;
}

int main() {
#define SPELL_IT(x) std::cout << #x " " << spell(x) << std::endl;
  SPELL_IT(      99);
  SPELL_IT(     300);
  SPELL_IT(     310);
  SPELL_IT(    1501);
  SPELL_IT(   12609);
  SPELL_IT(  512609);
  SPELL_IT(43112609);
  SPELL_IT(1234567890);
  return 0;
}


(clojure.pprint/cl-format nil "~R" 1234)
=> "one thousand, two hundred thirty-four"


spell_integer = (n) ->
  tens = [null, null, "twenty", "thirty", "forty",
      "fifty", "sixty", "seventy", "eighty", "ninety"]

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

  bl = [null, null, "m", "b", "tr", "quadr",
      "quint", "sext", "sept", "oct", "non", "dec"]

  divmod = (n, d) ->
    [Math.floor(n / d), n % d]

  nonzero = (c, n) ->
    if n == 0
      ""
    else
      c + spell_integer n

  big = (e, n) ->
    if e == 0
      spell_integer n
    else if e == 1
      spell_integer(n) + " thousand"
    else
      spell_integer(n) + " " + bl[e] + "illion"

  base1000_rev = (n) ->
    # generates the value of the digits of n in base 1000
    # (i.e. 3-digit chunks), in reverse.
    chunks = []
    while n != 0
      [n, r] = divmod n, 1000
      chunks.push r
    chunks

  if n < 0
    throw Error "spell_integer: negative input"
  else if n < 20
    small[n]
  else if n < 100
    [a, b] = divmod n, 10
    tens[a] + nonzero("-", b)
  else if n < 1000
    [a, b] = divmod n, 100
    small[a] + " hundred" + nonzero(" ", b)
  else
    chunks = (big(exp, x) for x, exp in base1000_rev(n) when x)
    chunks.reverse().join ', '

# example
console.log spell_integer 1278
console.log spell_integer 1752
console.log spell_integer 2010
console.log spell_integer 4000123007913


10 print chr$(147);chr$(14)
20 dim s$(11),ts$(11),t$(11),o$(11):co=39
30 for i=0 to 11:read s$(i),ts$(i),t$(i),o$(i):next
40 print "Enter a number";:input n$
45 ou$=""
50 if len(n$)>36 then print:print "Too long.":print:goto 40
51 print
55 rem check for negative
56 if left$(n$,1)="-" then n$=right$(n$,len(n$)-1):ou$="negative ":gosub 500
60 no=int((len(n$)-1)/3)
70 rem pad left side
71 p=(no+1)*3-len(n$)
75 if p>0 then n$="0"+n$:p=p-1:goto 75
77 if val(n$)=0 then ou$=s$(0):gosub 500:goto 125
80 rem calculate left to right
81 for i=no to 0 step -1:oi=no-i
85 ch$=mid$(n$,1+(oi*3),3)
90 h=val(mid$(ch$,1,1)):t=val(mid$(ch$,2,1)):s=val(mid$(ch$,3,1))
93 if h=0 and t=0 and s=0 then goto 120
95 if h>0 then ou$=s$(h)+" hundred ":gosub 500
100 if t>1 then ou$=t$(t)+mid$("- ",abs(s=0)+1,1):gosub 500
105 if t=1 then ou$=ts$(s)+" ":gosub 500
110 if t<>1 and s>0 then ou$=s$(s)+" ":gosub 500
115 ou$=o$(i)+" ":gosub 500
120 next i
125 print:print
130 print "Another? (y/n) ";
140 get k$:ifk$<>"y" and k$<>"n" then 140
145 print k$
150 if k$="y" then print:goto 40
200 end
500 rem print with word wrapping
505 cp=pos(0):nl=len(ou$)
510 if cp>co-nl then print
520 print ou$;
599 return
1000 data zero,ten,"",""
1001 data one,eleven,ten,thousand
1002 data two,twelve,twenty,million
1003 data three,thirteen,thirty,billion
1004 data four,fourteen,forty,trillion
1005 data five,fifteen,fifty,quadrillion
1006 data six,sixteen,sixty,quintillion
1007 data seven,seventeen,seventy,sextillion
1008 data eight,eighteen,eighty,septillion
1009 data nine,nineteen,ninety,octillion
1010 data "","","",nonillion
1011 data "","","",decillion


(format nil "~R" 1234)
=> "one thousand two hundred thirty-four"


import std.stdio, std.array, std.algorithm, std.bigint, std.range;

immutable tens = ["", "", "twenty", "thirty", "forty",
                  "fifty", "sixty", "seventy", "eighty", "ninety"];
immutable small = ["zero", "one", "two", "three", "four", "five",
                   "six", "seven", "eight", "nine", "ten", "eleven",
                   "twelve", "thirteen", "fourteen", "fifteen",
                   "sixteen", "seventeen", "eighteen", "nineteen"];
immutable huge = ["", ""] ~ ["m", "b", "tr", "quadr", "quint",
                             "sext", "sept", "oct", "non", "dec"]
                            .map!q{ a ~ "illion" }.array;

string spellBigInt(BigInt n) pure /*nothrow @safe*/ {
    static string nonZero(string c, BigInt n, string connect="") pure /*nothrow @safe*/ {
        return (n == 0) ? "" : (connect ~ c ~ n.spellBigInt);
    }

    static string lastAnd(string num) pure /*nothrow*/ @safe {
        if (num.canFind(',')) {
            string pre = num.retro.find(',').retro[0 .. $ - 1];
            string last = num[pre.length + 1 .. $];
            if (!last.canFind(" and "))
                last = " and" ~ last;
            num = pre ~ ',' ~ last;
        }
        return num;
    }

    static string big(in uint e, in BigInt n) pure /*nothrow @safe*/ {
        switch (e) {
            case 0:  return n.spellBigInt;
            case 1:  return n.spellBigInt ~ " thousand";
            default: return n.spellBigInt ~ " " ~ huge[e];
        }
    }

    if (n < 0) {
        return "minus " ~ spellBigInt(-n);
    } else if (n < 20) {
        return small[n.toInt];
    } else if (n < 100) {
        immutable BigInt a = n / 10;
        immutable BigInt b = n % 10;
        return tens[a.toInt] ~ nonZero("-", b);
    } else if (n < 1_000) {
        immutable BigInt a = n / 100;
        immutable BigInt b = n % 100;
        return small[a.toInt] ~ " hundred" ~ nonZero(" ", b, " and");
    } else {
        string[] bigs;
        uint e = 0;
        while (n != 0) {
            immutable BigInt r = n % 1_000;
            n /= 1_000;
            if (r != 0)
                bigs ~= big(e, r);
            e++;
        }

        return lastAnd(bigs.retro.join(", "));
    }
}

version(number_names_main) {
    void main() {
        foreach (immutable n; [0, -3, 5, -7, 11, -13, 17, -19, 23, -29])
            writefln("%+4d -> %s", n, n.BigInt.spellBigInt);
        writeln;

        auto n = 2_0121_002_001;
        while (n) {
            writefln("%-12d -> %s", n, n.BigInt.spellBigInt);
            n /= -10;
        }
        writefln("%-12d -> %s", n, n.BigInt.spellBigInt);
        writeln;
    }
}


program Number_names;

{$APPTYPE CONSOLE}

const
  smallies: array[1..19] of string = ('one', 'two', 'three', 'four', 'five',
    'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen',
    'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen');
  tens: array[2..9] of string = ('twenty', 'thirty', 'forty', 'fifty', 'sixty',
    'seventy', 'eighty', 'ninety');

function domaxies(number: int64): string;
const
  maxies: array[0..5] of string = (' thousand', ' million', ' billion',
    ' trillion', ' quadrillion', ' quintillion');
begin
  domaxies := '';
  if number >= 0 then
    domaxies := maxies[number];
end;

function doHundreds(number: int64): string;
begin
  Result := '';
  if number > 99 then
  begin
    Result := smallies[number div 100];
    Result := Result + ' hundred';
    number := number mod 100;
    if number > 0 then
      Result := Result + ' and ';
  end;
  if number >= 20 then
  begin
    Result := Result + tens[number div 10];
    number := number mod 10;
    if number > 0 then
      Result := Result + '-';
  end;
  if (0 < number) and (number < 20) then
    Result := Result + smallies[number];
end;

function spell(number: int64): string;
var
  scaleFactor: int64;
  maxieStart, h: int64;
begin
  Result := '';
  if number < 0 then
  begin
    number := -number;
    Result := 'negative ';
  end;
  scaleFactor := 1000000000000000000;
  maxieStart := 5;
  if number < 20 then
     exit(Result+smallies[number]);
  while scaleFactor > 0 do
  begin
    if number > scaleFactor then
    begin
      h := number div scaleFactor;
      Result := Result + doHundreds(h) + domaxies(maxieStart);
      number := number mod scaleFactor;
      if number > 0 then
        Result := Result + ', ';
    end;
    scaleFactor := scaleFactor div 1000;
    dec(maxieStart);
  end;
end;

begin
  writeln(99, ': ', spell(99));
  writeln(234, ': ', spell(234));
  writeln(7342, ': ', spell(7342));
  writeln(32784, ': ', spell(32784));
  writeln(234345, ': ', spell(234345));
  writeln(2343451, ': ', spell(2343451));
  writeln(23434534, ': ', spell(23434534));
  writeln(234345456, ': ', spell(234345456));
  writeln(2343454569, ': ', spell(2343454569));
  writeln(2343454564356, ': ', spell(2343454564356));
  writeln(2345286538456328, ': ', spell(2345286538456328));
  Readln;
end.


defmodule RC do
  @small  ~w(zero one two three four five six seven eight nine ten
             eleven twelve thirteen fourteen fifteen sixteen seventeen
             eighteen nineteen)
  @tens  ~w(wrong wrong twenty thirty forty fifty sixty seventy eighty ninety)
  @big  [nil, "thousand"] ++
        (~w( m b tr quadr quint sext sept oct non dec) |> Enum.map(&"#{&1}illion"))

  def wordify(number) when number<0, do: "negative #{wordify(-number)}"
  def wordify(number) when number<20, do: Enum.at(@small,number)
  def wordify(number) when number<100 do
    rm = rem(number,10)
    Enum.at(@tens,div(number,10)) <> (if rm==0, do: "", else: "-#{wordify(rm)}")
  end
  def wordify(number) when number<1000 do
    rm = rem(number,100)
    "#{Enum.at(@small,div(number,100))} hundred" <> (if rm==0, do: "", else: " and #{wordify(rm)}")
  end
  def wordify(number) do
    # separate into 3-digit chunks
    chunks = chunk(number, [])
    if length(chunks) > length(@big), do: raise(ArgumentError, "Integer value too large.")
    Enum.map(chunks, &wordify(&1))
    |> Enum.zip(@big)
    |> Enum.filter_map(fn {a,_} -> a != "zero" end, fn {a,b} -> "#{a} #{b}" end)
    |> Enum.reverse
    |> Enum.join(", ")
  end

  defp chunk(0, res), do: Enum.reverse(res)
  defp chunk(number, res) do
    chunk(div(number,1000), [rem(number,1000) | res])
  end
end

data = [-1123, 0, 1, 20, 123, 200, 220, 1245, 2000, 2200, 2220, 467889,
        23_000_467, 23_234_467, 2_235_654_234, 12_123_234_543_543_456,
        987_654_321_098_765_432_109_876_543_210_987_654,
        123890812938219038290489327894327894723897432]

Enum.each(data, fn n ->
  IO.write "#{n}: "
  try do
    IO.inspect RC.wordify(n)
  rescue
    e in ArgumentError -> IO.puts Exception.message(e)
  end
end)


-module(nr2eng).
-import(lists, [foreach/2, seq/2, append/2]).
-import(string, [strip/3, str/2]).
-export([start/0]).

sym(1) -> "one";
sym(2) -> "two";
sym(3) -> "three";
sym(4) -> "four";
sym(5) -> "five";
sym(6) -> "six";
sym(7) -> "seven";
sym(8) -> "eight";
sym(9) -> "nine";
sym(10) -> "ten";
sym(11) -> "eleven";
sym(12) -> "twelve";
sym(13) -> "thirteen";
sym(20) -> "twenty";
sym(30) -> "thirty";
sym(40) -> "forty";
sym(50) -> "fifty";
sym(100) -> "hundred";
sym(1000) -> "thousand";
sym(1000*1000) -> "million";
sym(1000*1000*1000) -> "billion";
sym(_) -> "".

next(1000) -> 100;
next(100) -> 10;
next(10) -> 1;
next(X) -> X div 1000.

concat(PRE, "") ->
   PRE;
concat(PRE, POST) ->
   PRE++" "++POST.
concat("", _, POST) ->
   POST;
concat(PRE, SYM, "") ->
   PRE++" "++SYM;
concat(PRE, SYM, POST) ->
   PRE++" "++SYM++" "++POST.

nr2eng(0, _) ->
   "";
nr2eng(NR, 1) ->
   sym(NR);
nr2eng(NR, 10) when NR =< 20 ->
   case sym(NR) of
        "" -> strip(sym(NR-10), right, $t) ++ "teen";
        _  -> sym(NR)
   end;
nr2eng(NR, 10) ->
   concat(
     case sym((NR div 10)*10) of
        "" -> strip(sym(NR div 10), right, $t) ++ "ty";
        _  -> sym((NR div 10)*10)
     end,
     nr2eng(NR rem 10, 1));
nr2eng(NR, B) ->
   PRE  = nr2eng(NR div B, next(B)),
   POST = nr2eng(NR rem B, next(B)),
   AND  = str(POST, "and"),
   COMMA = if
              POST == "" -> "";
              AND == 0 -> " and";
              B >= 1000 -> ",";
              true -> ""
   end,
   concat(PRE,  sym(B)++COMMA, POST).

start() ->
   lists:foreach(
     fun (X) -> io:fwrite("~p ~p ~n", [X, nr2eng(X, 1000000000)])
     end,
     append(seq(1, 2000), [123123, 43234234])).


function abs(atom i)
    if i < 0 then
        return -i
    else
        return i
    end if
end function

constant small = {"one", "two", "three", "four", "five", "six", "seven", "eight",
    "nine", "ten","eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
    "seventeen", "eighteen", "nineteen"}

constant tens = {"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty",
    "ninety"}

constant big = {"thousand", "million", "billion"}

function int2text(atom number)
    atom num
    integer unit, tmpLng1
    sequence outP
    outP = ""
    num = 0
    unit = 1
    tmpLng1 = 0

    if number = 0 then
        return "zero"
    end if

    num = abs(number)
    while 1 do
        tmpLng1 = remainder(num,100)
        if tmpLng1 > 0 and tmpLng1 < 20 then
            outP = small[tmpLng1] & ' ' & outP
        elsif tmpLng1 >= 20 then
            if remainder(tmpLng1,10) = 0 then
                outP = tens[floor(tmpLng1/10)-1] & ' ' & outP
            else
                outP = tens[floor(tmpLng1/10)-1] & '-' & small[remainder(tmpLng1, 10)] & ' ' & outP
            end if
        end if

        tmpLng1 = floor(remainder(num, 1000) / 100)
        if tmpLng1 then
            outP = small[tmpLng1] & " hundred " & outP
        end if

        num = floor(num/1000)
        if num < 1 then
            exit
        end if

        tmpLng1 = remainder(num,1000)
        if tmpLng1 then
            outP = big[unit] & ' ' & outP
        end if

        unit = unit + 1
    end while

    if number < 0 then
        outP = "negative " & outP
    end if

    return outP[1..$-1]
end function

puts(1,int2text(900000001) & "\n")
puts(1,int2text(1234567890) & "\n")
puts(1,int2text(-987654321) & "\n")
puts(1,int2text(0) & "\n")


let divMod n d = n / d, n % d

let join = String.concat ", "

let rec nonzero = function
  | _, 0 -> ""
  | c, n -> c + (spellInteger n)

and tens n =
  [| ""; ""; "twenty"; "thirty"; "forty"; "fifty";
             "sixty"; "seventy"; "eighty"; "ninety" |].[n]

and small n =
  [| "zero"; "one"; "two"; "three"; "four"; "five";
     "six"; "seven"; "eight"; "nine"; "ten"; "eleven";
     "twelve"; "thirteen"; "fourteen"; "fifteen";
     "sixteen";"seventeen"; "eighteen"; "nineteen" |].[n]

and bl = [| ""; ""; "m"; "b"; "tr"; "quadr"; "quint";
                    "sext"; "sept"; "oct"; "non"; "dec" |]

and big = function
  | 0, n -> (spellInteger n)
  | 1, n -> (spellInteger n) + " thousand"
  | e, n -> (spellInteger n) + " " + bl.[e] + "illion"

and uff acc = function
  | 0 -> List.rev acc
  | n ->
      let a, b = divMod n 1000
      uff (b::acc) a

and spellInteger = function
  | n when n < 0 -> "minus " + spellInteger (abs n)
  | n when n < 20 -> small n
  | n when n < 100 ->
      let a, b = divMod n 10
      (tens a) + nonzero ("-", b)
  | n when n < 1000 ->
      let a, b = divMod n 100
      (small a) + " hundred" + nonzero (" ", b)
  | n ->
      let seg = uff [] n
      let _, segn =
        (* just add the index of the item in the list *)
        List.fold
          (fun (i,acc) v -> i + 1, (i, v)::acc)
          (0, [])
          seg

      let fsegn =
        (* remove right part "zero" *)
        List.filter
          (function (_, 0) -> false | _ -> true)
          segn

      join (List.map big fsegn)
;;


IN: scratchpad USE: math.text.english
IN: scratchpad 43112609 number>text print
forty-three million, one hundred and twelve thousand, six hundred and nine


dim shared as string*9 lows(0 to 19) = {"", "one", "two", "three", "four",_
    "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve",_
    "thirteen", "fourteen", "fifteen", "sixteen", "seventeen",_
    "eighteen", "nineteen"}
dim shared as string*7 tens(0 to 9) = {"", "", "twenty", "thirty", "forty",_
    "fifty", "sixty", "seventy", "eighty", "ninety"}
dim shared as string*8 lev(0 to 3) = {"", "thousand", "million", "billion"}

function numname_int( byval n as integer ) as string
    if n = 0 then return "zero"
    if n < 0 then return "negative " + numname_int( -n )
    dim as integer t = -1, lasttwo, hundreds
    redim as integer triples(0 to 0)
    dim as string ret, tripname
    while n > 0
        t += 1
        triples(t) = n mod 1000
        n \= 1000
    wend
    for i as integer = t to 0 step -1
        tripname = ""
        if triples(i) = 0 then continue for
        lasttwo = triples(i) mod 100
        hundreds = triples(i)\100
        if lasttwo < 20 then
            tripname = lows(lasttwo) + tripname + " "
        else
            tripname = tens(lasttwo\10) + "-" + lows(lasttwo mod 10) + " " + tripname
        end if
        if hundreds > 0 then
             if lasttwo > 0 then tripname = " and " + tripname
             tripname = lows(hundreds)+" hundred" + tripname
        end if
        if i=0 and t>0 and hundreds = 0 then tripname = " and " + tripname
        tripname += lev(i)+" "
        ret = ltrim(ret) + ltrim(tripname)
    next i
    return ltrim(rtrim(ret))
end function

function numname( n as double ) as string
    if n=int(n) then return numname_int(int(n))
    dim as string prefix = numname_int( int(abs(n)) )+" point "
    dim as string decdig = str(abs(n)-int(abs(n))), ret
    if n < 0 then prefix = "negative "+prefix
    ret = prefix
    for i as uinteger = 3 to len(decdig)
        ret = ret + numname(val(mid(decdig,i,1)))+" "
    next i
    return ltrim(rtrim(ret))
end function

print numname(0)
print numname(1.0)
print numname(-1.7)
print numname(910000)
print numname(987654)
print numname(100000017)


program spell

  implicit none
  integer :: e
  integer :: i
  integer :: m
  integer :: n
  character (9), dimension (19), parameter :: small =       &
    & (/'one      ', 'two      ', 'three    ', 'four     ', &
    &   'five     ', 'six      ', 'seven    ', 'eight    ', &
    &   'nine     ', 'ten      ', 'eleven   ', 'twelve   ', &
    &   'thirteen ', 'fourteen ', 'fifteen  ', 'sixteen  ', &
    &   'seventeen', 'eighteen ', 'nineteen '/)
  character (7), dimension (2 : 9), parameter :: tens =        &
    & (/'twenty ', 'thirty ', 'forty  ', 'fifty  ', 'sixty  ', &
    &   'seventy', 'eighty ', 'ninety '/)
  character (8), dimension (3), parameter :: big = &
    & (/'thousand', 'million ', 'billion '/)
  character (256) :: r

  do
    read (*, *, iostat = i) n
    if (i /= 0) then
      exit
    end if
    if (n == 0) then
      r = 'zero'
    else
      r = ''
      m = abs (n)
      e = 0
      do
        if (m == 0) then
          exit
        end if
        if (modulo (m, 1000) > 0) then
          if (e > 0) then
            r = trim (big (e)) // ' ' // r
          end if
          if (modulo (m, 100) > 0) then
            if (modulo (m, 100) < 20) then
              r = trim (small (modulo (m, 100))) // ' ' // r
            else
              if (modulo (m, 10) > 0) then
                r = trim (small (modulo (m, 10))) // ' ' // r
                r = trim (tens (modulo (m, 100) / 10)) // '-' // r
              else
                r = trim (tens (modulo (m, 100) / 10)) // ' ' // r
              end if
            end if
          end if
          if (modulo (m, 1000) / 100 > 0) then
            r = 'hundred' // ' ' // r
            r = trim (small (modulo (m, 1000) / 100)) // ' ' // r
          end if
        end if
        m = m / 1000
        e = e + 1
      end do
      if (n < 0) then
        r = 'negative' // ' ' // r
      end if
    end if
    write (*, '(a)') trim (r)
  end do

end program spell


package main

import "fmt"

func main() {
	for _, n := range []int64{12, 1048576, 9e18, -2, 0} {
		fmt.Println(say(n))
	}
}

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

func say(n int64) string {
	var t string
	if n < 0 {
		t = "negative "
		// Note, for math.MinInt64 this leaves n negative.
		n = -n
	}
	switch {
	case n < 20:
		t += small[n]
	case n < 100:
		t += tens[n/10]
		s := n % 10
		if s > 0 {
			t += "-" + small[s]
		}
	case n < 1000:
		t += small[n/100] + " hundred"
		s := n % 100
		if s > 0 {
			t += " " + say(s)
		}
	default:
		// work right-to-left
		sx := ""
		for i := 0; n > 0; i++ {
			p := n % 1000
			n /= 1000
			if p > 0 {
				ix := say(p) + illions[i]
				if sx != "" {
					ix += " " + sx
				}
				sx = ix
			}
		}
		t += sx
	}
	return t
}


def divMod(BigInteger number, BigInteger divisor) {
    def qr = number.divideAndRemainder(divisor)
    [div:qr[0], remainder:qr[1]]
}

def toText(value) {
    value = value as BigInteger
    def units = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
            'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen']
    def tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety']
    def big = ['', 'thousand'] + ['m', 'b', 'tr', 'quadr', 'quint', 'sext', 'sept', 'oct', 'non', 'dec'].collect { "${it}illion"}

    if (value < 0) {
        "negative ${toText(-value)}"
    } else if (value < 20) {
        units[value]
    } else if (value < 100) {
        divMod(value, 10).with { "${tens[div]} ${units[remainder]}".replace(' zero', '') }
    } else if (value < 1000) {
        divMod(value, 100).with { "${toText(div)} hundred and ${toText(remainder)}".replace(' and zero', '') }
    } else {
        def chunks = []
        while (value != 0) {
            divMod(value, 1000).with {
                chunks << remainder
                value = div
            }
        }
        if (chunks.size() > big.size()) {
            throw new IllegalArgumentException("Number overflow")
        }
        def text = []
        (0..<chunks.size()).each { index ->
            if (chunks[index] > 0) {
                text << "${toText(chunks[index])}${index == 0 ? '' : ' ' + big[index]}"
                if (index == 0 && chunks[index] < 100) {
                    text << "and"
                }
            }
        }
        text.reverse().join(', ').replace(', and,', ' and')
    }
}

// Add this method to all Numbers
Number.metaClass.toText = { toText(delegate) }

println toText(29)
println 40.toText()
println toText(401)
println 9003.toText()
println toText(8011673)
println 8000100.toText()
println 4629436.toText()
948623487512387455323784623842314234.toText().split(',').each { println it.trim() }

def verifyToText(expected, value) {
    println "Checking '$expected' == $value"
    def actual = value.toText()
    assert expected == actual
}

verifyToText 'nineteen', 19
verifyToText 'one thousand, two hundred and thirty four', 1234
verifyToText 'twenty three million, four hundred and fifty nine thousand, six hundred and twelve', 23459612
verifyToText 'one thousand, nine hundred and ninety nine', 1999
verifyToText 'negative six hundred and one', -601
verifyToText 'twelve billion and nineteen', 12000000019
verifyToText 'negative one billion, two hundred and thirty four million, five hundred and sixty seven thousand, eight hundred and ninety', -1234567890
verifyToText 'one hundred and one', 101
verifyToText 'one thousand and one', 1001
verifyToText 'one million, one hundred and one', 1000101
verifyToText 'one million and forty five', 1000045
verifyToText 'one million and fifteen', 1000015
verifyToText 'one billion, forty five thousand and one', 1000045001


import Data.List (intercalate, unfoldr)

spellInteger :: Integer -> String
spellInteger n
 | n <    0  = "negative " ++ spellInteger (-n)
 | n <   20  = small n
 | n <  100  = let (a, b) = n `divMod` 10
               in  tens a ++ nonzero '-' b
 | n < 1000  = let (a, b) = n `divMod` 100
               in  small a ++ " hundred" ++ nonzero ' ' b
 | otherwise = intercalate ", " $ map big $ reverse $
               filter ((/= 0) . snd) $ zip [0..] $ unfoldr uff n

 where nonzero :: Char -> Integer -> String
       nonzero _ 0 = ""
       nonzero c n = c : spellInteger n

       uff :: Integer -> Maybe (Integer, Integer)
       uff 0 = Nothing
       uff n = Just $ uncurry (flip (,)) $ n `divMod` 1000

       small, tens :: Integer -> String
       small = (["zero", "one", "two", "three", "four", "five",
            "six", "seven", "eight", "nine", "ten", "eleven",
            "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
            "seventeen", "eighteen", "nineteen"] !!) . fromEnum
       tens = ([undefined, undefined, "twenty", "thirty", "forty",
           "fifty", "sixty", "seventy", "eighty", "ninety"] !!) .
           fromEnum

       big :: (Int, Integer) -> String
       big (0, n) = spellInteger n
       big (1, n) = spellInteger n ++ " thousand"
       big (e, n) = spellInteger n ++ ' ' : (l !! e) ++ "illion"
         where l = [undefined, undefined, "m", "b", "tr", "quadr",
                   "quint", "sext", "sept", "oct", "non", "dec"]


SUBROUTINE NumberToWords(number)
 CHARACTER outP*255, small*130, tens*80, big*80
 REAL ::   decimal_places = 7
 INIT( APPENDIX("#literals"), small, tens, big)

 num = ABS( INT(number) )
 order = 0
 outP = ' '
 DO i = 1, num + 1
   tmp = MOD(num, 100)
   IF(tmp > 19) THEN
       EDIT(Text=tens, ITeM=INT(MOD(tmp/10, 10)), Parse=medium)
       IF( MOD(tmp, 10) ) THEN
           EDIT(Text=small, ITeM=MOD(tmp,10)+1, Parse=mini)
           outP = medium // '-' // mini // ' ' // outP
       ELSE
           outP = medium // ' ' // outP
       ENDIF
   ELSEIF(tmp > 0) THEN
       EDIT(Text=small, ITeM=tmp+1, Parse=mini)
       outP = mini // ' '// outP
   ELSEIF(number == 0) THEN
       outP = 'zero'
   ENDIF

   tmp = INT(MOD(num, 1000) / 100)
   IF(tmp) THEN
       EDIT(Text=small, ITeM=tmp+1, Parse=oneto19)
       outP = oneto19 // ' hundred ' // outP
   ENDIF

   num = INT(num /1000)
   IF( num == 0) THEN
       IF(number < 0) outP = 'minus ' // outP
       fraction = ABS( MOD(number, 1) )
       IF(fraction) WRITE(Text=outP, APPend) ' point'
       DO j = 1, decimal_places
         IF( fraction >= 10^(-decimal_places) ) THEN
             num = INT( 10.01 * fraction )
             EDIT(Text=small, ITeM=num+1, Parse=digit)
             WRITE(Text=outP, APPend) ' ', digit
             fraction = 10*fraction - num
         ENDIF
       ENDDO
       OPEN(FIle="temp.txt", APPend)
       WRITE(FIle="temp.txt", Format='F10, " = ", A', CLoSe=1) number, outP
       RETURN
   ENDIF

   order = order + 1
   EDIT(Text=big, ITeM=order, Parse=kilo)
   IF( MOD(num, 1000) ) outP = kilo // ' and '// outP
 ENDDO
END

CALL NumberToWords( 0 )
CALL NumberToWords( 1234 )
CALL NumberToWords( 1234/100 )
CALL NumberToWords( 10000000 + 1.2 )
CALL NumberToWords( 2^15 )
CALL NumberToWords( 0.001 )
CALL NumberToWords( -EXP(1) )

#literals
 SMALL= zero one two three four five six seven eight nine ten &
 eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen

 TENS=ten twenty thirty forty fifty sixty seventy eighty ninety

 BIG=thousand million billion trillion quadrillion


link numbers    # commas, spell

procedure main(arglist)
every x := !arglist do
   write(commas(x), " -> ",spell(x))
end


u=. ;:'one two three four five six seven eight nine'
v=. ;:'ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen'
t=. ;:'twenty thirty forty fifty sixty seventy eighty ninety'
EN100=: '' ; u , v , , t ,&.>/ '';'-',&.>u

z=. '' ; 'thousand' ; (;:'m b tr quadr quint sext sept oct non'),&.> <'illion'
u=. ;:'un duo tre quattuor quin sex septen octo novem'
t=. (;:'dec vigint trigint quadragint quinquagint sexagint septuagint octogint nonagint'),&.><'illion'
ENU=: z , (, t ,~&.>/ '';u) , <'centillion'

en3=: 4 : 0
 'p q'=. 0 100#:y
 (p{::EN100),((*p)#' hundred'),((p*&*q)#x),q{::EN100
)

en=: 4 : 0
 d=. 1000&#.^:_1 y
 assert. (0<:y) *. ((=<.)y) *. d <:&# ENU
 c=. x&en3&.> (*d)#d
 ((0=y)#'zero') , (-2+*{:d) }. ; , c,.(<' '),.(ENU{~I.&.|.*d),.<', '
)

uk=: ' and '&en   NB. British
us=: ' '    &en   NB. American


public enum IntToWords {
    ;

    private static final String[] small = {
            "", "one", "two", "three", "four",
            "five", "six", "seven", "eight", "nine",
            "ten", "eleven", "twelve", "thirteen", "fourteen",
            "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"};
    private static final String[] tens = {
            "", "", "twenty", "thirty", "forty",
            "fifty", "sixty", "seventy", "eighty", "ninety"};
    private static final String[] big = {
            "", "thousand", "million", "billion", "trillion",
            "quadrillion", "quintillion"};

    public static void main(String[] args) {
        System.out.println(int2Text(0));
        System.out.println(int2Text(10));
        System.out.println(int2Text(30));
        System.out.println(int2Text(47));
        System.out.println(int2Text(100));
        System.out.println(int2Text(999));
        System.out.println(int2Text(1000));
        System.out.println(int2Text(9999));
        System.out.println(int2Text(123_456));
        System.out.println(int2Text(900_000_001));
        System.out.println(int2Text(1_234_567_890));
        System.out.println(int2Text(-987_654_321));
        System.out.println(int2Text(Long.MAX_VALUE));
        System.out.println(int2Text(Long.MIN_VALUE));
    }

    public static String int2Text(long number) {
        StringBuilder sb = new StringBuilder();

        if (number == 0) {
            return "zero";
        }

        long num = -Math.abs(number);

        int unit = 1;
        while (true) {
            int rem100 = (int) -(num % 100);
            if (rem100 >= 20) {
                if (rem100 % 10 == 0) {
                    sb.insert(0, tens[rem100 / 10] + " ");
                } else {
                    sb.insert(0, tens[rem100 / 10] + "-" + small[rem100 % 10] + " ");
                }
            } else if (rem100 != 0) {
                sb.insert(0, small[rem100] + " ");
            }

            int hundreds = (int) -(num % 1000) / 100;
            if (hundreds != 0) {
                sb.insert(0, small[hundreds] + " hundred ");
            }

            num /= 1000;
            if (num == 0) {
                break;
            }

            int rem1000 = (int) -(num % 1000);
            if (rem1000 != 0) {
                sb.insert(0, big[unit] + " ");
            }
            unit++;
        }

        if (number < 0) {
            sb.insert(0, "negative ");
        }

        return sb.toString().trim();
    }
}


const divMod = y => x => [Math.floor(y/x), y % x];

const sayNumber = value => {
  let name = '';
  let quotient, remainder;
  const dm = divMod(value);
  const units = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven',
    'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen',
    'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'];
  const tens = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty',
    'seventy', 'eighty', 'ninety'];
  const big = [...['', 'thousand'], ...['m', 'b', 'tr', 'quadr', 'quint',
    'sext', 'sept', 'oct', 'non', 'dec'].map(e => `${e}illion`)];

  if (value < 0) {
    name = `negative ${sayNumber(-value)}`
  } else if (value < 20) {
    name = units[value]
  } else if (value < 100) {
    [quotient, remainder] = dm(10);
    name = `${tens[quotient]} ${units[remainder]}`.replace(' zero', '');
  } else if (value < 1000) {
    [quotient, remainder] = dm(100);
    name = `${sayNumber(quotient)} hundred and ${sayNumber(remainder)}`
      .replace(' and zero', '')
  } else {
    const chunks = [];
    const text = [];
    while (value !== 0) {
      [value, remainder] = divMod(value)(1000);
      chunks.push(remainder);
    }
    chunks.forEach((e,i) => {
      if (e > 0) {
        text.push(`${sayNumber(e)}${i === 0 ? '' : ' ' + big[i]}`);
        if (i === 0 && e < 100) {
          text.push('and');
        }
      }
    });
    name = text.reverse().join(', ').replace(', and,', ' and');
  }
  return name;
};


DEFINE units ==
[ "zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten"
  "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen" "seventeen"
  "eighteen" "nineteen" ];

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

convert6 ==
[1000000 <]
[1000 div swap convert " thousand " putchars convert3]
[1000000 div swap convert " million " putchars convert3]
ifte;

convert5 ==
[null]
[]
[" and " putchars convert]
ifte;

convert4 ==
[1000 <]
[100 div swap units of putchars " hundred" putchars convert5]
[convert6]
ifte;

convert3 ==
[null]
[]
[32 putch convert]
ifte;

convert2 ==
[100 <]
[10 div swap pred tens of putchars convert3]
[convert4]
ifte;

convert ==
[20 <]
[units of putchars]
[convert2]
ifte.


# Adapted from the go version.
# Tested with jq 1.4
#
# say/0 as defined here supports positive and negative integers within
# the range of accuracy of jq, or up to the quintillions, whichever is
# less.  As of jq version 1.4, jq's integer accuracy is about 10^16.

def say:

  # subfunction zillions recursively handles the thousands,
  # millions, billions, etc.
  #   input: the number
  #   i: which "illion" to use
  #   sx: the string so far
  #   output: the updated string
  def zillions(i; sx):
    ["thousand", "million", "billion",
      "trillion", "quadrillion", "quintillion"] as $illions
    | if . == 0 then sx
       else (. / 1000 | floor)
            | (. % 1000) as $p
            | zillions(i + 1;
                       if $p > 0 then
                          (($p | say) + " " + $illions[i]) as $ix
                          | if sx != "" then $ix + ", " + sx
                            else $ix
                            end
                       else sx
                       end)
       end
  ;

  [ "", "one", "two", "three", "four", "five", "six", "seven",
    "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
    "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"] as $small
  | ["ones", "ten", "twenty", "thirty", "forty",
     "fifty", "sixty", "seventy", "eighty", "ninety"] as $tens

  | if . == 0 then "zero"
    elif . < 0 then "minus " + (-(.) | say)
    elif . < 20 then $small[.]
    elif . < 100 then
        $tens[./10|floor] as $t
        | (. % 10)
        | if . > 0 then ($t + " " + $small[.]) else $t end
    elif . < 1000 then
        ($small[./100|floor] + " hundred") as $h
        | (. % 100)
        | if . > 0 then $h + " and " + (say) else $h end
    else
        # Handle values larger than 1000 by considering
        # the rightmost three digits separately from the rest:
        ((. % 1000)
         | if . == 0 then ""
           elif . < 100 then "and " + say
           else say
           end ) as $sx
        | zillions(0; $sx)
    end ;

say