1const ZERO: &'static str = "zero";
3
4const SIGNED: &'static str = "minus ";
6
7const SEPARATOR: &'static str = " and ";
9
10const ONES: [&'static str; 10] = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"];
12
13const TEENS: [&'static str; 10] = ["", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
15
16const TENS: [&'static str; 10] = ["", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"];
18
19const HUNDRED: &'static str = "hundred";
21
22const SCALES: [&'static str; 7] = ["", "thousand", "million", "billion", "trillion", "quadrillion", "quintillion"];
24
25pub fn number_to_cardinal(number: i64) -> String {
42 if number == 0 {
43 return ZERO.to_string();
44 }
45
46 let mut words = String::new();
47 let mut num = if number < 0 { -number } else { number } as u64; let mut scale_idx = 0;
51 while num > 0 {
52 if let Some(chunk) = get_chunk_words(num % 1_000, scale_idx) {
53 words.insert_str(0, &chunk);
54 }
55 num /= 1_000;
56 scale_idx += 1;
57 }
58
59 if number < 0 {
60 words.insert_str(0, SIGNED);
61 }
62 words.trim().to_string()
63}
64
65fn get_chunk_words(chunk: u64, scale_idx: usize) -> Option<String> {
76 if chunk == 0 {
77 return None;
78 }
79
80 let mut result = convert_number_to_cardinal(chunk as i64);
81 if scale_idx > 0 {
82 result.push_str(&format!(" {} ", SCALES[scale_idx]));
83 }
84 Some(result)
85}
86
87fn convert_number_to_cardinal(number: i64) -> String {
97 let mut words = String::new();
98
99 if number >= 100 {
101 words.push_str(&format!("{} {}", ONES[(number / 100) as usize], HUNDRED));
102 if number % 100 != 0 {
103 words.push_str(SEPARATOR);
104 }
105 }
106
107 let remainder = number % 100;
108
109 match remainder {
111 11..=19 => words.push_str(TEENS[(remainder - 10) as usize]),
112 1..=9 => words.push_str(ONES[remainder as usize]),
113 10 => words.push_str(TENS[1]),
114 _ => {
115 if remainder >= 20 {
116 words.push_str(TENS[remainder as usize / 10]);
117 if remainder % 10 != 0 {
118 words.push_str(&format!("-{}", ONES[(remainder % 10) as usize]));
119 }
120 }
121 }
122 }
123 words
124}
125
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn it_works_with_ones() {
133 assert_eq!(number_to_cardinal(0), "zero");
134 assert_eq!(number_to_cardinal(1), "one");
135 assert_eq!(number_to_cardinal(2), "two");
136 assert_eq!(number_to_cardinal(3), "three");
137 assert_eq!(number_to_cardinal(4), "four");
138 assert_eq!(number_to_cardinal(5), "five");
139 assert_eq!(number_to_cardinal(6), "six");
140 assert_eq!(number_to_cardinal(7), "seven");
141 assert_eq!(number_to_cardinal(8), "eight");
142 assert_eq!(number_to_cardinal(9), "nine");
143 }
144
145 #[test]
146 fn it_works_with_signed_ones() {
147 assert_eq!(number_to_cardinal(-1), "minus one");
148 assert_eq!(number_to_cardinal(-2), "minus two");
149 assert_eq!(number_to_cardinal(-3), "minus three");
150 assert_eq!(number_to_cardinal(-4), "minus four");
151 assert_eq!(number_to_cardinal(-5), "minus five");
152 assert_eq!(number_to_cardinal(-6), "minus six");
153 assert_eq!(number_to_cardinal(-7), "minus seven");
154 assert_eq!(number_to_cardinal(-8), "minus eight");
155 assert_eq!(number_to_cardinal(-9), "minus nine");
156 assert_eq!(number_to_cardinal(-10), "minus ten");
157 }
158
159 #[test]
160 fn it_works_with_teens() {
161 assert_eq!(number_to_cardinal(11), "eleven");
162 assert_eq!(number_to_cardinal(12), "twelve");
163 assert_eq!(number_to_cardinal(13), "thirteen");
164 assert_eq!(number_to_cardinal(14), "fourteen");
165 assert_eq!(number_to_cardinal(15), "fifteen");
166 assert_eq!(number_to_cardinal(16), "sixteen");
167 assert_eq!(number_to_cardinal(17), "seventeen");
168 assert_eq!(number_to_cardinal(18), "eighteen");
169 assert_eq!(number_to_cardinal(19), "nineteen");
170 }
171
172 #[test]
173 fn it_works_with_tens() {
174 assert_eq!(number_to_cardinal(10), "ten");
175 assert_eq!(number_to_cardinal(20), "twenty");
176 assert_eq!(number_to_cardinal(21), "twenty-one");
177 assert_eq!(number_to_cardinal(30), "thirty");
178 assert_eq!(number_to_cardinal(33), "thirty-three");
179 assert_eq!(number_to_cardinal(40), "forty");
180 assert_eq!(number_to_cardinal(50), "fifty");
181 assert_eq!(number_to_cardinal(60), "sixty");
182 assert_eq!(number_to_cardinal(70), "seventy");
183 assert_eq!(number_to_cardinal(80), "eighty");
184 assert_eq!(number_to_cardinal(90), "ninety");
185 }
186
187 #[test]
188 fn it_works_with_thousands() {
189 assert_eq!(number_to_cardinal(1_000), "one thousand");
190 assert_eq!(number_to_cardinal(1_001), "one thousand one");
191 assert_eq!(number_to_cardinal(1_100), "one thousand one hundred");
192 assert_eq!(number_to_cardinal(10_000), "ten thousand");
193 assert_eq!(number_to_cardinal(11_000), "eleven thousand");
194 assert_eq!(number_to_cardinal(11_011), "eleven thousand eleven");
195 assert_eq!(number_to_cardinal(21_025), "twenty-one thousand twenty-five");
196 assert_eq!(number_to_cardinal(99_999), "ninety-nine thousand nine hundred and ninety-nine");
197 }
198
199 #[test]
200 fn it_works_with_larger_scales() {
201 assert_eq!(number_to_cardinal(1_000_000), "one million");
202 assert_eq!(number_to_cardinal(1_000_001), "one million one");
203 assert_eq!(number_to_cardinal(1_001_000), "one million one thousand");
204 assert_eq!(number_to_cardinal(1_001_001), "one million one thousand one");
205 assert_eq!(number_to_cardinal(1_061_044), "one million sixty-one thousand forty-four");
206
207 assert_eq!(number_to_cardinal(1_000_000_000), "one billion");
208 assert_eq!(number_to_cardinal(1_000_000_001), "one billion one");
209 assert_eq!(number_to_cardinal(1_000_001_000), "one billion one thousand");
210 assert_eq!(number_to_cardinal(1_000_001_001), "one billion one thousand one");
211 assert_eq!(number_to_cardinal(1_000_456_501), "one billion four hundred and fifty-six thousand five hundred and one");
212
213 assert_eq!(number_to_cardinal(1_000_000_000_000), "one trillion");
214 assert_eq!(number_to_cardinal(1_000_000_000_000_000), "one quadrillion");
215 assert_eq!(number_to_cardinal(1_000_000_000_000_000_000), "one quintillion");
216
217 assert_eq!(number_to_cardinal(2_000_000_000_000), "two trillion");
218 assert_eq!(number_to_cardinal(2_000_000_000_000_000), "two quadrillion");
219 assert_eq!(number_to_cardinal(2_000_000_000_000_000_000), "two quintillion");
220 assert_eq!(number_to_cardinal(2_000_892_000_560_056_000), "two quintillion eight hundred and ninety-two trillion five hundred and sixty million fifty-six thousand");
221
222 assert_eq!(number_to_cardinal(1_001_000_000_000), "one trillion one billion");
223 assert_eq!(number_to_cardinal(1_000_001_000_000_000), "one quadrillion one billion");
224 assert_eq!(number_to_cardinal(1_000_000_001_000_000_000), "one quintillion one billion");
225 assert_eq!(number_to_cardinal(1_000_892_000_560_056_000), "one quintillion eight hundred and ninety-two trillion five hundred and sixty million fifty-six thousand");
226
227 assert_eq!(number_to_cardinal(1_001_000_000_001), "one trillion one billion one");
228 assert_eq!(number_to_cardinal(1_000_001_000_000_001), "one quadrillion one billion one");
229 assert_eq!(number_to_cardinal(1_000_000_001_000_000_001), "one quintillion one billion one");
230
231 assert_eq!(number_to_cardinal(1_100_100_100_100_100_101), "one quintillion one hundred quadrillion one hundred trillion one hundred billion one hundred million one hundred thousand one hundred and one");
232 }
233}