1 ! Copyright (c) 2007, 2008, 2018 Aaron Schaefer.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: combinators combinators.short-circuit kernel math
4 math.order math.parser math.text.utils namespaces sequences
10 : small-numbers ( n -- str )
12 "zero" "one" "two" "three" "four" "five" "six"
13 "seven" "eight" "nine" "ten" "eleven" "twelve"
14 "thirteen" "fourteen" "fifteen" "sixteen" "seventeen"
20 f f "twenty" "thirty" "forty" "fifty" "sixty"
21 "seventy" "eighty" "ninety"
24 : scale-numbers ( n -- str ) ! up to 10^99
26 f "thousand" "million" "billion" "trillion" "quadrillion"
27 "quintillion" "sextillion" "septillion" "octillion"
28 "nonillion" "decillion" "undecillion" "duodecillion"
29 "tredecillion" "quattuordecillion" "quindecillion"
30 "sexdecillion" "septendecillion" "octodecillion" "novemdecillion"
31 "vigintillion" "unvigintillion" "duovigintillion" "trevigintillion"
32 "quattuorvigintillion" "quinvigintillion" "sexvigintillion"
33 "septvigintillion" "octovigintillion" "novemvigintillion"
34 "trigintillion" "untrigintillion" "duotrigintillion"
38 : set-conjunction ( seq -- )
39 first { [ 100 < ] [ 0 > ] } 1&& and-needed? set ;
41 : negative-text ( n -- str )
42 0 < "negative " "" ? ;
44 : hundreds-place ( n -- str )
48 [ small-numbers " hundred" append ] dip
49 0 = [ " and " append ] unless
52 : tens-place ( n -- str )
55 [ small-numbers "-" glue ] unless-zero
57 [ "" ] [ small-numbers ] if-zero
60 : 3digits>text ( n -- str )
61 [ hundreds-place ] [ tens-place ] bi append ;
63 : text-with-scale ( index seq -- str )
64 [ nth 3digits>text ] [ drop scale-numbers ] 2bi
65 [ " " glue ] unless-empty ;
67 : append-with-conjunction ( str1 str2 -- newstr )
69 and-needed? get " and " ", " ? glue
73 : (recombine) ( str index seq -- newstr )
77 text-with-scale append-with-conjunction
80 : recombine ( seq -- str )
84 [ set-conjunction "" ] [ length ] [ ] tri
85 [ (recombine) ] curry each-integer
88 : (number>text) ( n -- str )
89 [ negative-text ] [ abs 3 digit-groups recombine ] bi append ;
93 GENERIC: number>text ( n -- str )
95 M: integer number>text
96 [ "zero" ] [ [ (number>text) ] with-scope ] if-zero ;
99 >fraction [ number>text ] bi@ " divided by " glue ;
102 number>string "." split1 [
104 [ string>number number>text ]
105 [ [ "negative " prepend ] when ] bi*
107 [ CHAR: 0 - small-numbers ] { } map-as join-words
108 ] bi* " point " glue ;
110 M: complex number>text
111 >rect [ number>text ] [
112 [ 0 < " minus " " plus " ? ]
113 [ abs number>text " i" append ] bi
116 : ordinal-suffix ( n -- suffix )
117 abs dup 100 mod 11 13 between? [ drop "th" ] [
126 : number-ap-style ( n -- str )
127 dup { [ integer? ] [ 0 9 between? ] } 1&&
128 [ number>text ] [ number>string ] if ;
130 : ordinal-ap-style ( n -- str )
132 f "first" "second" "third" "fourth" "fifth" "sixth"
133 "seventh" "eighth" "ninth"
135 [ number>string ] [ ordinal-suffix ] bi append