@q @program english-numbers.muf 1 9999 d i $note A simple routine to render a numeric value as english words. $libdef english-number ( english-numbers.muf Dec 11 2012 - v1.000 caveats: doesn't handle floats doesn't check for overflow doesn't do fancy shortening, like someteen-hundred ) $lib-version 1.000 $version 1.000 $author $ifdef DEBUGGING ( trim some debug fluff ) $def D_SAVE prog "D" flag? D_STATE ! $def D_UNSET prog "!D" set $def D_RESTORE D_STATE @ if prog "D" set then lvar D_STATE $else $def D_SAVE $def D_UNSET $def D_RESTORE $endif : zero_ ( -- s ) "zero" ; ( the numbers, up until things become predictable ) : low_numbers_ ( @ -- s ) D_UNSET { "" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen" "seventeen" "eighteen" "nineteen" } array_make swap array_getitem D_RESTORE ; ( gangs of ten ) : decades_ ( @ -- s ) D_UNSET { "" "" "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety" } array_make swap array_getitem D_RESTORE ; ( just to keep things stylistically similar ) : hundred_ ( -- s ) "hundred" ; ( words for big numbers, according to wikipedia ) : big_numbers_ ( @ -- s ) D_UNSET { "" "thousand" "million" "billion" "trillion" "quadrillion" "quintillion" "sextillion" "septillion" "octillion" "nonillion" "decillion" "undecillion" "duodecillion" "tredecillion" "quattuordecillion" "quindecillion" "sexdecillion" "septendecillion" "octodecillion" "novemdecillion" "vigintillion" "silmarillion" } array_make swap array_getitem D_RESTORE ; ( outputs the words for a number under one-thousand ) : english_sub_thousand_ ( i -- s ) "" var! OUT dup 1000 % 100 / var! HUNDREDS dup 100 % 10 / var! TENS dup 10 % var! ONES ( show hundreds if they exist ) HUNDREDS @ if OUT @ HUNDREDS @ low_numbers_ strcat " " strcat hundred_ strcat ( if there's more number to show, need a word break ) TENS @ ONES @ or if " " strcat then OUT ! then ( show remaining teens or under ) TENS @ 2 < if OUT @ over 20 % low_numbers_ strcat OUT ! else ( otherwise show remaining tens-ones pattern ) OUT @ TENS @ decades_ strcat ONES @ if "-" strcat ONES @ low_numbers_ strcat then OUT ! then pop OUT @ ; : english-number ( i -- s ) "i" checkargs D_SAVE "" var! OUT dup sign 0 < var! ISNEG abs dup 0 = if pop zero_ exit then 0 var! BIGNESS begin ( i ) dup 1000 % english_sub_thousand_ ( i s ) BIGNESS @ dup 1 >= if ( i s i ) big_numbers_ " " swap strcat ( i s s ) strcat ( i s ) else pop then ( i s ) OUT @ ( i s s ) dup strlen if ( i s s ) " " swap strcat then ( i s ) strcat OUT ! ( i ) BIGNESS ++ ( i ) 1000 / dup 0 = ( i i ) until pop OUT @ ISNEG @ if "negative " swap strcat then ; public english-number : mpi atoi english-number ; . c q @reg english-numbers.muf=lib/squeep/english-numbers @set $lib/squeep/english-numbers=_docs:@list english-numbers.muf=1-10 @set $lib/squeep/english-numbers=L @set $lib/squeep/english-numbers=V @set #0=_msgmacs/english-number:{muf:$lib/squeep/english-numbers,{:1}}