Spelling of ordinal numbers: Difference between revisions
Added FreeBASIC |
|||
(49 intermediate revisions by 17 users not shown) | |||
Line 17: | Line 17: | ||
Furthermore, the |
Furthermore, the short scale numbering system (i.e. 2,000,000,000 is two billion) will be used here. [[wp:Long and short scales]] |
||
'''2,000,000,000''' is two billion, ''not'' two milliard. |
'''2,000,000,000''' is two billion, ''not'' two milliard. |
||
Line 39: | Line 39: | ||
* [[N'th]] |
* [[N'th]] |
||
<br><br> |
<br><br> |
||
=={{header|ALGOL 68}}== |
|||
Assumes LONG INT is at least 64 bits, as in e.g., Algol 68G. |
|||
<syntaxhighlight lang="algol68"> |
|||
BEGIN # construct number names from a number # |
|||
[]STRING units |
|||
= ( "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" ); |
|||
[]STRING unit prefix |
|||
= ( "ten", "twen", "thir", "four", "fif", "six", "seven", "eigh", "nine" ); |
|||
[]STRING singleth |
|||
= ( "first", "second", "third", "fourth", "fifth" |
|||
, "sixth", "seventh", "eighth", "nineth" |
|||
); |
|||
[]STRING power suffix |
|||
= ( "thousand", "million", "billion", "trillion", "quadrillion", "quintillion" ); |
|||
# returns n converted to a number name, n must be 1-99 # |
|||
# if final is TRUE, the name will end in st, nd, rd, ... # |
|||
PROC two digits = ( INT n, BOOL final )STRING: |
|||
IF n < 10 THEN IF final THEN singleth[ n ] ELSE units[ n ] FI |
|||
ELIF n = 10 THEN IF final THEN "tenth" ELSE "ten" FI |
|||
ELIF n = 11 THEN IF final THEN "eleventh" ELSE "eleven" FI |
|||
ELIF n = 12 THEN IF final THEN "twelfth" ELSE "twelve" FI |
|||
ELIF n < 20 THEN unit prefix[ n - 10 ] |
|||
+ IF final THEN "teenth" ELSE "teen" FI |
|||
ELIF n MOD 10 = 0 THEN unit prefix[ n OVER 10 ] |
|||
+ IF final THEN "tieth" ELSE "ty" FI |
|||
ELSE unit prefix[ n OVER 10 ] |
|||
+ "ty " |
|||
+ IF final THEN singleth[ n MOD 10 ] ELSE units[ n MOD 10 ] FI |
|||
FI # two digits # ; |
|||
# returns n converted to a number name, n must be 1-999 # |
|||
# if final is TRUE, the name will end in st, nd, rd, ... # |
|||
PROC three digits = ( INT n, BOOL final )STRING: |
|||
IF n < 100 |
|||
THEN two digits( n, final ) |
|||
ELIF STRING hundreds = units[ n OVER 100 ] + " hundred"; |
|||
INT ending = n MOD 100; |
|||
ending = 0 |
|||
THEN IF final THEN hundreds + "th" ELSE hundreds FI |
|||
ELSE hundreds + " and " + two digits( ending, final ) |
|||
FI # three digits # ; |
|||
# returns the "name" of n # |
|||
OP NAME = ( LONG INT n )STRING: |
|||
IF n < 0 THEN "minus " + NAME - n |
|||
ELIF n = 0 THEN "zeroth" |
|||
ELSE |
|||
# have a positive number to name # |
|||
LONG INT v := n; |
|||
STRING result := ""; |
|||
INT power pos := 0; |
|||
WHILE v /= 0 DO |
|||
BOOL final component = power pos = 0; |
|||
INT v999 = SHORTEN ( v MOD 1000 ); |
|||
IF v999 /= 0 THEN |
|||
STRING component := three digits( v999, final component ); |
|||
IF power pos > 0 THEN |
|||
component +:= " " + power suffix[ power pos ]; |
|||
IF final component THEN component +:= "th" FI |
|||
FI; |
|||
IF power pos = 0 AND v > 1000 AND v999 < 100 THEN |
|||
"and " +=: component |
|||
FI; |
|||
IF result /= "" THEN component +:= " " FI; |
|||
component +=: result |
|||
FI; |
|||
power pos +:= 1; |
|||
v OVERAB 1000 |
|||
OD; |
|||
IF n MOD 1000 = 0 THEN result + "th" ELSE result FI |
|||
FI # NAME # ; |
|||
# additional operator to handle shorter integers # |
|||
OP NAME = ( INT n )STRING: NAME LENG n; |
|||
# additional operators to handle integers expressed in floating point # |
|||
OP NAME = ( LONG REAL n )STRING: NAME ENTIER n; |
|||
OP NAME = ( REAL n )STRING: NAME ENTIER n; |
|||
# task test cases # |
|||
[]LONG INT t = ( 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23 456, 8 007 006 005 004 003 ); |
|||
FOR n FROM LWB t TO UPB t DO |
|||
print( ( whole( t[ n ], -16 ), ": ", NAME t[ n ], newline ) ) |
|||
OD |
|||
END |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1: first |
|||
2: second |
|||
3: third |
|||
4: fourth |
|||
5: fifth |
|||
11: eleventh |
|||
65: sixty fifth |
|||
100: one hundredth |
|||
101: one hundred and first |
|||
272: two hundred and seventy second |
|||
23456: twenty three thousand four hundred and fifty sixth |
|||
8007006005004003: eight quadrillion seven trillion six billion five million four thousand and third |
|||
</pre> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
Based on [[Number_names#AutoHotkey|Number_names]] |
Based on [[Number_names#AutoHotkey|Number_names]] |
||
< |
<syntaxhighlight lang="autohotkey">OrdinalNumber(n){ |
||
OrdinalNumber := {"one":"first", "two":"second", "three":"third", "five":"fifth", "eight":"eighth", "nine":"ninth", "twelve": "twelfth"} |
OrdinalNumber := {"one":"first", "two":"second", "three":"third", "five":"fifth", "eight":"eighth", "nine":"ninth", "twelve": "twelfth"} |
||
RegExMatch(n, "\w+$", m) |
RegExMatch(n, "\w+$", m) |
||
Line 71: | Line 168: | ||
PrettyNumber(n) { ; inserts thousands separators into a number string |
PrettyNumber(n) { ; inserts thousands separators into a number string |
||
Return RegExReplace( RegExReplace(n,"^0+(\d)","$1"), "\G\d+?(?=(\d{3})+(?:\D|$))", "$0,") |
Return RegExReplace( RegExReplace(n,"^0+(\d)","$1"), "\G\d+?(?=(\d{3})+(?:\D|$))", "$0,") |
||
}</ |
}</syntaxhighlight> |
||
Example:< |
Example:<syntaxhighlight lang="autohotkey">for i, n in StrSplit("1 2 3 4 5 11 65 100 101 272 23456 8007006005004003", " ") |
||
res .= PrettyNumber(n) "`t" Spell(n) "`t" OrdinalNumber(Spell(n)) "`n" |
res .= PrettyNumber(n) "`t" Spell(n) "`t" OrdinalNumber(Spell(n)) "`n" |
||
MsgBox % res |
MsgBox % res |
||
</syntaxhighlight> |
|||
</lang> |
|||
Outputs:<pre>1 first |
Outputs:<pre>1 first |
||
2 second |
2 second |
||
Line 88: | Line 185: | ||
23,456 twenty-three thousand , four hundred and fifty-sixth |
23,456 twenty-three thousand , four hundred and fifty-sixth |
||
8,007,006,005,004,003 eight quadrillion , seven trillion , six billion , five million , four thousand , third</pre> |
8,007,006,005,004,003 eight quadrillion , seven trillion , six billion , five million , four thousand , third</pre> |
||
=={{header|C}}== |
|||
{{libheader|GLib}} |
|||
<syntaxhighlight lang="c">#include <stdbool.h> |
|||
#include <stdio.h> |
|||
#include <stdint.h> |
|||
#include <glib.h> |
|||
typedef uint64_t integer; |
|||
typedef struct number_names_tag { |
|||
const char* cardinal; |
|||
const char* ordinal; |
|||
} number_names; |
|||
const number_names small[] = { |
|||
{ "zero", "zeroth" }, { "one", "first" }, { "two", "second" }, |
|||
{ "three", "third" }, { "four", "fourth" }, { "five", "fifth" }, |
|||
{ "six", "sixth" }, { "seven", "seventh" }, { "eight", "eighth" }, |
|||
{ "nine", "ninth" }, { "ten", "tenth" }, { "eleven", "eleventh" }, |
|||
{ "twelve", "twelfth" }, { "thirteen", "thirteenth" }, |
|||
{ "fourteen", "fourteenth" }, { "fifteen", "fifteenth" }, |
|||
{ "sixteen", "sixteenth" }, { "seventeen", "seventeenth" }, |
|||
{ "eighteen", "eighteenth" }, { "nineteen", "nineteenth" } |
|||
}; |
|||
const number_names tens[] = { |
|||
{ "twenty", "twentieth" }, { "thirty", "thirtieth" }, |
|||
{ "forty", "fortieth" }, { "fifty", "fiftieth" }, |
|||
{ "sixty", "sixtieth" }, { "seventy", "seventieth" }, |
|||
{ "eighty", "eightieth" }, { "ninety", "ninetieth" } |
|||
}; |
|||
typedef struct named_number_tag { |
|||
const char* cardinal; |
|||
const char* ordinal; |
|||
integer number; |
|||
} named_number; |
|||
const named_number named_numbers[] = { |
|||
{ "hundred", "hundredth", 100 }, |
|||
{ "thousand", "thousandth", 1000 }, |
|||
{ "million", "millionth", 1000000 }, |
|||
{ "billion", "billionth", 1000000000 }, |
|||
{ "trillion", "trillionth", 1000000000000 }, |
|||
{ "quadrillion", "quadrillionth", 1000000000000000ULL }, |
|||
{ "quintillion", "quintillionth", 1000000000000000000ULL } |
|||
}; |
|||
const char* get_small_name(const number_names* n, bool ordinal) { |
|||
return ordinal ? n->ordinal : n->cardinal; |
|||
} |
|||
const char* get_big_name(const named_number* n, bool ordinal) { |
|||
return ordinal ? n->ordinal : n->cardinal; |
|||
} |
|||
const named_number* get_named_number(integer n) { |
|||
const size_t names_len = sizeof(named_numbers)/sizeof(named_numbers[0]); |
|||
for (size_t i = 0; i + 1 < names_len; ++i) { |
|||
if (n < named_numbers[i + 1].number) |
|||
return &named_numbers[i]; |
|||
} |
|||
return &named_numbers[names_len - 1]; |
|||
} |
|||
void append_number_name(GString* gstr, integer n, bool ordinal) { |
|||
if (n < 20) |
|||
g_string_append(gstr, get_small_name(&small[n], ordinal)); |
|||
else if (n < 100) { |
|||
if (n % 10 == 0) { |
|||
g_string_append(gstr, get_small_name(&tens[n/10 - 2], ordinal)); |
|||
} else { |
|||
g_string_append(gstr, get_small_name(&tens[n/10 - 2], false)); |
|||
g_string_append_c(gstr, '-'); |
|||
g_string_append(gstr, get_small_name(&small[n % 10], ordinal)); |
|||
} |
|||
} else { |
|||
const named_number* num = get_named_number(n); |
|||
integer p = num->number; |
|||
append_number_name(gstr, n/p, false); |
|||
g_string_append_c(gstr, ' '); |
|||
if (n % p == 0) { |
|||
g_string_append(gstr, get_big_name(num, ordinal)); |
|||
} else { |
|||
g_string_append(gstr, get_big_name(num, false)); |
|||
g_string_append_c(gstr, ' '); |
|||
append_number_name(gstr, n % p, ordinal); |
|||
} |
|||
} |
|||
} |
|||
GString* number_name(integer n, bool ordinal) { |
|||
GString* result = g_string_sized_new(8); |
|||
append_number_name(result, n, ordinal); |
|||
return result; |
|||
} |
|||
void test_ordinal(integer n) { |
|||
GString* name = number_name(n, true); |
|||
printf("%llu: %s\n", n, name->str); |
|||
g_string_free(name, TRUE); |
|||
} |
|||
int main() { |
|||
test_ordinal(1); |
|||
test_ordinal(2); |
|||
test_ordinal(3); |
|||
test_ordinal(4); |
|||
test_ordinal(5); |
|||
test_ordinal(11); |
|||
test_ordinal(15); |
|||
test_ordinal(21); |
|||
test_ordinal(42); |
|||
test_ordinal(65); |
|||
test_ordinal(98); |
|||
test_ordinal(100); |
|||
test_ordinal(101); |
|||
test_ordinal(272); |
|||
test_ordinal(300); |
|||
test_ordinal(750); |
|||
test_ordinal(23456); |
|||
test_ordinal(7891233); |
|||
test_ordinal(8007006005004003LL); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1: first |
|||
2: second |
|||
3: third |
|||
4: fourth |
|||
5: fifth |
|||
11: eleventh |
|||
15: fifteenth |
|||
21: twenty-first |
|||
42: forty-second |
|||
65: sixty-fifth |
|||
98: ninety-eighth |
|||
100: one hundredth |
|||
101: one hundred first |
|||
272: two hundred seventy-second |
|||
300: three hundredth |
|||
750: seven hundred fiftieth |
|||
23456: twenty-three thousand four hundred fifty-sixth |
|||
7891233: seven million eight hundred ninety-one thousand two hundred thirty-third |
|||
8007006005004003: eight quadrillion seven trillion six billion five million four thousand third |
|||
</pre> |
|||
=={{header|C#}}== |
|||
{{trans|Java}} |
|||
<syntaxhighlight lang="C#"> |
|||
using System; |
|||
using System.Collections.Generic; |
|||
class SpellingOfOrdinalNumbers |
|||
{ |
|||
private static readonly Dictionary<string, string> ordinalMap = new Dictionary<string, string> |
|||
{ |
|||
{"one", "first"}, |
|||
{"two", "second"}, |
|||
{"three", "third"}, |
|||
{"five", "fifth"}, |
|||
{"eight", "eighth"}, |
|||
{"nine", "ninth"}, |
|||
{"twelve", "twelfth"} |
|||
}; |
|||
static void Main(string[] args) |
|||
{ |
|||
long[] tests = new long[] { 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003L }; |
|||
foreach (long test in tests) |
|||
{ |
|||
Console.WriteLine($"{test} = {ToOrdinal(test)}"); |
|||
} |
|||
} |
|||
private static string ToOrdinal(long n) |
|||
{ |
|||
string spelling = NumToString(n); |
|||
string[] split = spelling.Split(' '); |
|||
string last = split[split.Length - 1]; |
|||
string replace; |
|||
if (last.Contains("-")) |
|||
{ |
|||
string[] lastSplit = last.Split('-'); |
|||
string lastWithDash = lastSplit[1]; |
|||
string lastReplace; |
|||
if (ordinalMap.ContainsKey(lastWithDash)) |
|||
{ |
|||
lastReplace = ordinalMap[lastWithDash]; |
|||
} |
|||
else if (lastWithDash.EndsWith("y")) |
|||
{ |
|||
lastReplace = lastWithDash.Substring(0, lastWithDash.Length - 1) + "ieth"; |
|||
} |
|||
else |
|||
{ |
|||
lastReplace = lastWithDash + "th"; |
|||
} |
|||
replace = lastSplit[0] + "-" + lastReplace; |
|||
} |
|||
else |
|||
{ |
|||
if (ordinalMap.ContainsKey(last)) |
|||
{ |
|||
replace = ordinalMap[last]; |
|||
} |
|||
else if (last.EndsWith("y")) |
|||
{ |
|||
replace = last.Substring(0, last.Length - 1) + "ieth"; |
|||
} |
|||
else |
|||
{ |
|||
replace = last + "th"; |
|||
} |
|||
} |
|||
split[split.Length - 1] = replace; |
|||
return string.Join(" ", split); |
|||
} |
|||
private static readonly string[] nums = new string[] |
|||
{ |
|||
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", |
|||
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" |
|||
}; |
|||
private static readonly string[] tens = new string[] { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; |
|||
private static string NumToString(long n) |
|||
{ |
|||
return NumToStringHelper(n); |
|||
} |
|||
private static string NumToStringHelper(long n) |
|||
{ |
|||
if (n < 0) |
|||
{ |
|||
return "negative " + NumToStringHelper(-n); |
|||
} |
|||
if (n <= 19) |
|||
{ |
|||
return nums[n]; |
|||
} |
|||
if (n <= 99) |
|||
{ |
|||
return tens[n / 10] + (n % 10 > 0 ? "-" + NumToStringHelper(n % 10) : ""); |
|||
} |
|||
string label = null; |
|||
long factor = 0; |
|||
if (n <= 999) |
|||
{ |
|||
label = "hundred"; |
|||
factor = 100; |
|||
} |
|||
else if (n <= 999999) |
|||
{ |
|||
label = "thousand"; |
|||
factor = 1000; |
|||
} |
|||
else if (n <= 999999999) |
|||
{ |
|||
label = "million"; |
|||
factor = 1000000; |
|||
} |
|||
else if (n <= 999999999999L) |
|||
{ |
|||
label = "billion"; |
|||
factor = 1000000000; |
|||
} |
|||
else if (n <= 999999999999999L) |
|||
{ |
|||
label = "trillion"; |
|||
factor = 1000000000000L; |
|||
} |
|||
else if (n <= 999999999999999999L) |
|||
{ |
|||
label = "quadrillion"; |
|||
factor = 1000000000000000L; |
|||
} |
|||
else |
|||
{ |
|||
label = "quintillion"; |
|||
factor = 1000000000000000000L; |
|||
} |
|||
return NumToStringHelper(n / factor) + " " + label + (n % factor > 0 ? " " + NumToStringHelper(n % factor) : ""); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 = first |
|||
2 = second |
|||
3 = third |
|||
4 = fourth |
|||
5 = fifth |
|||
11 = eleventh |
|||
65 = sixty-fifth |
|||
100 = one hundredth |
|||
101 = one hundred first |
|||
272 = two hundred seventy-second |
|||
23456 = twenty-three thousand four hundred fifty-sixth |
|||
8007006005004003 = eight quadrillion seven trillion six billion five million four thousand third |
|||
</pre> |
|||
=={{header|C++}}== |
|||
<syntaxhighlight lang="cpp">#include <iostream> |
|||
#include <string> |
|||
#include <cstdint> |
|||
typedef std::uint64_t integer; |
|||
struct number_names { |
|||
const char* cardinal; |
|||
const char* ordinal; |
|||
}; |
|||
const number_names small[] = { |
|||
{ "zero", "zeroth" }, { "one", "first" }, { "two", "second" }, |
|||
{ "three", "third" }, { "four", "fourth" }, { "five", "fifth" }, |
|||
{ "six", "sixth" }, { "seven", "seventh" }, { "eight", "eighth" }, |
|||
{ "nine", "ninth" }, { "ten", "tenth" }, { "eleven", "eleventh" }, |
|||
{ "twelve", "twelfth" }, { "thirteen", "thirteenth" }, |
|||
{ "fourteen", "fourteenth" }, { "fifteen", "fifteenth" }, |
|||
{ "sixteen", "sixteenth" }, { "seventeen", "seventeenth" }, |
|||
{ "eighteen", "eighteenth" }, { "nineteen", "nineteenth" } |
|||
}; |
|||
const number_names tens[] = { |
|||
{ "twenty", "twentieth" }, { "thirty", "thirtieth" }, |
|||
{ "forty", "fortieth" }, { "fifty", "fiftieth" }, |
|||
{ "sixty", "sixtieth" }, { "seventy", "seventieth" }, |
|||
{ "eighty", "eightieth" }, { "ninety", "ninetieth" } |
|||
}; |
|||
struct named_number { |
|||
const char* cardinal; |
|||
const char* ordinal; |
|||
integer number; |
|||
}; |
|||
const named_number named_numbers[] = { |
|||
{ "hundred", "hundredth", 100 }, |
|||
{ "thousand", "thousandth", 1000 }, |
|||
{ "million", "millionth", 1000000 }, |
|||
{ "billion", "billionth", 1000000000 }, |
|||
{ "trillion", "trillionth", 1000000000000 }, |
|||
{ "quadrillion", "quadrillionth", 1000000000000000ULL }, |
|||
{ "quintillion", "quintillionth", 1000000000000000000ULL } |
|||
}; |
|||
const char* get_name(const number_names& n, bool ordinal) { |
|||
return ordinal ? n.ordinal : n.cardinal; |
|||
} |
|||
const char* get_name(const named_number& n, bool ordinal) { |
|||
return ordinal ? n.ordinal : n.cardinal; |
|||
} |
|||
const named_number& get_named_number(integer n) { |
|||
constexpr size_t names_len = std::size(named_numbers); |
|||
for (size_t i = 0; i + 1 < names_len; ++i) { |
|||
if (n < named_numbers[i + 1].number) |
|||
return named_numbers[i]; |
|||
} |
|||
return named_numbers[names_len - 1]; |
|||
} |
|||
std::string number_name(integer n, bool ordinal) { |
|||
std::string result; |
|||
if (n < 20) |
|||
result = get_name(small[n], ordinal); |
|||
else if (n < 100) { |
|||
if (n % 10 == 0) { |
|||
result = get_name(tens[n/10 - 2], ordinal); |
|||
} else { |
|||
result = get_name(tens[n/10 - 2], false); |
|||
result += "-"; |
|||
result += get_name(small[n % 10], ordinal); |
|||
} |
|||
} else { |
|||
const named_number& num = get_named_number(n); |
|||
integer p = num.number; |
|||
result = number_name(n/p, false); |
|||
result += " "; |
|||
if (n % p == 0) { |
|||
result += get_name(num, ordinal); |
|||
} else { |
|||
result += get_name(num, false); |
|||
result += " "; |
|||
result += number_name(n % p, ordinal); |
|||
} |
|||
} |
|||
return result; |
|||
} |
|||
void test_ordinal(integer n) { |
|||
std::cout << n << ": " << number_name(n, true) << '\n'; |
|||
} |
|||
int main() { |
|||
test_ordinal(1); |
|||
test_ordinal(2); |
|||
test_ordinal(3); |
|||
test_ordinal(4); |
|||
test_ordinal(5); |
|||
test_ordinal(11); |
|||
test_ordinal(15); |
|||
test_ordinal(21); |
|||
test_ordinal(42); |
|||
test_ordinal(65); |
|||
test_ordinal(98); |
|||
test_ordinal(100); |
|||
test_ordinal(101); |
|||
test_ordinal(272); |
|||
test_ordinal(300); |
|||
test_ordinal(750); |
|||
test_ordinal(23456); |
|||
test_ordinal(7891233); |
|||
test_ordinal(8007006005004003LL); |
|||
return 0; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1: first |
|||
2: second |
|||
3: third |
|||
4: fourth |
|||
5: fifth |
|||
11: eleventh |
|||
15: fifteenth |
|||
21: twenty-first |
|||
42: forty-second |
|||
65: sixty-fifth |
|||
98: ninety-eighth |
|||
100: one hundredth |
|||
101: one hundred first |
|||
272: two hundred seventy-second |
|||
300: three hundredth |
|||
750: seven hundred fiftieth |
|||
23456: twenty-three thousand four hundred fifty-sixth |
|||
7891233: seven million eight hundred ninety-one thousand two hundred thirty-third |
|||
8007006005004003: eight quadrillion seven trillion six billion five million four thousand third |
|||
</pre> |
|||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
< |
<syntaxhighlight lang="clojure">(def test-cases [1 2 3 4 5 11 65 100 101 272 23456 8007006005004003]) |
||
(pprint |
(pprint |
||
(sort (zipmap test-cases (map #(clojure.pprint/cl-format nil "~:R" %) test-cases)))) |
(sort (zipmap test-cases (map #(clojure.pprint/cl-format nil "~:R" %) test-cases)))) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 110: | Line 654: | ||
"eight quadrillion, seven trillion, six billion, five million, four thousand, third"]) |
"eight quadrillion, seven trillion, six billion, five million, four thousand, third"]) |
||
</pre> |
</pre> |
||
=={{header|Common Lisp}}== |
|||
Common Lisp's format is able to do this directly. Here's a short function wrapping it and a demonstration. |
|||
<syntaxhighlight lang="lisp">(defun ordinal-number (n) |
|||
(format nil "~:R" n)) |
|||
#| |
|||
CL-USER> (loop for i in '(1 2 3 4 5 11 65 100 101 272 23456 8007006005004003) |
|||
do (format t "~a: ~a~%" i (ordinal-number i))) |
|||
1: first |
|||
2: second |
|||
3: third |
|||
4: fourth |
|||
5: fifth |
|||
11: eleventh |
|||
65: sixty-fifth |
|||
100: one hundredth |
|||
101: one hundred first |
|||
272: two hundred seventy-second |
|||
23456: twenty-three thousand four hundred fifty-sixth |
|||
8007006005004003: eight quadrillion seven trillion six billion five million four thousand third |
|||
NIL |
|||
|# |
|||
</syntaxhighlight> |
|||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
Factor's <code>math.text.english</code> vocabulary provides the <code>number>text</code> word for converting numbers to written English. It also provides the <code>ordinal-suffix</code> word for getting the suffix for a given number, such as <tt>th</tt> for <tt>12</tt>. The bulk of this code deals with converting the output of <code>number>text</code> to ordinal format. |
Factor's <code>math.text.english</code> vocabulary provides the <code>number>text</code> word for converting numbers to written English. It also provides the <code>ordinal-suffix</code> word for getting the suffix for a given number, such as <tt>th</tt> for <tt>12</tt>. The bulk of this code deals with converting the output of <code>number>text</code> to ordinal format. |
||
< |
<syntaxhighlight lang="factor">USING: assocs formatting grouping kernel literals locals math |
||
math.parser math.text.english qw regexp sequences |
math.parser math.text.english qw regexp sequences |
||
splitting.extras ; |
splitting.extras ; |
||
Line 168: | Line 736: | ||
"C{ 123 0 }" C{ 123 0 } print-ordinal-pair ; |
"C{ 123 0 }" C{ 123 0 } print-ordinal-pair ; |
||
MAIN: ordinal-text-demo</ |
MAIN: ordinal-text-demo</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 193: | Line 761: | ||
C{ 123 0 } => one hundred twenty-third |
C{ 123 0 } => one hundred twenty-third |
||
</pre> |
</pre> |
||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="vbnet">Dim Shared small(19) As String*9 => { _ |
|||
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", _ |
|||
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", _ |
|||
"sixteen", "seventeen", "eighteen", "nineteen" } |
|||
Dim Shared tens(9) As String*7 => { "", "", _ |
|||
"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" } |
|||
Dim Shared illions(6) As String*12 => {"", _ |
|||
" thousand", " million", " billion"," trillion", " quadrillion", " quintillion" } |
|||
Dim Shared irregularOrdinals(7, 1) As String*7 = { _ |
|||
{"one", "first"}, {"two", "second"}, {"three", "third"}, {"five", "fifth"}, _ |
|||
{"eight", "eighth"}, {"nine", "ninth"}, {"twelve", "twelfth"} } |
|||
Function spell(n As Integer) As String |
|||
Dim As String sx, ix, t = "" |
|||
Dim As Integer s, i, p |
|||
If n < 0 Then |
|||
t = "negative " |
|||
n = -n |
|||
End If |
|||
If n < 20 Then |
|||
t &= small(n) |
|||
Elseif n < 100 Then |
|||
t &= tens(n \ 10) |
|||
s = n Mod 10 |
|||
If s > 0 Then t &= "-" & small(s) |
|||
Elseif n < 1000 Then |
|||
t &= small(n \ 100) & " hundred" |
|||
s = n Mod 100 |
|||
If s > 0 Then t &= " " & spell(s) |
|||
Else |
|||
sx = "" |
|||
i = 0 |
|||
While n > 0 |
|||
p = n Mod 1000 |
|||
n \= 1000 |
|||
If p > 0 Then |
|||
ix = spell(p) & illions(i) |
|||
If sx <> "" Then ix &= " " & sx |
|||
sx = ix |
|||
End If |
|||
i += 1 |
|||
Wend |
|||
t &= sx |
|||
End If |
|||
Return t |
|||
End Function |
|||
Function sayOrdinal(n As Integer) As String |
|||
Dim As String s = spell(n) |
|||
Dim As String lastWord = "" |
|||
Dim As Integer j, i = Len(s) |
|||
While i > 0 And Mid(s, i, 1) <> " " And Mid(s, i, 1) <> "-" |
|||
lastWord = Mid(s, i, 1) + lastWord |
|||
i -= 1 |
|||
Wend |
|||
For j = 0 To Ubound(irregularOrdinals, 1) |
|||
If irregularOrdinals(j, 0) = lastWord Then |
|||
Return Left(s, i) + irregularOrdinals(j, 1) |
|||
End If |
|||
Next j |
|||
If Right(s, 1) = "y" Then |
|||
Return Left(s, Len(s) - 1) + "ieth" |
|||
Else |
|||
Return s + "th" |
|||
End If |
|||
End Function |
|||
Dim As Integer t(0 To ...) = { 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, _ |
|||
23456, 8007006005004003, 123, 00123.0, 1.23E2 } |
|||
For n As Integer = 0 To Ubound(t) |
|||
Print sayOrdinal(t(n)) |
|||
Next n |
|||
Sleep</syntaxhighlight> |
|||
{{out}} |
|||
<pre>first |
|||
second |
|||
third |
|||
fourth |
|||
fifth |
|||
eleventh |
|||
sixty-fifth |
|||
one hundredth |
|||
one hundred first |
|||
two hundred seventy-second |
|||
twenty-three thousand four hundred fifty-sixth |
|||
eight quadrillion seven trillion six billion five million four thousand third |
|||
one hundred twenty-third |
|||
one hundred twenty-third |
|||
one hundred twenty-third</pre> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
As with the Kotlin solution, this uses the output of <code>say</code> from the |
As with the Kotlin solution, this uses the output of <code>say</code> from the |
||
[[Number_names#Go|Number_names]] task. |
[[Number_names#Go|Number_names]] task. |
||
< |
<syntaxhighlight lang="go">import ( |
||
"fmt" |
"fmt" |
||
"strings" |
"strings" |
||
Line 287: | Line 949: | ||
} |
} |
||
return t |
return t |
||
}</ |
}</syntaxhighlight> |
||
{{output}} |
{{output}} |
||
<pre>first |
<pre>first |
||
Line 301: | Line 963: | ||
twenty-three thousand four hundred fifty-sixth |
twenty-three thousand four hundred fifty-sixth |
||
eight quadrillion seven trillion six billion five million four thousand third</pre> |
eight quadrillion seven trillion six billion five million four thousand third</pre> |
||
=={{header|Haskell}}== |
|||
Uses solution of [[Number_names#Haskell]] |
|||
<syntaxhighlight lang="haskell">spellOrdinal :: Integer -> String |
|||
spellOrdinal n |
|||
| n <= 0 = "not ordinal" |
|||
| n < 20 = small n |
|||
| n < 100 = case divMod n 10 of |
|||
(k, 0) -> spellInteger (10*k) ++ "th" |
|||
(k, m) -> spellInteger (10*k) ++ "-" ++ spellOrdinal m |
|||
| n < 1000 = case divMod n 100 of |
|||
(k, 0) -> spellInteger (100*k) ++ "th" |
|||
(k, m) -> spellInteger (100*k) ++ " and " ++ spellOrdinal m |
|||
| otherwise = case divMod n 1000 of |
|||
(k, 0) -> spellInteger (1000*k) ++ "th" |
|||
(k, m) -> spellInteger (k*1000) ++ s ++ spellOrdinal m |
|||
where s = if m < 100 then " and " else ", " |
|||
where |
|||
small = ([ undefined, "first", "second", "third", "fourth", "fifth" |
|||
, "sixth", "seventh", "eighth", "nineth", "tenth", "eleventh" |
|||
, "twelveth", "thirteenth", "fourteenth", "fifteenth", "sixteenth" |
|||
, "seventeenth", "eighteenth", "nineteenth"] !!) . fromEnum</syntaxhighlight> |
|||
Testing |
|||
<syntaxhighlight lang="haskell">main = mapM_ (\n -> putStrLn $ show n ++ "\t" ++ spellOrdinal n) |
|||
[1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003]</syntaxhighlight> |
|||
<pre>λ> main |
|||
1 first |
|||
2 second |
|||
3 third |
|||
4 fourth |
|||
5 fifth |
|||
11 eleventh |
|||
65 sixty-fifth |
|||
100 one hundredth |
|||
101 one hundred and first |
|||
272 two hundred and seventy-second |
|||
23456 twenty-three thousand, four hundred and fifty-sixth |
|||
8007006005004003 eight quadrillion, seven trillion, six billion, five million, four thousand and third</pre> |
|||
=={{header|J}}== |
|||
Here, we follow J's [[j:Vocabulary/Idioms#Ordinal_Number|best practice for ordinal numbers]], which is that 0 is first and 1 is second. This emphasizes the distinction between cardinal numbers like 0 and ordinal numbers like first, accurately represents array indices, and neatly captures a variety of related linguistic issues. |
|||
Also, we use definitions from the [[Number_names#J|number names task]] and the [[N%27th#J|N'th task]]: |
|||
<syntaxhighlight lang="j">ord=: {{ |
|||
((us,suf)1+y) rplc ;:{{)n onest first twond second |
|||
threerd third fiveth fifth eightth eighth |
|||
}}-.LF |
|||
}}</syntaxhighlight> |
|||
Examples: |
|||
<syntaxhighlight lang="j"> ord 0 |
|||
first |
|||
ord 1 |
|||
second |
|||
ord 2 |
|||
third |
|||
ord 3 |
|||
fourth |
|||
ord 4 |
|||
fifth |
|||
ord 5 |
|||
sixth |
|||
ord 11 |
|||
twelveth |
|||
ord 65 |
|||
sixty-sixth |
|||
ord 100 |
|||
one hundred first |
|||
ord 101 |
|||
one hundred second |
|||
ord 272 |
|||
two hundred seventy-third |
|||
ord 23456 |
|||
twenty-three thousand four hundred fifty-seventh |
|||
ord 8007006005004003 |
|||
eight quadrillion seven trillion six billion five million four thousand fourth |
|||
ord 123 |
|||
one hundred twenty-fourth |
|||
ord 00123.0 |
|||
one hundred twenty-fourth |
|||
ord 1.23e2 |
|||
one hundred twenty-fourth</syntaxhighlight> |
|||
=={{header|Java}}== |
|||
<syntaxhighlight lang="java"> |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
public class SpellingOfOrdinalNumbers { |
|||
public static void main(String[] args) { |
|||
for ( long test : new long[] {1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003L} ) { |
|||
System.out.printf("%d = %s%n", test, toOrdinal(test)); |
|||
} |
|||
} |
|||
private static Map<String,String> ordinalMap = new HashMap<>(); |
|||
static { |
|||
ordinalMap.put("one", "first"); |
|||
ordinalMap.put("two", "second"); |
|||
ordinalMap.put("three", "third"); |
|||
ordinalMap.put("five", "fifth"); |
|||
ordinalMap.put("eight", "eighth"); |
|||
ordinalMap.put("nine", "ninth"); |
|||
ordinalMap.put("twelve", "twelfth"); |
|||
} |
|||
private static String toOrdinal(long n) { |
|||
String spelling = numToString(n); |
|||
String[] split = spelling.split(" "); |
|||
String last = split[split.length - 1]; |
|||
String replace = ""; |
|||
if ( last.contains("-") ) { |
|||
String[] lastSplit = last.split("-"); |
|||
String lastWithDash = lastSplit[1]; |
|||
String lastReplace = ""; |
|||
if ( ordinalMap.containsKey(lastWithDash) ) { |
|||
lastReplace = ordinalMap.get(lastWithDash); |
|||
} |
|||
else if ( lastWithDash.endsWith("y") ) { |
|||
lastReplace = lastWithDash.substring(0, lastWithDash.length() - 1) + "ieth"; |
|||
} |
|||
else { |
|||
lastReplace = lastWithDash + "th"; |
|||
} |
|||
replace = lastSplit[0] + "-" + lastReplace; |
|||
} |
|||
else { |
|||
if ( ordinalMap.containsKey(last) ) { |
|||
replace = ordinalMap.get(last); |
|||
} |
|||
else if ( last.endsWith("y") ) { |
|||
replace = last.substring(0, last.length() - 1) + "ieth"; |
|||
} |
|||
else { |
|||
replace = last + "th"; |
|||
} |
|||
} |
|||
split[split.length - 1] = replace; |
|||
return String.join(" ", split); |
|||
} |
|||
private static final String[] nums = new String[] { |
|||
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", |
|||
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" |
|||
}; |
|||
private static final String[] tens = new String[] {"zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}; |
|||
private static final String numToString(long n) { |
|||
return numToStringHelper(n); |
|||
} |
|||
private static final String numToStringHelper(long n) { |
|||
if ( n < 0 ) { |
|||
return "negative " + numToStringHelper(-n); |
|||
} |
|||
int index = (int) n; |
|||
if ( n <= 19 ) { |
|||
return nums[index]; |
|||
} |
|||
if ( n <= 99 ) { |
|||
return tens[index/10] + (n % 10 > 0 ? "-" + numToStringHelper(n % 10) : ""); |
|||
} |
|||
String label = null; |
|||
long factor = 0; |
|||
if ( n <= 999 ) { |
|||
label = "hundred"; |
|||
factor = 100; |
|||
} |
|||
else if ( n <= 999999) { |
|||
label = "thousand"; |
|||
factor = 1000; |
|||
} |
|||
else if ( n <= 999999999) { |
|||
label = "million"; |
|||
factor = 1000000; |
|||
} |
|||
else if ( n <= 999999999999L) { |
|||
label = "billion"; |
|||
factor = 1000000000; |
|||
} |
|||
else if ( n <= 999999999999999L) { |
|||
label = "trillion"; |
|||
factor = 1000000000000L; |
|||
} |
|||
else if ( n <= 999999999999999999L) { |
|||
label = "quadrillion"; |
|||
factor = 1000000000000000L; |
|||
} |
|||
else { |
|||
label = "quintillion"; |
|||
factor = 1000000000000000000L; |
|||
} |
|||
return numToStringHelper(n / factor) + " " + label + (n % factor > 0 ? " " + numToStringHelper(n % factor ) : ""); |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 = first |
|||
2 = second |
|||
3 = third |
|||
4 = fourth |
|||
5 = fifth |
|||
11 = eleventh |
|||
65 = sixty-fifth |
|||
100 = one hundredth |
|||
101 = one hundred first |
|||
272 = two hundred seventy-second |
|||
23456 = twenty-three thousand four hundred fifty-sixth |
|||
8007006005004003 = eight quadrillion seven trillion six billion five million four thousand third |
|||
</pre> |
|||
=={{header|jq}}== |
|||
'''Adapted from [[#Wren|Wren]]''' |
|||
{{works with|jq}} |
|||
'''Also works with gojq and fq, the Go implementations''' |
|||
One point of interest in the following is that the program checks not |
|||
only that its integer input is within the scope of the program, but |
|||
also that it is within the capability of the C or Go platform. |
|||
In particular, `check_ok` checks for the platform's precision of |
|||
integer arithmetic. |
|||
For further remarks on this point, see the comments that |
|||
are included in the test data. |
|||
<syntaxhighlight lang=jq> |
|||
# integer division for precision when using gojq |
|||
def idivide($j): |
|||
. as $i |
|||
| ($i % $j) as $mod |
|||
| ($i - $mod) / $j ; |
|||
def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .; |
|||
def small: |
|||
["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"]; |
|||
# Up to 1e63 (vigintillion) |
|||
def illions: |
|||
["", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion", |
|||
" sextillion", " septillion", " octillion", " nonillion", " decillion", " undecillion", |
|||
" duodecillion", " tredecillion", " quattuordecillion", " quindecillion", |
|||
" sexdecillion", " septendecillion", " octadecillion", " novemdecillion", |
|||
" vigintillion" |
|||
]; |
|||
def illions($i): |
|||
if $i >= (illions|length) then "\($i * 3) zeros is beyond the scope of this exercise" | error |
|||
else illions[$i] |
|||
end; |
|||
def irregularOrdinals: { |
|||
"one": "first", |
|||
"two": "second", |
|||
"three": "third", |
|||
"five": "fifth", |
|||
"eight": "eighth", |
|||
"nine": "ninth", |
|||
"twelve": "twelfth" |
|||
}; |
|||
def check_ok: |
|||
def ieee754: |
|||
9007199254740993==9007199254740992; |
|||
if ieee754 |
|||
then if (. > 0 and (. + 1) == .) or (. < 0 and (. - 1) == .) |
|||
then "The number \(.) is too large for this platform" | error |
|||
else . |
|||
end |
|||
else . |
|||
end; |
|||
# error courtesy of illions/1 if order of magnitude is too large |
|||
def say: |
|||
check_ok |
|||
| { t: "", n: .} |
|||
| if .n < 0 then .t = "negative " | .n *= -1 else . end |
|||
| if .n < 20 |
|||
then .t += small[.n] |
|||
elif .n < 100 |
|||
then .t += tens[.n | idivide(10)] |
|||
| .s = .n % 10 |
|||
| if .s > 0 then .t += "-" + small[.s] else . end |
|||
elif .n < 1000 |
|||
then .t += small[.n | idivide(100)] + " hundred" |
|||
| .s = .n % 100 |
|||
| if .s > 0 then .t += " " + (.s|say) else . end |
|||
else .sx = "" |
|||
| .i = 0 |
|||
| until (.n <= 0; |
|||
.p = .n % 1000 |
|||
| .n = (.n | idivide(1000)) |
|||
| if .p > 0 |
|||
then .ix = (.p|say) + illions(.i) |
|||
| if .sx != "" then .ix += " " + .sx else . end |
|||
| .sx = .ix |
|||
else . |
|||
end |
|||
| .i += 1 ) |
|||
| .t += .sx |
|||
end |
|||
| .t ; |
|||
def sayOrdinal: |
|||
{n: ., s: say} |
|||
| .r = (.s | explode | reverse | implode) |
|||
| .i1 = (.r|index(" ")) |
|||
| if .i1 then .i1 = (.s|length) - 1 - .i1 else . end |
|||
| .i2 = (.r|index("-")) |
|||
| if .i2 then .i2 = (.s|length) - 1 - .i2 else . end |
|||
# Set .i to 0 iff there was no space or hyphen: |
|||
| .i = (if .i1 or .i2 then 1 + ([.i1,.i2] | max) else 0 end) |
|||
# Now s[.i:] is the last word: |
|||
| irregularOrdinals[.s[.i:]] as $x |
|||
| if $x then .s[:.i] + $x |
|||
elif .s | endswith("y") |
|||
then .s[:-1] + "ieth" |
|||
else .s + "th" |
|||
end; |
|||
# Sample inputs |
|||
(1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, |
|||
8007006005004003, |
|||
9007199254740991, |
|||
2e12, |
|||
9007199254740993, # too large for jq |
|||
# 1e63 is vigintillion so gojq should be able to handle 999 * 1e63 |
|||
999000000000000000000000000000000000000000000000000000000000000000, |
|||
# ... but not 1000 vigintillion |
|||
1000000000000000000000000000000000000000000000000000000000000000000 |
|||
) |
|||
| "\(lpad(10)) => \(sayOrdinal)" |
|||
</syntaxhighlight> |
|||
{{output}} |
|||
The output using gojq is shown first. The tail of the output |
|||
using jq is then shown to illustrate what happens when the program |
|||
determines the given integer is too large for jq's built-in support |
|||
for integer arithmetic. |
|||
'''Using gojq''' |
|||
<pre> |
|||
1 => first |
|||
2 => second |
|||
3 => third |
|||
4 => fourth |
|||
5 => fifth |
|||
11 => eleventh |
|||
65 => sixty-fifth |
|||
100 => one hundredth |
|||
101 => one hundred first |
|||
272 => two hundred seventy-second |
|||
23456 => twenty-three thousand four hundred fifty-sixth |
|||
8007006005004003 => eight quadrillion seven trillion six billion five million four thousand third |
|||
9007199254740991 => nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-first |
|||
2000000000000 => two trillionth |
|||
9007199254740993 => nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-third |
|||
999000000000000000000000000000000000000000000000000000000000000000 => nine hundred ninety-nine vigintillionth |
|||
gojq: error: 66 zeros is beyond the scope of this exercise |
|||
</pre> |
|||
'''Tail of output using the C implementation''' |
|||
<pre> |
|||
2000000000000 => two trillionth |
|||
jq: error (at <unknown>): The number 9007199254740992 is too large for this platform |
|||
</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
This makes use of code posted on this site by MichaeLeroy for a similar task at |
This makes use of code posted on this site by MichaeLeroy for a similar task at [[Number_names#Julia]]. The function num2text is used (but not included here) as posted from that location. |
||
<syntaxhighlight lang="julia"> |
|||
<lang Julia> |
|||
const irregular = Dict("one" => "first", "two" => "second", "three" => "third", "five" => "fifth", |
const irregular = Dict("one" => "first", "two" => "second", "three" => "third", "five" => "fifth", |
||
"eight" => "eighth", "nine" => "ninth", "twelve" => "twelfth") |
"eight" => "eighth", "nine" => "ninth", "twelve" => "twelfth") |
||
Line 336: | Line 1,378: | ||
println("$n => $(numtext2ordinal(num2text(n)))") |
println("$n => $(numtext2ordinal(num2text(n)))") |
||
end |
end |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{output}} |
{{output}} |
||
<pre> |
<pre> |
||
Line 355: | Line 1,397: | ||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
This makes use of the code at https://rosettacode.org/wiki/Number_names#Kotlin, which I also wrote, and adjusts it to output the corresponding ordinal. Although, for good measure, the program can deal with negative integers, zero and UK-style numbers (the insertion of 'and' at strategic places, no 'milliards' I promise!) none of these are actually tested in line with the task's requirements. |
This makes use of the code at https://rosettacode.org/wiki/Number_names#Kotlin, which I also wrote, and adjusts it to output the corresponding ordinal. Although, for good measure, the program can deal with negative integers, zero and UK-style numbers (the insertion of 'and' at strategic places, no 'milliards' I promise!) none of these are actually tested in line with the task's requirements. |
||
< |
<syntaxhighlight lang="scala">// version 1.1.4-3 |
||
typealias IAE = IllegalArgumentException |
typealias IAE = IllegalArgumentException |
||
Line 483: | Line 1,525: | ||
val sa = arrayOf("123", "00123.0", "1.23e2") |
val sa = arrayOf("123", "00123.0", "1.23e2") |
||
for (s in sa) println("${"%16s".format(s)} = ${numToOrdinalText(s)}") |
for (s in sa) println("${"%16s".format(s)} = ${numToOrdinalText(s)}") |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 505: | Line 1,547: | ||
</pre> |
</pre> |
||
=={{header|Nim}}== |
|||
{{trans|Python}} |
|||
As in the Python solution, we reuse the output of <code>spellInteger</code> from the |
|||
[[Number_names#Nim|Number_names]] task. |
|||
<syntaxhighlight lang="nim">import strutils, algorithm, tables |
|||
=={{header|Perl}}== |
|||
Adding zero to the input forces a numeric conversion (any identity operation would suffice). |
|||
<lang perl>use Lingua::EN::Numbers 'num2en_ordinal'; |
|||
const irregularOrdinals = {"one": "first", |
|||
printf "%16s : %s\n", $_, num2en_ordinal(0+$_) for |
|||
"two": "second", |
|||
<1 2 3 4 5 11 65 100 101 272 23456 8007006005004003 123 00123.0 '00123.0' 1.23e2 '1.23e2'>;</lang> |
|||
"three": "third", |
|||
{{out}} |
|||
"five": "fifth", |
|||
"eight": "eighth", |
|||
"nine": "ninth", |
|||
"twelve": "twelfth"}.toTable |
|||
5 : fifth |
|||
11 : eleventh |
|||
65 : sixty-fifth |
|||
100 : one hundredth |
|||
101 : one hundred and first |
|||
272 : two hundred and seventy-second |
|||
23456 : twenty-three thousand four hundred and fifty-sixth |
|||
8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand and third |
|||
123 : one hundred and twenty-third |
|||
00123.0 : one hundred and twenty-third |
|||
00123.0 : one hundred and twenty-third |
|||
1.23e2 : one hundred and twenty-third |
|||
1.23e2 : one hundred and twenty-third</pre> |
|||
const |
|||
=={{header|Perl 6}}== |
|||
tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", |
|||
{{works with|Rakudo|2017.08}} |
|||
"eighty", "ninety"] |
|||
This would be pretty simple to implement from scratch; it would be straightforward to do a minor modification of the [[Number_names#Perl_6| Number names]] task code. Much simpler to just use the Lingua::EN::Numbers::Cardinal module from the Perl 6 ecosystem though. It easily handles ordinal numbers even though that is not its primary focus. |
|||
small = ["zero", "one", "two", "three", "four", "five", "six", "seven", |
|||
"eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", |
|||
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen"] |
|||
huge = ["", "", "million", "billion", "trillion", "quadrillion", |
|||
"quintillion", "sextillion", "septillion", "octillion", "nonillion", |
|||
"decillion"] |
|||
# Forward reference. |
|||
We need to be slightly careful of terminology. In Perl 6, 123, 00123.0, & 1.23e2 are not all integers. They are respectively an Int (integer), a Rat (rational number) and a Num (floating point number). (The fourth numeric is a Complex) For this task it doesn't much matter as the ordinal routine coerces its argument to an Int, but to Perl 6 they are different things. We can further abuse allomorphic types and role mixins for some somewhat non-intuitive results as well. |
|||
proc spellInteger(n: int64): string |
|||
proc nonzero(c: string; n: int64; connect = ""): string = |
|||
Note that the different allomorphic integer forms of 123 are evaluated on ''use'', not on ''assignment''. They can be passed around in parameters, but until they are used numerically, they retain their stringy characteristics. The numerics are evaluated on assignment, hence the stringified output not exactly matching the input format. The mixin role returns different things depending on what context you evaluate it under. When evaluated as a string it is 17, numerically, it is 123. |
|||
if n == 0: "" else: connect & c & spellInteger(n) |
|||
proc lastAnd(num: string): string = |
|||
Perl 6 uses Unicode natively. If it has a Unicode 'Numeric Digit' property, it is treated as a numeric digit. |
|||
if ',' in num: |
|||
let pos = num.rfind(',') |
|||
var (pre, last) = if pos >= 0: (num[0 ..< pos], num[pos+1 .. num.high]) |
|||
else: ("", num) |
|||
if " and " notin last: last = " and" & last |
|||
result = [pre, ",", last].join() |
|||
else: |
|||
result = num |
|||
proc big(e, n: int64): string = |
|||
It is not really clear what is meant by "Write a driver and a function...". Well, the function part is clear enough; driver not so much. Perhaps this will suffice. |
|||
if e == 0: |
|||
spellInteger(n) |
|||
elif e == 1: |
|||
spellInteger(n) & " thousand" |
|||
else: |
|||
spellInteger(n) & " " & huge[e] |
|||
iterator base1000Rev(n: int64): int64 = |
|||
<lang perl6>use Lingua::EN::Numbers::Cardinal; |
|||
var n = n |
|||
while n != 0: |
|||
let r = n mod 1000 |
|||
n = n div 1000 |
|||
yield r |
|||
proc spellInteger(n: int64): string = |
|||
printf( "\%16s : %s\n", $_, ordinal($_) ) for |
|||
if n < 0: |
|||
"minus " & spellInteger(-n) |
|||
elif n < 20: |
|||
small[int(n)] |
|||
elif n < 100: |
|||
let a = n div 10 |
|||
let b = n mod 10 |
|||
tens[int(a)] & nonzero("-", b) |
|||
elif n < 1000: |
|||
let a = n div 100 |
|||
let b = n mod 100 |
|||
small[int(a)] & " hundred" & nonzero(" ", b, " and") |
|||
else: |
|||
var sq = newSeq[string]() |
|||
var e = 0 |
|||
for x in base1000Rev(n): |
|||
if x > 0: sq.add big(e, x) |
|||
inc e |
|||
reverse sq |
|||
lastAnd(sq.join(", ")) |
|||
proc num2ordinal(n: SomeInteger|SomeFloat): string = |
|||
# Required tests |
|||
|<1 2 3 4 5 11 65 100 101 272 23456 8007006005004003>, |
|||
let n = n.int64 |
|||
# Optional tests |
|||
var num = spellInteger(n) |
|||
# Numerics |
|||
let hyphen = num.rsplit('-', 1) |
|||
|(123, 1_2_3, 00123.0, 1.23e2, 123+0i), |
|||
var number = num.rsplit(' ', 1) |
|||
var delim = ' ' |
|||
if number[^1].len > hyphen[^1].len: |
|||
number = hyphen |
|||
delim = '-' |
|||
if number[^1] in irregularOrdinals: |
|||
# Allomorphs |
|||
number[^1] = delim & irregularOrdinals[number[^1]] |
|||
|<1_2_3 00123.0 1.23e2 123+0i 0b1111011 0o173 0x7B 861/7>, |
|||
elif number[^1].endswith('y'): |
|||
number[^1] = delim & number[^1][0..^2] & "ieth" |
|||
else: |
|||
number[^1] = delim & number[^1] & "th" |
|||
result = number.join() |
|||
# Unicode (Only using groups of digits from the same Unicode block. Technically, |
|||
# digits from any block could be combined with digits from any other block.) |
|||
|((^0x1FFFF).grep( { .chr ~~ /<:Nd>/ and |
|||
.chr.uniname ~~ / "DIGIT ONE" | "DIGIT TWO" | "DIGIT THREE" / |
|||
}).rotor(3)».chr».join), |
|||
# type system abuse (role mixin) |
|||
when isMainModule: |
|||
'17' but 123;</lang> |
|||
const |
|||
tests1 = [int64 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003, 123] |
|||
tests2 = [0123.0, 1.23e2] |
|||
for num in tests1: |
|||
echo "$1 => $2".format(num, num2ordinal(num)) |
|||
for num in tests2: |
|||
echo "$1 => $2".format(num, num2ordinal(num))</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 => first |
|||
2 => second |
|||
3 => third |
|||
4 => fourth |
|||
5 => fifth |
|||
11 => eleventh |
|||
65 => sixty-fifth |
|||
100 => one hundredth |
|||
101 => one hundred and first |
|||
272 => two hundred and seventy-second |
|||
23456 => twenty-three thousand, four hundred and fifty-sixth |
|||
8007006005004003 => eight quadrillion, seven trillion, six billion, five million, four thousand, and third |
|||
123 => one hundred and twenty-third |
|||
123.0 => one hundred and twenty-third |
|||
123.0 => one hundred and twenty-third</pre> |
|||
=={{header|Perl}}== |
|||
Adding zero to the input forces a numeric conversion (any identity operation would suffice). |
|||
<syntaxhighlight lang="perl">use Lingua::EN::Numbers 'num2en_ordinal'; |
|||
printf "%16s : %s\n", $_, num2en_ordinal(0+$_) for |
|||
<1 2 3 4 5 11 65 100 101 272 23456 8007006005004003 123 00123.0 '00123.0' 1.23e2 '1.23e2'>;</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre> 1 : first |
<pre> 1 : first |
||
Line 575: | Line 1,690: | ||
65 : sixty-fifth |
65 : sixty-fifth |
||
100 : one hundredth |
100 : one hundredth |
||
101 : one hundred first |
101 : one hundred and first |
||
272 : two hundred seventy-second |
272 : two hundred and seventy-second |
||
23456 : twenty-three thousand |
23456 : twenty-three thousand four hundred and fifty-sixth |
||
8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand third |
8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand and third |
||
123 : one hundred twenty-third |
123 : one hundred and twenty-third |
||
00123.0 : one hundred and twenty-third |
|||
00123.0 : one hundred and twenty-third |
|||
1.23e2 : one hundred and twenty-third |
|||
1.23e2 : one hundred and twenty-third</pre> |
|||
1_2_3 : one hundred twenty-third |
|||
00123.0 : one hundred twenty-third |
|||
1.23e2 : one hundred twenty-third |
|||
123+0i : one hundred twenty-third |
|||
0b1111011 : one hundred twenty-third |
|||
0o173 : one hundred twenty-third |
|||
0x7B : one hundred twenty-third |
|||
861/7 : one hundred twenty-third |
|||
123 : one hundred twenty-third |
|||
١٢٣ : one hundred twenty-third |
|||
۱۲۳ : one hundred twenty-third |
|||
߁߂߃ : one hundred twenty-third |
|||
१२३ : one hundred twenty-third |
|||
১২৩ : one hundred twenty-third |
|||
੧੨੩ : one hundred twenty-third |
|||
૧૨૩ : one hundred twenty-third |
|||
୧୨୩ : one hundred twenty-third |
|||
௧௨௩ : one hundred twenty-third |
|||
౧౨౩ : one hundred twenty-third |
|||
೧೨೩ : one hundred twenty-third |
|||
൧൨൩ : one hundred twenty-third |
|||
෧෨෩ : one hundred twenty-third |
|||
๑๒๓ : one hundred twenty-third |
|||
໑໒໓ : one hundred twenty-third |
|||
༡༢༣ : one hundred twenty-third |
|||
၁၂၃ : one hundred twenty-third |
|||
႑႒႓ : one hundred twenty-third |
|||
១២៣ : one hundred twenty-third |
|||
᠑᠒᠓ : one hundred twenty-third |
|||
᥇᥈᥉ : one hundred twenty-third |
|||
᧑᧒᧓ : one hundred twenty-third |
|||
᪁᪂᪃ : one hundred twenty-third |
|||
᪑᪒᪓ : one hundred twenty-third |
|||
᭑᭒᭓ : one hundred twenty-third |
|||
᮱᮲᮳ : one hundred twenty-third |
|||
᱁᱂᱃ : one hundred twenty-third |
|||
᱑᱒᱓ : one hundred twenty-third |
|||
꘡꘢꘣ : one hundred twenty-third |
|||
꣑꣒꣓ : one hundred twenty-third |
|||
꤁꤂꤃ : one hundred twenty-third |
|||
꧑꧒꧓ : one hundred twenty-third |
|||
꧱꧲꧳ : one hundred twenty-third |
|||
꩑꩒꩓ : one hundred twenty-third |
|||
꯱꯲꯳ : one hundred twenty-third |
|||
123 : one hundred twenty-third |
|||
𐒡𐒢𐒣 : one hundred twenty-third |
|||
𐴱𐴲𐴳 : one hundred twenty-third |
|||
𑁧𑁨𑁩 : one hundred twenty-third |
|||
𑃱𑃲𑃳 : one hundred twenty-third |
|||
𑄷𑄸𑄹 : one hundred twenty-third |
|||
𑇑𑇒𑇓 : one hundred twenty-third |
|||
𑋱𑋲𑋳 : one hundred twenty-third |
|||
𑑑𑑒𑑓 : one hundred twenty-third |
|||
𑓑𑓒𑓓 : one hundred twenty-third |
|||
𑙑𑙒𑙓 : one hundred twenty-third |
|||
𑛁𑛂𑛃 : one hundred twenty-third |
|||
𑜱𑜲𑜳 : one hundred twenty-third |
|||
𑣡𑣢𑣣 : one hundred twenty-third |
|||
𑱑𑱒𑱓 : one hundred twenty-third |
|||
𑵑𑵒𑵓 : one hundred twenty-third |
|||
𑶡𑶢𑶣 : one hundred twenty-third |
|||
𖩡𖩢𖩣 : one hundred twenty-third |
|||
𖭑𖭒𖭓 : one hundred twenty-third |
|||
𝟏𝟐𝟑 : one hundred twenty-third |
|||
𝟙𝟚𝟛 : one hundred twenty-third |
|||
𝟣𝟤𝟥 : one hundred twenty-third |
|||
𝟭𝟮𝟯 : one hundred twenty-third |
|||
𝟷𝟸𝟹 : one hundred twenty-third |
|||
𞥑𞥒𞥓 : one hundred twenty-third |
|||
17 : one hundred twenty-third</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Standard builtin |
|||
<lang Phix>include demo\rosetta\number_names.exw |
|||
<!--<syntaxhighlight lang="phix">--> |
|||
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">11</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">65</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">100</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">101</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">272</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">23456</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8007006005004003</span><span style="color: #0000FF;">,</span> |
|||
constant {irregs,ordinals} = columnize({{"one","first"}, |
|||
<span style="color: #000000;">123</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">00123.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.23e2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0b1111011</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0o173</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0x7B</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">861</span><span style="color: #0000FF;">/</span><span style="color: #000000;">7</span><span style="color: #0000FF;">}</span> |
|||
{"two","second"}, |
|||
{"three","third"}, |
|||
{"five","fifth"}, |
|||
{"eight","eighth"}, |
|||
{"nine","ninth"}, |
|||
{"twelve","twelfth"}}) |
|||
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span> |
|||
function ordinal(string s) |
|||
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">ordinal</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])&</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">)</span> |
|||
integer i |
|||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span> |
|||
for i=length(s) to 1 by -1 do |
|||
<!--</syntaxhighlight>--> |
|||
integer ch = s[i] |
|||
if ch=' ' or ch='-' then exit end if |
|||
end for |
|||
integer k = find(s[i+1..$],irregs) |
|||
if k then |
|||
s = s[1..i]&ordinals[k] |
|||
elsif s[$]='y' then |
|||
s[$..$] = "ieth" |
|||
else |
|||
s &= "th" |
|||
end if |
|||
return s |
|||
end function |
|||
constant tests = {1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003, |
|||
123, 00123.0, 1.23e2, 0b1111011, 0o173, 0x7B, 861/7} |
|||
for i=1 to length(tests) do |
|||
puts(1,ordinal(spell(tests[i]))&'\n') |
|||
end for</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 712: | Line 1,733: | ||
</pre> |
</pre> |
||
=={{header|Prolog}}== |
|||
As with the Go solution, this uses the output of spell_integer from the Number_names task (not included here). |
|||
{{works with|SWI Prolog}} |
|||
<syntaxhighlight lang="prolog">test_ordinal(Number):- |
|||
number_name(Number, ordinal, Name), |
|||
writef('%w: %w\n', [Number, Name]). |
|||
main:- |
|||
test_ordinal(1), |
|||
test_ordinal(2), |
|||
test_ordinal(3), |
|||
test_ordinal(4), |
|||
test_ordinal(5), |
|||
test_ordinal(11), |
|||
test_ordinal(15), |
|||
test_ordinal(21), |
|||
test_ordinal(42), |
|||
test_ordinal(65), |
|||
test_ordinal(98), |
|||
test_ordinal(100), |
|||
test_ordinal(101), |
|||
test_ordinal(272), |
|||
test_ordinal(300), |
|||
test_ordinal(750), |
|||
test_ordinal(23456), |
|||
test_ordinal(7891233), |
|||
test_ordinal(8007006005004003).</syntaxhighlight> |
|||
Module for spelling numbers in US English: |
|||
<syntaxhighlight lang="prolog">:- module(number_name, [number_name/3]). |
|||
small_name(0, zero, zeroth). |
|||
small_name(1, one, first). |
|||
small_name(2, two, second). |
|||
small_name(3, three, third). |
|||
small_name(4, four, fourth). |
|||
small_name(5, five, fifth). |
|||
small_name(6, six, sixth). |
|||
small_name(7, seven, seventh). |
|||
small_name(8, eight, eighth). |
|||
small_name(9, nine, ninth). |
|||
small_name(10, ten, tenth). |
|||
small_name(11, eleven, eleventh). |
|||
small_name(12, tewlve, twelfth). |
|||
small_name(13, thirteen, thirteenth). |
|||
small_name(14, fourteen, fourteenth). |
|||
small_name(15, fifteen, fifteenth). |
|||
small_name(16, sixteen, sixteenth). |
|||
small_name(17, seventeen, seventeenth). |
|||
small_name(18, eighteen, eighteenth). |
|||
small_name(19, nineteen, nineteenth). |
|||
small_name(20, twenty, twentieth). |
|||
small_name(30, thirty, thirtieth). |
|||
small_name(40, forty, fortieth). |
|||
small_name(50, fifty, fiftieth). |
|||
small_name(60, sixty, sixtieth). |
|||
small_name(70, seventy, seventieth). |
|||
small_name(80, eighty, eightieth). |
|||
small_name(90, ninety, ninetieth). |
|||
big_names([big(100, hundred, hundredth), |
|||
big(1000, thousand, thousandth), |
|||
big(1000000, million, millionth), |
|||
big(1000000000, billion, billionth), |
|||
big(1000000000000, trillion, trillionth), |
|||
big(1000000000000000, quadrillion, quadrillionth), |
|||
big(1000000000000000000, quintillion, quintillionth), |
|||
big(1000000000000000000000, sextillion, sextillionth), |
|||
big(1000000000000000000000000, septillion, septillionth)]). |
|||
big_name(Number, Big):- |
|||
big_names(Names), |
|||
big_name(Names, Number, Big). |
|||
big_name([Big], _, Big):- |
|||
!. |
|||
big_name([Big1, Big2|_], Number, Big1):- |
|||
Big2 = big(N2, _, _), |
|||
Number < N2, |
|||
!. |
|||
big_name([_|Names], Number, Big):- |
|||
big_name(Names, Number, Big). |
|||
get_big_name(big(_, C, _), cardinal, C). |
|||
get_big_name(big(_, _, O), ordinal, O). |
|||
get_small_name(Number, cardinal, Name):- |
|||
small_name(Number, Name, _), |
|||
!. |
|||
get_small_name(Number, ordinal, Name):- |
|||
small_name(Number, _, Name). |
|||
number_name(Number, Type, Name):- |
|||
Number < 20, |
|||
!, |
|||
get_small_name(Number, Type, Name). |
|||
number_name(Number, Type, Name):- |
|||
Number < 100, |
|||
!, |
|||
N is Number mod 10, |
|||
(N = 0 -> |
|||
get_small_name(Number, Type, Name) |
|||
; |
|||
N1 is Number - N, |
|||
get_small_name(N1, cardinal, Name1), |
|||
get_small_name(N, Type, Name2), |
|||
atomic_list_concat([Name1, '-', Name2], Name) |
|||
). |
|||
number_name(Number, Type, Name):- |
|||
big_name(Number, big(P, C, O)), |
|||
N is Number // P, |
|||
number_name(N, cardinal, Name1), |
|||
M is Number mod P, |
|||
(M = 0 -> |
|||
get_big_name(big(P, C, O), Type, Name2) |
|||
; |
|||
number_name(M, Type, Name3), |
|||
atomic_list_concat([C, ' ', Name3], Name2) |
|||
), |
|||
atomic_list_concat([Name1, ' ', Name2], Name).</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1: first |
|||
2: second |
|||
3: third |
|||
4: fourth |
|||
5: fifth |
|||
11: eleventh |
|||
15: fifteenth |
|||
21: twenty-first |
|||
42: forty-second |
|||
65: sixty-fifth |
|||
98: ninety-eighth |
|||
100: one hundredth |
|||
101: one hundred first |
|||
272: two hundred seventy-second |
|||
300: three hundredth |
|||
750: seven hundred fiftieth |
|||
23456: twenty-three thousand four hundred fifty-sixth |
|||
7891233: seven million eight hundred ninety-one thousand two hundred thirty-third |
|||
8007006005004003: eight quadrillion seven trillion six billion five million four thousand third |
|||
</pre> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
||
Line 719: | Line 1,881: | ||
[[Number_names#Python|Number_names]] task. |
[[Number_names#Python|Number_names]] task. |
||
< |
<syntaxhighlight lang="python">irregularOrdinals = { |
||
"one": "first", |
"one": "first", |
||
"two": "second", |
"two": "second", |
||
Line 805: | Line 1,967: | ||
num = ", ".join([big(e, x) for e, x in |
num = ", ".join([big(e, x) for e, x in |
||
enumerate(base1000_rev(n)) if x][::-1]) |
enumerate(base1000_rev(n)) if x][::-1]) |
||
return last_and(num)</ |
return last_and(num)</syntaxhighlight> |
||
<b>Output</b> |
<b>Output</b> |
||
<pre> |
<pre> |
||
Line 824: | Line 1,986: | ||
1.23e2 => one hundred and twenty-third |
1.23e2 => one hundred and twenty-third |
||
</pre> |
</pre> |
||
=={{header|Quackery}}== |
|||
<code>name$</code> is defined at [[Number names#Quackery]]. |
|||
<code>switch</code>, <code>case</code>, and <code>otherwise</code> are defined at [[Metaprogramming#Quackery]]. |
|||
<syntaxhighlight lang="Quackery"> [ name$ |
|||
dup -2 split nip |
|||
[ switch |
|||
$ "ne" case |
|||
[ -3 split drop |
|||
$ "first" join ] |
|||
$ "wo" case |
|||
[ -3 split drop |
|||
$ "second" join ] |
|||
$ "ee" case |
|||
[ -3 split drop |
|||
$ "ird" join ] |
|||
$ "ve" case |
|||
[ -2 split drop |
|||
$ "fth" join ] |
|||
$ "ht" case |
|||
[ $ "h" join ] |
|||
$ "ty" case |
|||
[ -1 split drop |
|||
$ "ieth" join ] |
|||
otherwise |
|||
[ $ "th" join ] ] ] is nameth$ ( n --> $ ) |
|||
' [ 1 2 3 4 5 11 65 100 101 272 23456 8007006005004003 ] |
|||
witheach |
|||
[ dup echo say " = " nameth$ echo$ cr ]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 = first |
|||
2 = second |
|||
3 = third |
|||
4 = fourth |
|||
5 = fifth |
|||
11 = eleventh |
|||
65 = sixty fifth |
|||
100 = one hundredth |
|||
101 = one hundred and first |
|||
272 = two hundred and seventy second |
|||
23456 = twenty three thousand and four hundred and fifty sixth |
|||
8007006005004003 = eight quadrillion, seven trillion, six billion, five million, four thousand and third</pre> |
|||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
{{works with|Rakudo|2019.07.1}} |
|||
Rakudo version 2019.07.1 is updated to Unicode version 12.1. Unicode version 12.0 introduced some new numeric digits, which changed the output here a bit. This will ''work'' with earlier versions of Rakudo, but will yield slightly different results. |
|||
This would be pretty simple to implement from scratch; it would be straightforward to do a minor modification of the [[Number_names#Raku| Number names]] task code. Much simpler to just use the Lingua::EN::Numbers module from the Raku ecosystem though. It will easily handles ordinal number conversions. |
|||
We need to be slightly careful of terminology. In Raku, 123, 00123.0, & 1.23e2 are not all integers. They are respectively an Int (integer), a Rat (rational number) and a Num (floating point number). (The fourth numeric is a Complex) For this task it doesn't much matter as the ordinal routine coerces its argument to an Int, but to Raku they are different things. We can further abuse allomorphic and String types and role mixins for some somewhat non-intuitive results as well. |
|||
Note that the different allomorphic integer forms of 123 are evaluated on ''use'', not on ''assignment''. They can be passed around in parameters, but until they are used numerically, they retain their stringy characteristics and are distinctive, determinable through introspection. The numerics are evaluated on assignment, hence the stringified output not exactly matching the input format. The mixin role returns different things depending on what context you evaluate it under. When evaluated as a string it is 17, numerically, it is 123. |
|||
Raku uses Unicode natively. If a glyph has a Unicode 'Numeric Digit' (<:Nd>) property, it is treated as a numeric digit, and may be used as one. |
|||
It is not really clear what is meant by "Write a driver and a function...". Well, the function part is clear enough; driver not so much. Perhaps this will suffice. |
|||
<syntaxhighlight lang="raku" line>use Lingua::EN::Numbers; |
|||
# The task |
|||
+$_ ?? printf( "Type: \%-14s %16s : %s\n", .^name, $_, .&ordinal ) !! say "\n$_:" for |
|||
# Testing |
|||
'Required tests', |
|||
1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003, |
|||
'Optional tests - different forms of 123', |
|||
'Numerics', |
|||
123, 00123.0, 1.23e2, 123+0i, |
|||
'Allomorphs', |
|||
|<123 1_2_3 00123.0 1.23e2 123+0i 0b1111011 0o173 0x7B 861/7>, |
|||
'Numeric Strings', |
|||
|'1_2_3 00123.0 1.23e2 123+0i 0b1111011 0o173 0x7B 861/7'.words, |
|||
'Unicode Numeric Strings', |
|||
# (Only using groups of digits from the same Unicode block. Technically, |
|||
# digits from any block could be combined with digits from any other block.) |
|||
|(^0x1FFFF).grep( { .chr ~~ /<:Nd>/ and .unival == 1|2|3 }).rotor(3)».chr».join, |
|||
'Role Mixin', |
|||
'17' but 123;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>Required tests: |
|||
Type: Int 1 : first |
|||
Type: Int 2 : second |
|||
Type: Int 3 : third |
|||
Type: Int 4 : fourth |
|||
Type: Int 5 : fifth |
|||
Type: Int 11 : eleventh |
|||
Type: Int 65 : sixty-fifth |
|||
Type: Int 100 : one hundredth |
|||
Type: Int 101 : one hundred first |
|||
Type: Int 272 : two hundred seventy-second |
|||
Type: Int 23456 : twenty-three thousand, four hundred fifty-sixth |
|||
Type: Int 8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand third |
|||
Optional tests - different forms of 123: |
|||
Numerics: |
|||
Type: Int 123 : one hundred twenty-third |
|||
Type: Rat 123 : one hundred twenty-third |
|||
Type: Num 123 : one hundred twenty-third |
|||
Type: Complex 123+0i : one hundred twenty-third |
|||
Allomorphs: |
|||
Type: IntStr 123 : one hundred twenty-third |
|||
Type: IntStr 1_2_3 : one hundred twenty-third |
|||
Type: RatStr 00123.0 : one hundred twenty-third |
|||
Type: NumStr 1.23e2 : one hundred twenty-third |
|||
Type: ComplexStr 123+0i : one hundred twenty-third |
|||
Type: IntStr 0b1111011 : one hundred twenty-third |
|||
Type: IntStr 0o173 : one hundred twenty-third |
|||
Type: IntStr 0x7B : one hundred twenty-third |
|||
Type: RatStr 861/7 : one hundred twenty-third |
|||
Numeric Strings: |
|||
Type: Str 1_2_3 : one hundred twenty-third |
|||
Type: Str 00123.0 : one hundred twenty-third |
|||
Type: Str 1.23e2 : one hundred twenty-third |
|||
Type: Str 123+0i : one hundred twenty-third |
|||
Type: Str 0b1111011 : one hundred twenty-third |
|||
Type: Str 0o173 : one hundred twenty-third |
|||
Type: Str 0x7B : one hundred twenty-third |
|||
Type: Str 861/7 : one hundred twenty-third |
|||
Unicode Numeric Strings: |
|||
Type: Str 123 : one hundred twenty-third |
|||
Type: Str ١٢٣ : one hundred twenty-third |
|||
Type: Str ۱۲۳ : one hundred twenty-third |
|||
Type: Str ߁߂߃ : one hundred twenty-third |
|||
Type: Str १२३ : one hundred twenty-third |
|||
Type: Str ১২৩ : one hundred twenty-third |
|||
Type: Str ੧੨੩ : one hundred twenty-third |
|||
Type: Str ૧૨૩ : one hundred twenty-third |
|||
Type: Str ୧୨୩ : one hundred twenty-third |
|||
Type: Str ௧௨௩ : one hundred twenty-third |
|||
Type: Str ౧౨౩ : one hundred twenty-third |
|||
Type: Str ೧೨೩ : one hundred twenty-third |
|||
Type: Str ൧൨൩ : one hundred twenty-third |
|||
Type: Str ෧෨෩ : one hundred twenty-third |
|||
Type: Str ๑๒๓ : one hundred twenty-third |
|||
Type: Str ໑໒໓ : one hundred twenty-third |
|||
Type: Str ༡༢༣ : one hundred twenty-third |
|||
Type: Str ၁၂၃ : one hundred twenty-third |
|||
Type: Str ႑႒႓ : one hundred twenty-third |
|||
Type: Str ១២៣ : one hundred twenty-third |
|||
Type: Str ᠑᠒᠓ : one hundred twenty-third |
|||
Type: Str ᥇᥈᥉ : one hundred twenty-third |
|||
Type: Str ᧑᧒᧓ : one hundred twenty-third |
|||
Type: Str ᪁᪂᪃ : one hundred twenty-third |
|||
Type: Str ᪑᪒᪓ : one hundred twenty-third |
|||
Type: Str ᭑᭒᭓ : one hundred twenty-third |
|||
Type: Str ᮱᮲᮳ : one hundred twenty-third |
|||
Type: Str ᱁᱂᱃ : one hundred twenty-third |
|||
Type: Str ᱑᱒᱓ : one hundred twenty-third |
|||
Type: Str ꘡꘢꘣ : one hundred twenty-third |
|||
Type: Str ꣑꣒꣓ : one hundred twenty-third |
|||
Type: Str ꤁꤂꤃ : one hundred twenty-third |
|||
Type: Str ꧑꧒꧓ : one hundred twenty-third |
|||
Type: Str ꧱꧲꧳ : one hundred twenty-third |
|||
Type: Str ꩑꩒꩓ : one hundred twenty-third |
|||
Type: Str ꯱꯲꯳ : one hundred twenty-third |
|||
Type: Str 123 : one hundred twenty-third |
|||
Type: Str 𐒡𐒢𐒣 : one hundred twenty-third |
|||
Type: Str 𐴱𐴲𐴳 : one hundred twenty-third |
|||
Type: Str 𑁧𑁨𑁩 : one hundred twenty-third |
|||
Type: Str 𑃱𑃲𑃳 : one hundred twenty-third |
|||
Type: Str 𑄷𑄸𑄹 : one hundred twenty-third |
|||
Type: Str 𑇑𑇒𑇓 : one hundred twenty-third |
|||
Type: Str 𑋱𑋲𑋳 : one hundred twenty-third |
|||
Type: Str 𑑑𑑒𑑓 : one hundred twenty-third |
|||
Type: Str 𑓑𑓒𑓓 : one hundred twenty-third |
|||
Type: Str 𑙑𑙒𑙓 : one hundred twenty-third |
|||
Type: Str 𑛁𑛂𑛃 : one hundred twenty-third |
|||
Type: Str 𑜱𑜲𑜳 : one hundred twenty-third |
|||
Type: Str 𑣡𑣢𑣣 : one hundred twenty-third |
|||
Type: Str 𑱑𑱒𑱓 : one hundred twenty-third |
|||
Type: Str 𑵑𑵒𑵓 : one hundred twenty-third |
|||
Type: Str 𑶡𑶢𑶣 : one hundred twenty-third |
|||
Type: Str 𖩡𖩢𖩣 : one hundred twenty-third |
|||
Type: Str 𖭑𖭒𖭓 : one hundred twenty-third |
|||
Type: Str 𝟏𝟐𝟑 : one hundred twenty-third |
|||
Type: Str 𝟙𝟚𝟛 : one hundred twenty-third |
|||
Type: Str 𝟣𝟤𝟥 : one hundred twenty-third |
|||
Type: Str 𝟭𝟮𝟯 : one hundred twenty-third |
|||
Type: Str 𝟷𝟸𝟹 : one hundred twenty-third |
|||
Type: Str 𞥑𞥒𞥓 : one hundred twenty-third |
|||
Role Mixin: |
|||
Type: Str+{<anon|1>} 17 : one hundred twenty-third</pre> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
< |
<syntaxhighlight lang="rexx">/*REXX programs spells out ordinal numbers (in English, using the American system). */ |
||
numeric digits 3000 /*just in case the user uses gihugic #s*/ |
numeric digits 3000 /*just in case the user uses gihugic #s*/ |
||
parse arg n /*obtain optional arguments from the CL*/ |
parse arg n /*obtain optional arguments from the CL*/ |
||
Line 839: | Line 2,201: | ||
os=$spell#(x pgmOpts) /*invoke REXX routine to spell ordinal#*/ |
os=$spell#(x pgmOpts) /*invoke REXX routine to spell ordinal#*/ |
||
say right(x, max(20, length(x) ) ) ' spelled ordinal number ───► ' os |
say right(x, max(20, length(x) ) ) ' spelled ordinal number ───► ' os |
||
end /*j*/</ |
end /*j*/</syntaxhighlight> |
||
{{out|output|text= when using the default inputs:}} |
{{out|output|text= when using the default inputs:}} |
||
<pre> |
<pre> |
||
Line 856: | Line 2,218: | ||
</pre> |
</pre> |
||
The '''$SPELL#.REX''' routine can be found here ───► [[$SPELL.REX|$SPELL#.REX]]. <br><br> |
The '''$SPELL#.REX''' routine can be found here ───► [[$SPELL.REX|$SPELL#.REX]]. <br><br> |
||
=={{header|Rust}}== |
|||
{{trans|C++}} |
|||
<syntaxhighlight lang="rust">struct NumberNames { |
|||
cardinal: &'static str, |
|||
ordinal: &'static str, |
|||
} |
|||
impl NumberNames { |
|||
fn get_name(&self, ordinal: bool) -> &'static str { |
|||
if ordinal { |
|||
return self.ordinal; |
|||
} |
|||
self.cardinal |
|||
} |
|||
} |
|||
const SMALL_NAMES: [NumberNames; 20] = [ |
|||
NumberNames { |
|||
cardinal: "zero", |
|||
ordinal: "zeroth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "one", |
|||
ordinal: "first", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "two", |
|||
ordinal: "second", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "three", |
|||
ordinal: "third", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "four", |
|||
ordinal: "fourth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "five", |
|||
ordinal: "fifth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "six", |
|||
ordinal: "sixth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "seven", |
|||
ordinal: "seventh", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "eight", |
|||
ordinal: "eighth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "nine", |
|||
ordinal: "ninth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "ten", |
|||
ordinal: "tenth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "eleven", |
|||
ordinal: "eleventh", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "twelve", |
|||
ordinal: "twelfth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "thirteen", |
|||
ordinal: "thirteenth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "fourteen", |
|||
ordinal: "fourteenth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "fifteen", |
|||
ordinal: "fifteenth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "sixteen", |
|||
ordinal: "sixteenth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "seventeen", |
|||
ordinal: "seventeenth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "eighteen", |
|||
ordinal: "eighteenth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "nineteen", |
|||
ordinal: "nineteenth", |
|||
}, |
|||
]; |
|||
const TENS: [NumberNames; 8] = [ |
|||
NumberNames { |
|||
cardinal: "twenty", |
|||
ordinal: "twentieth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "thirty", |
|||
ordinal: "thirtieth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "forty", |
|||
ordinal: "fortieth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "fifty", |
|||
ordinal: "fiftieth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "sixty", |
|||
ordinal: "sixtieth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "seventy", |
|||
ordinal: "seventieth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "eighty", |
|||
ordinal: "eightieth", |
|||
}, |
|||
NumberNames { |
|||
cardinal: "ninety", |
|||
ordinal: "ninetieth", |
|||
}, |
|||
]; |
|||
struct NamedNumber { |
|||
cardinal: &'static str, |
|||
ordinal: &'static str, |
|||
number: usize, |
|||
} |
|||
impl NamedNumber { |
|||
fn get_name(&self, ordinal: bool) -> &'static str { |
|||
if ordinal { |
|||
return self.ordinal; |
|||
} |
|||
self.cardinal |
|||
} |
|||
} |
|||
const N: usize = 7; |
|||
const NAMED_NUMBERS: [NamedNumber; N] = [ |
|||
NamedNumber { |
|||
cardinal: "hundred", |
|||
ordinal: "hundredth", |
|||
number: 100, |
|||
}, |
|||
NamedNumber { |
|||
cardinal: "thousand", |
|||
ordinal: "thousandth", |
|||
number: 1000, |
|||
}, |
|||
NamedNumber { |
|||
cardinal: "million", |
|||
ordinal: "millionth", |
|||
number: 1000000, |
|||
}, |
|||
NamedNumber { |
|||
cardinal: "billion", |
|||
ordinal: "billionth", |
|||
number: 1000000000, |
|||
}, |
|||
NamedNumber { |
|||
cardinal: "trillion", |
|||
ordinal: "trillionth", |
|||
number: 1000000000000, |
|||
}, |
|||
NamedNumber { |
|||
cardinal: "quadrillion", |
|||
ordinal: "quadrillionth", |
|||
number: 1000000000000000, |
|||
}, |
|||
NamedNumber { |
|||
cardinal: "quintillion", |
|||
ordinal: "quintillionth", |
|||
number: 1000000000000000000, |
|||
}, |
|||
]; |
|||
fn big_name(n: usize) -> &'static NamedNumber { |
|||
for i in 1..N { |
|||
if n < NAMED_NUMBERS[i].number { |
|||
return &NAMED_NUMBERS[i - 1]; |
|||
} |
|||
} |
|||
&NAMED_NUMBERS[N - 1] |
|||
} |
|||
fn number_name(n: usize, ordinal: bool) -> String { |
|||
if n < 20 { |
|||
return String::from(SMALL_NAMES[n].get_name(ordinal)); |
|||
} else if n < 100 { |
|||
if n % 10 == 0 { |
|||
return String::from(TENS[n / 10 - 2].get_name(ordinal)); |
|||
} |
|||
let s1 = TENS[n / 10 - 2].get_name(false); |
|||
let s2 = SMALL_NAMES[n % 10].get_name(ordinal); |
|||
return format!("{}-{}", s1, s2); |
|||
} |
|||
let big = big_name(n); |
|||
let mut result = number_name(n / big.number, false); |
|||
result.push(' '); |
|||
if n % big.number == 0 { |
|||
result.push_str(big.get_name(ordinal)); |
|||
} else { |
|||
result.push_str(big.get_name(false)); |
|||
result.push(' '); |
|||
result.push_str(&number_name(n % big.number, ordinal)); |
|||
} |
|||
result |
|||
} |
|||
fn test_ordinal(n: usize) { |
|||
println!("{}: {}", n, number_name(n, true)); |
|||
} |
|||
fn main() { |
|||
test_ordinal(1); |
|||
test_ordinal(2); |
|||
test_ordinal(3); |
|||
test_ordinal(4); |
|||
test_ordinal(5); |
|||
test_ordinal(11); |
|||
test_ordinal(15); |
|||
test_ordinal(21); |
|||
test_ordinal(42); |
|||
test_ordinal(65); |
|||
test_ordinal(98); |
|||
test_ordinal(100); |
|||
test_ordinal(101); |
|||
test_ordinal(272); |
|||
test_ordinal(300); |
|||
test_ordinal(750); |
|||
test_ordinal(23456); |
|||
test_ordinal(7891233); |
|||
test_ordinal(8007006005004003); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1: first |
|||
2: second |
|||
3: third |
|||
4: fourth |
|||
5: fifth |
|||
11: eleventh |
|||
15: fifteenth |
|||
21: twenty-first |
|||
42: forty-second |
|||
65: sixty-fifth |
|||
98: ninety-eighth |
|||
100: one hundredth |
|||
101: one hundred first |
|||
272: two hundred seventy-second |
|||
300: three hundredth |
|||
750: seven hundred fiftieth |
|||
23456: twenty-three thousand four hundred fifty-sixth |
|||
7891233: seven million eight hundred ninety-one thousand two hundred thirty-third |
|||
8007006005004003: eight quadrillion seven trillion six billion five million four thousand third |
|||
</pre> |
|||
=={{header|Sidef}}== |
|||
<syntaxhighlight lang="ruby">var lingua_en = frequire('Lingua::EN::Numbers') |
|||
var tests = [1,2,3,4,5,11,65,100,101,272,23456,8007006005004003] |
|||
tests.each {|n| |
|||
printf("%16s : %s\n", n, lingua_en.num2en_ordinal(n)) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 : first |
|||
2 : second |
|||
3 : third |
|||
4 : fourth |
|||
5 : fifth |
|||
11 : eleventh |
|||
65 : sixty-fifth |
|||
100 : one hundredth |
|||
101 : one hundred and first |
|||
272 : two hundred and seventy-second |
|||
23456 : twenty-three thousand four hundred and fifty-sixth |
|||
8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand and third |
|||
</pre> |
|||
=={{header|Swift}}== |
|||
<syntaxhighlight lang="swift">fileprivate class NumberNames { |
|||
let cardinal: String |
|||
let ordinal: String |
|||
init(cardinal: String, ordinal: String) { |
|||
self.cardinal = cardinal |
|||
self.ordinal = ordinal |
|||
} |
|||
func getName(_ ordinal: Bool) -> String { |
|||
return ordinal ? self.ordinal : self.cardinal |
|||
} |
|||
class func numberName(number: Int, ordinal: Bool) -> String { |
|||
guard number < 100 else { |
|||
return "" |
|||
} |
|||
if number < 20 { |
|||
return smallNames[number].getName(ordinal) |
|||
} |
|||
if number % 10 == 0 { |
|||
return tens[number/10 - 2].getName(ordinal) |
|||
} |
|||
var result = tens[number/10 - 2].getName(false) |
|||
result += "-" |
|||
result += smallNames[number % 10].getName(ordinal) |
|||
return result |
|||
} |
|||
static let smallNames = [ |
|||
NumberNames(cardinal: "zero", ordinal: "zeroth"), |
|||
NumberNames(cardinal: "one", ordinal: "first"), |
|||
NumberNames(cardinal: "two", ordinal: "second"), |
|||
NumberNames(cardinal: "three", ordinal: "third"), |
|||
NumberNames(cardinal: "four", ordinal: "fourth"), |
|||
NumberNames(cardinal: "five", ordinal: "fifth"), |
|||
NumberNames(cardinal: "six", ordinal: "sixth"), |
|||
NumberNames(cardinal: "seven", ordinal: "seventh"), |
|||
NumberNames(cardinal: "eight", ordinal: "eighth"), |
|||
NumberNames(cardinal: "nine", ordinal: "ninth"), |
|||
NumberNames(cardinal: "ten", ordinal: "tenth"), |
|||
NumberNames(cardinal: "eleven", ordinal: "eleventh"), |
|||
NumberNames(cardinal: "twelve", ordinal: "twelfth"), |
|||
NumberNames(cardinal: "thirteen", ordinal: "thirteenth"), |
|||
NumberNames(cardinal: "fourteen", ordinal: "fourteenth"), |
|||
NumberNames(cardinal: "fifteen", ordinal: "fifteenth"), |
|||
NumberNames(cardinal: "sixteen", ordinal: "sixteenth"), |
|||
NumberNames(cardinal: "seventeen", ordinal: "seventeenth"), |
|||
NumberNames(cardinal: "eighteen", ordinal: "eighteenth"), |
|||
NumberNames(cardinal: "nineteen", ordinal: "nineteenth") |
|||
] |
|||
static let tens = [ |
|||
NumberNames(cardinal: "twenty", ordinal: "twentieth"), |
|||
NumberNames(cardinal: "thirty", ordinal: "thirtieth"), |
|||
NumberNames(cardinal: "forty", ordinal: "fortieth"), |
|||
NumberNames(cardinal: "fifty", ordinal: "fiftieth"), |
|||
NumberNames(cardinal: "sixty", ordinal: "sixtieth"), |
|||
NumberNames(cardinal: "seventy", ordinal: "seventieth"), |
|||
NumberNames(cardinal: "eighty", ordinal: "eightieth"), |
|||
NumberNames(cardinal: "ninety", ordinal: "ninetieth") |
|||
] |
|||
} |
|||
fileprivate class NamedPower { |
|||
let cardinal: String |
|||
let ordinal: String |
|||
let number: UInt64 |
|||
init(cardinal: String, ordinal: String, number: UInt64) { |
|||
self.cardinal = cardinal |
|||
self.ordinal = ordinal |
|||
self.number = number |
|||
} |
|||
func getName(_ ordinal: Bool) -> String { |
|||
return ordinal ? self.ordinal : self.cardinal |
|||
} |
|||
class func getNamedPower(_ number: UInt64) -> NamedPower { |
|||
for i in 1..<namedPowers.count { |
|||
if number < namedPowers[i].number { |
|||
return namedPowers[i - 1] |
|||
} |
|||
} |
|||
return namedPowers[namedPowers.count - 1] |
|||
} |
|||
static let namedPowers = [ |
|||
NamedPower(cardinal: "hundred", ordinal: "hundredth", |
|||
number: 100), |
|||
NamedPower(cardinal: "thousand", ordinal: "thousandth", |
|||
number: 1000), |
|||
NamedPower(cardinal: "million", ordinal: "millionth", |
|||
number: 1000000), |
|||
NamedPower(cardinal: "billion", ordinal: "billionth", |
|||
number: 1000000000), |
|||
NamedPower(cardinal: "trillion", ordinal: "trillionth", |
|||
number: 1000000000000), |
|||
NamedPower(cardinal: "quadrillion", ordinal: "quadrillionth", |
|||
number: 1000000000000000), |
|||
NamedPower(cardinal: "quintillion", ordinal: "quintillionth", |
|||
number: 1000000000000000000) |
|||
] |
|||
} |
|||
public func numberName(number: UInt64, ordinal: Bool) -> String { |
|||
if number < 100 { |
|||
return NumberNames.numberName(number: Int(truncatingIfNeeded: number), |
|||
ordinal: ordinal) |
|||
} |
|||
let p = NamedPower.getNamedPower(number) |
|||
var result = numberName(number: number/p.number, ordinal: false) |
|||
result += " " |
|||
if number % p.number == 0 { |
|||
result += p.getName(ordinal) |
|||
} else { |
|||
result += p.getName(false) |
|||
result += " " |
|||
result += numberName(number: number % p.number, ordinal: ordinal) |
|||
} |
|||
return result |
|||
} |
|||
func printOrdinal(_ number: UInt64) { |
|||
print("\(number): \(numberName(number: number, ordinal: true))") |
|||
} |
|||
printOrdinal(1) |
|||
printOrdinal(2) |
|||
printOrdinal(3) |
|||
printOrdinal(4) |
|||
printOrdinal(5) |
|||
printOrdinal(11) |
|||
printOrdinal(15) |
|||
printOrdinal(21) |
|||
printOrdinal(42) |
|||
printOrdinal(65) |
|||
printOrdinal(98) |
|||
printOrdinal(100) |
|||
printOrdinal(101) |
|||
printOrdinal(272) |
|||
printOrdinal(300) |
|||
printOrdinal(750) |
|||
printOrdinal(23456) |
|||
printOrdinal(7891233) |
|||
printOrdinal(8007006005004003)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1: first |
|||
2: second |
|||
3: third |
|||
4: fourth |
|||
5: fifth |
|||
11: eleventh |
|||
15: fifteenth |
|||
21: twenty-first |
|||
42: forty-second |
|||
65: sixty-fifth |
|||
98: ninety-eighth |
|||
100: one hundredth |
|||
101: one hundred first |
|||
272: two hundred seventy-second |
|||
300: three hundredth |
|||
750: seven hundred fiftieth |
|||
23456: twenty-three thousand four hundred fifty-sixth |
|||
7891233: seven million eight hundred ninety-one thousand two hundred thirty-third |
|||
8007006005004003: eight quadrillion seven trillion six billion five million four thousand third |
|||
</pre> |
|||
=={{header|VBA}}== |
=={{header|VBA}}== |
||
Inspired by the Phix solution. Uses [[Number_names#VBA|Number names]] |
Inspired by the Phix solution. Uses [[Number_names#VBA|Number names]] |
||
< |
<syntaxhighlight lang="vb">Private Function ordinal(s As String) As String |
||
Dim irregs As New Collection |
Dim irregs As New Collection |
||
irregs.Add "first", "one" |
irregs.Add "first", "one" |
||
Line 891: | Line 2,718: | ||
Debug.Print ordinal(spell(tests(i))) |
Debug.Print ordinal(spell(tests(i))) |
||
Next i |
Next i |
||
End Sub</ |
End Sub</syntaxhighlight>{{out}} |
||
<pre>first |
<pre>first |
||
second |
second |
||
Line 906: | Line 2,733: | ||
one hundred and twenty-third |
one hundred and twenty-third |
||
one hundred and twenty-third</pre> |
one hundred and twenty-third</pre> |
||
=={{header|V (Vlang)}}== |
|||
{{trans|go}} |
|||
As with the Kotlin solution, this uses the output of <code>say</code> from the |
|||
[[Number_names#Go|Number_names]] task. |
|||
<syntaxhighlight lang="v (vlang)">fn main() { |
|||
for n in [i64(1), 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003, |
|||
] { |
|||
println(say_ordinal(n)) |
|||
} |
|||
} |
|||
fn say_ordinal(n i64) string { |
|||
mut s := say(n) |
|||
mut i := s.last_index('-') or {s.last_index(' ') or {-1}} |
|||
i++ |
|||
// Now s[:i] is everything upto and including the space or hyphen |
|||
// and s[i:] is the last word; we modify s[i:] as required. |
|||
// Since LastIndex returns -1 if there was no space/hyphen, |
|||
// `i` will be zero and this will still be fine. |
|||
ok := s[i..] in irregular_ordinals |
|||
x := irregular_ordinals[s[i..]] |
|||
if ok { |
|||
s = s[..i] + x |
|||
} else if s[s.len-1..s.len] == 'y' { |
|||
s = s[..i] + s[i..s.len-1] + "ieth" |
|||
} else { |
|||
s = s[..i] + s[i..] + "th" |
|||
} |
|||
return s |
|||
} |
|||
// Below is a copy of https://rosettacode.org/wiki/Number_names#Go |
|||
const ( |
|||
small = ["zero", "one", "two", "three", "four", "five", "six", |
|||
"seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", |
|||
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"] |
|||
tens = ["", "", "twenty", "thirty", "forty", |
|||
"fifty", "sixty", "seventy", "eighty", "ninety"] |
|||
illions = ["", " thousand", " million", " billion", |
|||
" trillion", " quadrillion", " quintillion"] |
|||
irregular_ordinals = { |
|||
"one": "first", |
|||
"two": "second", |
|||
"three": "third", |
|||
"five": "fifth", |
|||
"eight": "eighth", |
|||
"nine": "ninth", |
|||
"twelve": "twelfth", |
|||
} |
|||
) |
|||
fn say(nn i64) string { |
|||
mut n := nn |
|||
mut t := '' |
|||
if n < 0 { |
|||
t = "negative " |
|||
// Note, for math.MinInt64 this leaves n negative. |
|||
n = -n |
|||
} |
|||
if n < 20{ |
|||
t += small[n] |
|||
} else if n < 100{ |
|||
t += tens[n/10] |
|||
s := n % 10 |
|||
if s > 0 { |
|||
t += "-" + small[s] |
|||
} |
|||
} else if n < 1000{ |
|||
t += small[n/100] + " hundred" |
|||
s := n % 100 |
|||
if s > 0 { |
|||
t += " " + say(s) |
|||
} |
|||
} else { |
|||
// work right-to-left |
|||
mut sx := "" |
|||
for i := 0; n > 0; i++ { |
|||
p := n % 1000 |
|||
n /= 1000 |
|||
if p > 0 { |
|||
mut ix := say(p) + illions[i] |
|||
if sx != "" { |
|||
ix += " " + sx |
|||
} |
|||
sx = ix |
|||
} |
|||
} |
|||
t += sx |
|||
} |
|||
return t |
|||
}</syntaxhighlight> |
|||
{{output}} |
|||
<pre>first |
|||
second |
|||
third |
|||
fourth |
|||
fifth |
|||
eleventh |
|||
sixty-fifth |
|||
one hundredth |
|||
one hundred first |
|||
two hundred seventy-second |
|||
twenty-three thousand four hundred fifty-sixth |
|||
eight quadrillion seven trillion six billion five million four thousand third</pre> |
|||
=={{header|Wren}}== |
|||
{{trans|Go}} |
|||
This reuses the <code>say</code> function from the [[Number names#Wren|Number names]] task. |
|||
Note that it is not safe to use this script for numbers with an absolute magnitude >= 2^53 as integers cannot be expressed exactly by Wren's Num type beyond that limit. |
|||
<syntaxhighlight lang="wren">var small = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", |
|||
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"] |
|||
var tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"] |
|||
var illions = ["", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion"] |
|||
var irregularOrdinals = { |
|||
"one": "first", |
|||
"two": "second", |
|||
"three": "third", |
|||
"five": "fifth", |
|||
"eight": "eighth", |
|||
"nine": "ninth", |
|||
"twelve": "twelfth" |
|||
} |
|||
var say |
|||
say = Fn.new { |n| |
|||
var t = "" |
|||
if (n < 0) { |
|||
t = "negative " |
|||
n = -n |
|||
} |
|||
if (n < 20) { |
|||
t = t + small[n] |
|||
} else if (n < 100) { |
|||
t = t + tens[(n/10).floor] |
|||
var s = n % 10 |
|||
if (s > 0) t = t + "-" + small[s] |
|||
} else if (n < 1000) { |
|||
t = t + small[(n/100).floor] + " hundred" |
|||
var s = n % 100 |
|||
System.write("") // guards against VM recursion bug |
|||
if (s > 0) t = t + " " + say.call(s) |
|||
} else { |
|||
var sx = "" |
|||
var i = 0 |
|||
while (n > 0) { |
|||
var p = n % 1000 |
|||
n = (n/1000).floor |
|||
if (p > 0) { |
|||
System.write("") // guards against VM recursion bug |
|||
var ix = say.call(p) + illions[i] |
|||
if (sx != "") ix = ix + " " + sx |
|||
sx = ix |
|||
} |
|||
i = i + 1 |
|||
} |
|||
t = t + sx |
|||
} |
|||
return t |
|||
} |
|||
var sayOrdinal = Fn.new { |n| |
|||
var s = say.call(n) |
|||
var r = s[-1..0] |
|||
var i1 = r.indexOf(" ") |
|||
if (i1 != -1) i1 = s.count - 1 - i1 |
|||
var i2 = r.indexOf("-") |
|||
if (i2 != -1) i2 = s.count - 1 - i2 |
|||
var i = (i1 > i2) ? i1 : i2 |
|||
i = i + 1 |
|||
// Now s[0...i] is everything up to and including the space or hyphen |
|||
// and s[i..-1] is the last word; we modify s[i..-1] as required. |
|||
// Since indexOf returns -1 if there was no space/hyphen, |
|||
// `i` will be zero and this will still be fine. |
|||
var x = irregularOrdinals[s[i..-1]] |
|||
if (x) { |
|||
return s[0...i] + x |
|||
} else if (s[-1] == "y") { |
|||
return s[0...i] + s[i..-2] + "ieth" |
|||
} else { |
|||
return s[0...i] + s[i..-1] + "th" |
|||
} |
|||
} |
|||
for (n in [1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 9007199254740991]) { |
|||
System.print(sayOrdinal.call(n)) |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
first |
|||
second |
|||
third |
|||
fourth |
|||
fifth |
|||
eleventh |
|||
sixty-fifth |
|||
one hundredth |
|||
one hundred first |
|||
two hundred seventy-second |
|||
twenty-three thousand four hundred fifty-sixth |
|||
nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-first |
|||
</pre> |
|||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
< |
<syntaxhighlight lang="zkl">fcn nth(n,th=True){ |
||
var [const] |
var [const] |
||
nmsth=T("","first","second","third","fourth","fifth","sixth","seventh","eighth","ninth"), |
nmsth=T("","first","second","third","fourth","fifth","sixth","seventh","eighth","ninth"), |
||
Line 937: | Line 2,973: | ||
} |
} |
||
} |
} |
||
fcn dash(n,d,th){ if(n) String(d,nth(n,th)) else (th and "th" or "") }</ |
fcn dash(n,d,th){ if(n) String(d,nth(n,th)) else (th and "th" or "") }</syntaxhighlight> |
||
< |
<syntaxhighlight lang="zkl">testNs:=L(1,2,3,4,5,11,65,100,101,272,23456,8007006005004003, |
||
123,00123.0,1.23e2,); |
123,00123.0,1.23e2,); |
||
foreach n in (testNs){ |
foreach n in (testNs){ |
||
if(n.isType(Float)) println("%16.2f --> %s".fmt(n,nth(n))); |
if(n.isType(Float)) println("%16.2f --> %s".fmt(n,nth(n))); |
||
else println("%16d --> %s".fmt(n,nth(n))); |
else println("%16d --> %s".fmt(n,nth(n))); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
Latest revision as of 03:31, 9 March 2024
You are encouraged to solve this task according to the task description, using any language you may know.
Ordinal numbers (as used in this Rosetta Code task), are numbers that describe the position of something in a list.
It is this context that ordinal numbers will be used, using an English-spelled name of an ordinal number.
The ordinal numbers are (at least, one form of them):
1st 2nd 3rd 4th 5th 6th 7th ··· 99th 100th ··· 1000000000th ··· etc
sometimes expressed as:
1st 2nd 3rd 4th 5th 6th 7th ··· 99th 100th ··· 1000000000th ···
For this task, the following (English-spelled form) will be used:
first second third fourth fifth sixth seventh ninety-nineth one hundredth one billionth
Furthermore, the short scale numbering system (i.e. 2,000,000,000 is two billion) will be used here. wp:Long and short scales
2,000,000,000 is two billion, not two milliard.
- Task
Write a driver and a function (subroutine/routine ···) that returns the English-spelled ordinal version of a specified number (a positive integer).
Optionally, try to support as many forms of an integer that can be expressed: 123 00123.0 1.23e2 all are forms of the same integer.
Show all output here.
- Test cases
Use (at least) the test cases of:
1 2 3 4 5 11 65 100 101 272 23456 8007006005004003
- Related tasks
ALGOL 68
Assumes LONG INT is at least 64 bits, as in e.g., Algol 68G.
BEGIN # construct number names from a number #
[]STRING units
= ( "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" );
[]STRING unit prefix
= ( "ten", "twen", "thir", "four", "fif", "six", "seven", "eigh", "nine" );
[]STRING singleth
= ( "first", "second", "third", "fourth", "fifth"
, "sixth", "seventh", "eighth", "nineth"
);
[]STRING power suffix
= ( "thousand", "million", "billion", "trillion", "quadrillion", "quintillion" );
# returns n converted to a number name, n must be 1-99 #
# if final is TRUE, the name will end in st, nd, rd, ... #
PROC two digits = ( INT n, BOOL final )STRING:
IF n < 10 THEN IF final THEN singleth[ n ] ELSE units[ n ] FI
ELIF n = 10 THEN IF final THEN "tenth" ELSE "ten" FI
ELIF n = 11 THEN IF final THEN "eleventh" ELSE "eleven" FI
ELIF n = 12 THEN IF final THEN "twelfth" ELSE "twelve" FI
ELIF n < 20 THEN unit prefix[ n - 10 ]
+ IF final THEN "teenth" ELSE "teen" FI
ELIF n MOD 10 = 0 THEN unit prefix[ n OVER 10 ]
+ IF final THEN "tieth" ELSE "ty" FI
ELSE unit prefix[ n OVER 10 ]
+ "ty "
+ IF final THEN singleth[ n MOD 10 ] ELSE units[ n MOD 10 ] FI
FI # two digits # ;
# returns n converted to a number name, n must be 1-999 #
# if final is TRUE, the name will end in st, nd, rd, ... #
PROC three digits = ( INT n, BOOL final )STRING:
IF n < 100
THEN two digits( n, final )
ELIF STRING hundreds = units[ n OVER 100 ] + " hundred";
INT ending = n MOD 100;
ending = 0
THEN IF final THEN hundreds + "th" ELSE hundreds FI
ELSE hundreds + " and " + two digits( ending, final )
FI # three digits # ;
# returns the "name" of n #
OP NAME = ( LONG INT n )STRING:
IF n < 0 THEN "minus " + NAME - n
ELIF n = 0 THEN "zeroth"
ELSE
# have a positive number to name #
LONG INT v := n;
STRING result := "";
INT power pos := 0;
WHILE v /= 0 DO
BOOL final component = power pos = 0;
INT v999 = SHORTEN ( v MOD 1000 );
IF v999 /= 0 THEN
STRING component := three digits( v999, final component );
IF power pos > 0 THEN
component +:= " " + power suffix[ power pos ];
IF final component THEN component +:= "th" FI
FI;
IF power pos = 0 AND v > 1000 AND v999 < 100 THEN
"and " +=: component
FI;
IF result /= "" THEN component +:= " " FI;
component +=: result
FI;
power pos +:= 1;
v OVERAB 1000
OD;
IF n MOD 1000 = 0 THEN result + "th" ELSE result FI
FI # NAME # ;
# additional operator to handle shorter integers #
OP NAME = ( INT n )STRING: NAME LENG n;
# additional operators to handle integers expressed in floating point #
OP NAME = ( LONG REAL n )STRING: NAME ENTIER n;
OP NAME = ( REAL n )STRING: NAME ENTIER n;
# task test cases #
[]LONG INT t = ( 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23 456, 8 007 006 005 004 003 );
FOR n FROM LWB t TO UPB t DO
print( ( whole( t[ n ], -16 ), ": ", NAME t[ n ], newline ) )
OD
END
- Output:
1: first 2: second 3: third 4: fourth 5: fifth 11: eleventh 65: sixty fifth 100: one hundredth 101: one hundred and first 272: two hundred and seventy second 23456: twenty three thousand four hundred and fifty sixth 8007006005004003: eight quadrillion seven trillion six billion five million four thousand and third
AutoHotkey
Based on Number_names
OrdinalNumber(n){
OrdinalNumber := {"one":"first", "two":"second", "three":"third", "five":"fifth", "eight":"eighth", "nine":"ninth", "twelve": "twelfth"}
RegExMatch(n, "\w+$", m)
return (OrdinalNumber[m] ? RegExReplace(n, "\w+$", OrdinalNumber[m]) : n "th")
}
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 1000+
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 100..999
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,")
}
Example:
for i, n in StrSplit("1 2 3 4 5 11 65 100 101 272 23456 8007006005004003", " ")
res .= PrettyNumber(n) "`t" Spell(n) "`t" OrdinalNumber(Spell(n)) "`n"
MsgBox % res
Outputs:
1 first 2 second 3 third 4 fourth 5 fifth 11 eleventh 65 sixty-fifth 100 one hundredth 101 one hundred and first 272 two hundred and seventy-second 23,456 twenty-three thousand , four hundred and fifty-sixth 8,007,006,005,004,003 eight quadrillion , seven trillion , six billion , five million , four thousand , third
C
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <glib.h>
typedef uint64_t integer;
typedef struct number_names_tag {
const char* cardinal;
const char* ordinal;
} number_names;
const number_names small[] = {
{ "zero", "zeroth" }, { "one", "first" }, { "two", "second" },
{ "three", "third" }, { "four", "fourth" }, { "five", "fifth" },
{ "six", "sixth" }, { "seven", "seventh" }, { "eight", "eighth" },
{ "nine", "ninth" }, { "ten", "tenth" }, { "eleven", "eleventh" },
{ "twelve", "twelfth" }, { "thirteen", "thirteenth" },
{ "fourteen", "fourteenth" }, { "fifteen", "fifteenth" },
{ "sixteen", "sixteenth" }, { "seventeen", "seventeenth" },
{ "eighteen", "eighteenth" }, { "nineteen", "nineteenth" }
};
const number_names tens[] = {
{ "twenty", "twentieth" }, { "thirty", "thirtieth" },
{ "forty", "fortieth" }, { "fifty", "fiftieth" },
{ "sixty", "sixtieth" }, { "seventy", "seventieth" },
{ "eighty", "eightieth" }, { "ninety", "ninetieth" }
};
typedef struct named_number_tag {
const char* cardinal;
const char* ordinal;
integer number;
} named_number;
const named_number named_numbers[] = {
{ "hundred", "hundredth", 100 },
{ "thousand", "thousandth", 1000 },
{ "million", "millionth", 1000000 },
{ "billion", "billionth", 1000000000 },
{ "trillion", "trillionth", 1000000000000 },
{ "quadrillion", "quadrillionth", 1000000000000000ULL },
{ "quintillion", "quintillionth", 1000000000000000000ULL }
};
const char* get_small_name(const number_names* n, bool ordinal) {
return ordinal ? n->ordinal : n->cardinal;
}
const char* get_big_name(const named_number* n, bool ordinal) {
return ordinal ? n->ordinal : n->cardinal;
}
const named_number* get_named_number(integer n) {
const size_t names_len = sizeof(named_numbers)/sizeof(named_numbers[0]);
for (size_t i = 0; i + 1 < names_len; ++i) {
if (n < named_numbers[i + 1].number)
return &named_numbers[i];
}
return &named_numbers[names_len - 1];
}
void append_number_name(GString* gstr, integer n, bool ordinal) {
if (n < 20)
g_string_append(gstr, get_small_name(&small[n], ordinal));
else if (n < 100) {
if (n % 10 == 0) {
g_string_append(gstr, get_small_name(&tens[n/10 - 2], ordinal));
} else {
g_string_append(gstr, get_small_name(&tens[n/10 - 2], false));
g_string_append_c(gstr, '-');
g_string_append(gstr, get_small_name(&small[n % 10], ordinal));
}
} else {
const named_number* num = get_named_number(n);
integer p = num->number;
append_number_name(gstr, n/p, false);
g_string_append_c(gstr, ' ');
if (n % p == 0) {
g_string_append(gstr, get_big_name(num, ordinal));
} else {
g_string_append(gstr, get_big_name(num, false));
g_string_append_c(gstr, ' ');
append_number_name(gstr, n % p, ordinal);
}
}
}
GString* number_name(integer n, bool ordinal) {
GString* result = g_string_sized_new(8);
append_number_name(result, n, ordinal);
return result;
}
void test_ordinal(integer n) {
GString* name = number_name(n, true);
printf("%llu: %s\n", n, name->str);
g_string_free(name, TRUE);
}
int main() {
test_ordinal(1);
test_ordinal(2);
test_ordinal(3);
test_ordinal(4);
test_ordinal(5);
test_ordinal(11);
test_ordinal(15);
test_ordinal(21);
test_ordinal(42);
test_ordinal(65);
test_ordinal(98);
test_ordinal(100);
test_ordinal(101);
test_ordinal(272);
test_ordinal(300);
test_ordinal(750);
test_ordinal(23456);
test_ordinal(7891233);
test_ordinal(8007006005004003LL);
return 0;
}
- Output:
1: first 2: second 3: third 4: fourth 5: fifth 11: eleventh 15: fifteenth 21: twenty-first 42: forty-second 65: sixty-fifth 98: ninety-eighth 100: one hundredth 101: one hundred first 272: two hundred seventy-second 300: three hundredth 750: seven hundred fiftieth 23456: twenty-three thousand four hundred fifty-sixth 7891233: seven million eight hundred ninety-one thousand two hundred thirty-third 8007006005004003: eight quadrillion seven trillion six billion five million four thousand third
C#
using System;
using System.Collections.Generic;
class SpellingOfOrdinalNumbers
{
private static readonly Dictionary<string, string> ordinalMap = new Dictionary<string, string>
{
{"one", "first"},
{"two", "second"},
{"three", "third"},
{"five", "fifth"},
{"eight", "eighth"},
{"nine", "ninth"},
{"twelve", "twelfth"}
};
static void Main(string[] args)
{
long[] tests = new long[] { 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003L };
foreach (long test in tests)
{
Console.WriteLine($"{test} = {ToOrdinal(test)}");
}
}
private static string ToOrdinal(long n)
{
string spelling = NumToString(n);
string[] split = spelling.Split(' ');
string last = split[split.Length - 1];
string replace;
if (last.Contains("-"))
{
string[] lastSplit = last.Split('-');
string lastWithDash = lastSplit[1];
string lastReplace;
if (ordinalMap.ContainsKey(lastWithDash))
{
lastReplace = ordinalMap[lastWithDash];
}
else if (lastWithDash.EndsWith("y"))
{
lastReplace = lastWithDash.Substring(0, lastWithDash.Length - 1) + "ieth";
}
else
{
lastReplace = lastWithDash + "th";
}
replace = lastSplit[0] + "-" + lastReplace;
}
else
{
if (ordinalMap.ContainsKey(last))
{
replace = ordinalMap[last];
}
else if (last.EndsWith("y"))
{
replace = last.Substring(0, last.Length - 1) + "ieth";
}
else
{
replace = last + "th";
}
}
split[split.Length - 1] = replace;
return string.Join(" ", split);
}
private static readonly string[] nums = new string[]
{
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
private static readonly string[] tens = new string[] { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
private static string NumToString(long n)
{
return NumToStringHelper(n);
}
private static string NumToStringHelper(long n)
{
if (n < 0)
{
return "negative " + NumToStringHelper(-n);
}
if (n <= 19)
{
return nums[n];
}
if (n <= 99)
{
return tens[n / 10] + (n % 10 > 0 ? "-" + NumToStringHelper(n % 10) : "");
}
string label = null;
long factor = 0;
if (n <= 999)
{
label = "hundred";
factor = 100;
}
else if (n <= 999999)
{
label = "thousand";
factor = 1000;
}
else if (n <= 999999999)
{
label = "million";
factor = 1000000;
}
else if (n <= 999999999999L)
{
label = "billion";
factor = 1000000000;
}
else if (n <= 999999999999999L)
{
label = "trillion";
factor = 1000000000000L;
}
else if (n <= 999999999999999999L)
{
label = "quadrillion";
factor = 1000000000000000L;
}
else
{
label = "quintillion";
factor = 1000000000000000000L;
}
return NumToStringHelper(n / factor) + " " + label + (n % factor > 0 ? " " + NumToStringHelper(n % factor) : "");
}
}
- Output:
1 = first 2 = second 3 = third 4 = fourth 5 = fifth 11 = eleventh 65 = sixty-fifth 100 = one hundredth 101 = one hundred first 272 = two hundred seventy-second 23456 = twenty-three thousand four hundred fifty-sixth 8007006005004003 = eight quadrillion seven trillion six billion five million four thousand third
C++
#include <iostream>
#include <string>
#include <cstdint>
typedef std::uint64_t integer;
struct number_names {
const char* cardinal;
const char* ordinal;
};
const number_names small[] = {
{ "zero", "zeroth" }, { "one", "first" }, { "two", "second" },
{ "three", "third" }, { "four", "fourth" }, { "five", "fifth" },
{ "six", "sixth" }, { "seven", "seventh" }, { "eight", "eighth" },
{ "nine", "ninth" }, { "ten", "tenth" }, { "eleven", "eleventh" },
{ "twelve", "twelfth" }, { "thirteen", "thirteenth" },
{ "fourteen", "fourteenth" }, { "fifteen", "fifteenth" },
{ "sixteen", "sixteenth" }, { "seventeen", "seventeenth" },
{ "eighteen", "eighteenth" }, { "nineteen", "nineteenth" }
};
const number_names tens[] = {
{ "twenty", "twentieth" }, { "thirty", "thirtieth" },
{ "forty", "fortieth" }, { "fifty", "fiftieth" },
{ "sixty", "sixtieth" }, { "seventy", "seventieth" },
{ "eighty", "eightieth" }, { "ninety", "ninetieth" }
};
struct named_number {
const char* cardinal;
const char* ordinal;
integer number;
};
const named_number named_numbers[] = {
{ "hundred", "hundredth", 100 },
{ "thousand", "thousandth", 1000 },
{ "million", "millionth", 1000000 },
{ "billion", "billionth", 1000000000 },
{ "trillion", "trillionth", 1000000000000 },
{ "quadrillion", "quadrillionth", 1000000000000000ULL },
{ "quintillion", "quintillionth", 1000000000000000000ULL }
};
const char* get_name(const number_names& n, bool ordinal) {
return ordinal ? n.ordinal : n.cardinal;
}
const char* get_name(const named_number& n, bool ordinal) {
return ordinal ? n.ordinal : n.cardinal;
}
const named_number& get_named_number(integer n) {
constexpr size_t names_len = std::size(named_numbers);
for (size_t i = 0; i + 1 < names_len; ++i) {
if (n < named_numbers[i + 1].number)
return named_numbers[i];
}
return named_numbers[names_len - 1];
}
std::string number_name(integer n, bool ordinal) {
std::string result;
if (n < 20)
result = get_name(small[n], ordinal);
else if (n < 100) {
if (n % 10 == 0) {
result = get_name(tens[n/10 - 2], ordinal);
} else {
result = get_name(tens[n/10 - 2], false);
result += "-";
result += get_name(small[n % 10], ordinal);
}
} else {
const named_number& num = get_named_number(n);
integer p = num.number;
result = number_name(n/p, false);
result += " ";
if (n % p == 0) {
result += get_name(num, ordinal);
} else {
result += get_name(num, false);
result += " ";
result += number_name(n % p, ordinal);
}
}
return result;
}
void test_ordinal(integer n) {
std::cout << n << ": " << number_name(n, true) << '\n';
}
int main() {
test_ordinal(1);
test_ordinal(2);
test_ordinal(3);
test_ordinal(4);
test_ordinal(5);
test_ordinal(11);
test_ordinal(15);
test_ordinal(21);
test_ordinal(42);
test_ordinal(65);
test_ordinal(98);
test_ordinal(100);
test_ordinal(101);
test_ordinal(272);
test_ordinal(300);
test_ordinal(750);
test_ordinal(23456);
test_ordinal(7891233);
test_ordinal(8007006005004003LL);
return 0;
}
- Output:
1: first 2: second 3: third 4: fourth 5: fifth 11: eleventh 15: fifteenth 21: twenty-first 42: forty-second 65: sixty-fifth 98: ninety-eighth 100: one hundredth 101: one hundred first 272: two hundred seventy-second 300: three hundredth 750: seven hundred fiftieth 23456: twenty-three thousand four hundred fifty-sixth 7891233: seven million eight hundred ninety-one thousand two hundred thirty-third 8007006005004003: eight quadrillion seven trillion six billion five million four thousand third
Clojure
(def test-cases [1 2 3 4 5 11 65 100 101 272 23456 8007006005004003])
(pprint
(sort (zipmap test-cases (map #(clojure.pprint/cl-format nil "~:R" %) test-cases))))
- Output:
([1 "first"] [2 "second"] [3 "third"] [4 "fourth"] [5 "fifth"] [11 "eleventh"] [65 "sixty-fifth"] [100 "one hundredth"] [101 "one hundred first"] [272 "two hundred seventy-second"] [23456 "twenty-three thousand, four hundred fifty-sixth"] [8007006005004003 "eight quadrillion, seven trillion, six billion, five million, four thousand, third"])
Common Lisp
Common Lisp's format is able to do this directly. Here's a short function wrapping it and a demonstration.
(defun ordinal-number (n)
(format nil "~:R" n))
#|
CL-USER> (loop for i in '(1 2 3 4 5 11 65 100 101 272 23456 8007006005004003)
do (format t "~a: ~a~%" i (ordinal-number i)))
1: first
2: second
3: third
4: fourth
5: fifth
11: eleventh
65: sixty-fifth
100: one hundredth
101: one hundred first
272: two hundred seventy-second
23456: twenty-three thousand four hundred fifty-sixth
8007006005004003: eight quadrillion seven trillion six billion five million four thousand third
NIL
|#
Factor
Factor's math.text.english
vocabulary provides the number>text
word for converting numbers to written English. It also provides the ordinal-suffix
word for getting the suffix for a given number, such as th for 12. The bulk of this code deals with converting the output of number>text
to ordinal format.
USING: assocs formatting grouping kernel literals locals math
math.parser math.text.english qw regexp sequences
splitting.extras ;
IN: rosetta-code.spelling-ordinal-numbers
<PRIVATE
! Factor supports the arbitrary use of commas in integer
! literals, as some number systems (e.g. Indian) don't solely
! break numbers up into triplets.
CONSTANT: test-cases qw{
1 2 3 4 5 11 65 100 101 272 23456 8007006005004003 123
00123.0 1.23e2 1,2,3 0b1111011 0o173 0x7B 2706/22
}
CONSTANT: replacements $[
qw{
one first
two second
three third
five fifth
eight eighth
nine ninth
twelve twelfth
} 2 group
]
: regular-ordinal ( n -- str )
[ number>text ] [ ordinal-suffix ] bi append ;
! Since Factor's number>text word contains commas and "and",
! strip them out with a regular expression.
: text>ordinal-text ( str -- str' ) R/ \sand|,/ "" re-replace ;
PRIVATE>
:: number>ordinal-text ( n! -- str )
n >integer n!
n number>text " ,-" split* dup last replacements at
[ [ but-last ] dip suffix "" join ]
[ drop n regular-ordinal ] if* text>ordinal-text ;
<PRIVATE
: print-ordinal-pair ( str x -- )
number>ordinal-text "%16s => %s\n" printf ;
PRIVATE>
: ordinal-text-demo ( -- )
test-cases [ dup string>number print-ordinal-pair ] each
"C{ 123 0 }" C{ 123 0 } print-ordinal-pair ;
MAIN: ordinal-text-demo
- Output:
1 => first 2 => second 3 => third 4 => fourth 5 => fifth 11 => eleventh 65 => sixty-fifth 100 => one hundredth 101 => one hundred first 272 => two hundred seventy-second 23456 => twenty-three thousand four hundred fifty-sixth 8007006005004003 => eight quadrillion seven trillion six billion five million four thousand third 123 => one hundred twenty-third 00123.0 => one hundred twenty-third 1.23e2 => one hundred twenty-third 1,2,3 => one hundred twenty-third 0b1111011 => one hundred twenty-third 0o173 => one hundred twenty-third 0x7B => one hundred twenty-third 2706/22 => one hundred twenty-third C{ 123 0 } => one hundred twenty-third
FreeBASIC
Dim Shared small(19) As String*9 => { _
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", _
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", _
"sixteen", "seventeen", "eighteen", "nineteen" }
Dim Shared tens(9) As String*7 => { "", "", _
"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }
Dim Shared illions(6) As String*12 => {"", _
" thousand", " million", " billion"," trillion", " quadrillion", " quintillion" }
Dim Shared irregularOrdinals(7, 1) As String*7 = { _
{"one", "first"}, {"two", "second"}, {"three", "third"}, {"five", "fifth"}, _
{"eight", "eighth"}, {"nine", "ninth"}, {"twelve", "twelfth"} }
Function spell(n As Integer) As String
Dim As String sx, ix, t = ""
Dim As Integer s, i, p
If n < 0 Then
t = "negative "
n = -n
End If
If n < 20 Then
t &= small(n)
Elseif n < 100 Then
t &= tens(n \ 10)
s = n Mod 10
If s > 0 Then t &= "-" & small(s)
Elseif n < 1000 Then
t &= small(n \ 100) & " hundred"
s = n Mod 100
If s > 0 Then t &= " " & spell(s)
Else
sx = ""
i = 0
While n > 0
p = n Mod 1000
n \= 1000
If p > 0 Then
ix = spell(p) & illions(i)
If sx <> "" Then ix &= " " & sx
sx = ix
End If
i += 1
Wend
t &= sx
End If
Return t
End Function
Function sayOrdinal(n As Integer) As String
Dim As String s = spell(n)
Dim As String lastWord = ""
Dim As Integer j, i = Len(s)
While i > 0 And Mid(s, i, 1) <> " " And Mid(s, i, 1) <> "-"
lastWord = Mid(s, i, 1) + lastWord
i -= 1
Wend
For j = 0 To Ubound(irregularOrdinals, 1)
If irregularOrdinals(j, 0) = lastWord Then
Return Left(s, i) + irregularOrdinals(j, 1)
End If
Next j
If Right(s, 1) = "y" Then
Return Left(s, Len(s) - 1) + "ieth"
Else
Return s + "th"
End If
End Function
Dim As Integer t(0 To ...) = { 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, _
23456, 8007006005004003, 123, 00123.0, 1.23E2 }
For n As Integer = 0 To Ubound(t)
Print sayOrdinal(t(n))
Next n
Sleep
- Output:
first second third fourth fifth eleventh sixty-fifth one hundredth one hundred first two hundred seventy-second twenty-three thousand four hundred fifty-sixth eight quadrillion seven trillion six billion five million four thousand third one hundred twenty-third one hundred twenty-third one hundred twenty-third
Go
As with the Kotlin solution, this uses the output of say
from the
Number_names task.
import (
"fmt"
"strings"
)
func main() {
for _, n := range []int64{
1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003,
} {
fmt.Println(sayOrdinal(n))
}
}
var irregularOrdinals = map[string]string{
"one": "first",
"two": "second",
"three": "third",
"five": "fifth",
"eight": "eighth",
"nine": "ninth",
"twelve": "twelfth",
}
func sayOrdinal(n int64) string {
s := say(n)
i := strings.LastIndexAny(s, " -")
i++
// Now s[:i] is everything upto and including the space or hyphen
// and s[i:] is the last word; we modify s[i:] as required.
// Since LastIndex returns -1 if there was no space/hyphen,
// `i` will be zero and this will still be fine.
if x, ok := irregularOrdinals[s[i:]]; ok {
s = s[:i] + x
} else if s[len(s)-1] == 'y' {
s = s[:i] + s[i:len(s)-1] + "ieth"
} else {
s = s[:i] + s[i:] + "th"
}
return s
}
// Below is a copy of https://rosettacode.org/wiki/Number_names#Go
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
}
- Output:
first second third fourth fifth eleventh sixty-fifth one hundredth one hundred first two hundred seventy-second twenty-three thousand four hundred fifty-sixth eight quadrillion seven trillion six billion five million four thousand third
Haskell
Uses solution of Number_names#Haskell
spellOrdinal :: Integer -> String
spellOrdinal n
| n <= 0 = "not ordinal"
| n < 20 = small n
| n < 100 = case divMod n 10 of
(k, 0) -> spellInteger (10*k) ++ "th"
(k, m) -> spellInteger (10*k) ++ "-" ++ spellOrdinal m
| n < 1000 = case divMod n 100 of
(k, 0) -> spellInteger (100*k) ++ "th"
(k, m) -> spellInteger (100*k) ++ " and " ++ spellOrdinal m
| otherwise = case divMod n 1000 of
(k, 0) -> spellInteger (1000*k) ++ "th"
(k, m) -> spellInteger (k*1000) ++ s ++ spellOrdinal m
where s = if m < 100 then " and " else ", "
where
small = ([ undefined, "first", "second", "third", "fourth", "fifth"
, "sixth", "seventh", "eighth", "nineth", "tenth", "eleventh"
, "twelveth", "thirteenth", "fourteenth", "fifteenth", "sixteenth"
, "seventeenth", "eighteenth", "nineteenth"] !!) . fromEnum
Testing
main = mapM_ (\n -> putStrLn $ show n ++ "\t" ++ spellOrdinal n)
[1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003]
λ> main 1 first 2 second 3 third 4 fourth 5 fifth 11 eleventh 65 sixty-fifth 100 one hundredth 101 one hundred and first 272 two hundred and seventy-second 23456 twenty-three thousand, four hundred and fifty-sixth 8007006005004003 eight quadrillion, seven trillion, six billion, five million, four thousand and third
J
Here, we follow J's best practice for ordinal numbers, which is that 0 is first and 1 is second. This emphasizes the distinction between cardinal numbers like 0 and ordinal numbers like first, accurately represents array indices, and neatly captures a variety of related linguistic issues.
Also, we use definitions from the number names task and the N'th task:
ord=: {{
((us,suf)1+y) rplc ;:{{)n onest first twond second
threerd third fiveth fifth eightth eighth
}}-.LF
}}
Examples:
ord 0
first
ord 1
second
ord 2
third
ord 3
fourth
ord 4
fifth
ord 5
sixth
ord 11
twelveth
ord 65
sixty-sixth
ord 100
one hundred first
ord 101
one hundred second
ord 272
two hundred seventy-third
ord 23456
twenty-three thousand four hundred fifty-seventh
ord 8007006005004003
eight quadrillion seven trillion six billion five million four thousand fourth
ord 123
one hundred twenty-fourth
ord 00123.0
one hundred twenty-fourth
ord 1.23e2
one hundred twenty-fourth
Java
import java.util.HashMap;
import java.util.Map;
public class SpellingOfOrdinalNumbers {
public static void main(String[] args) {
for ( long test : new long[] {1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003L} ) {
System.out.printf("%d = %s%n", test, toOrdinal(test));
}
}
private static Map<String,String> ordinalMap = new HashMap<>();
static {
ordinalMap.put("one", "first");
ordinalMap.put("two", "second");
ordinalMap.put("three", "third");
ordinalMap.put("five", "fifth");
ordinalMap.put("eight", "eighth");
ordinalMap.put("nine", "ninth");
ordinalMap.put("twelve", "twelfth");
}
private static String toOrdinal(long n) {
String spelling = numToString(n);
String[] split = spelling.split(" ");
String last = split[split.length - 1];
String replace = "";
if ( last.contains("-") ) {
String[] lastSplit = last.split("-");
String lastWithDash = lastSplit[1];
String lastReplace = "";
if ( ordinalMap.containsKey(lastWithDash) ) {
lastReplace = ordinalMap.get(lastWithDash);
}
else if ( lastWithDash.endsWith("y") ) {
lastReplace = lastWithDash.substring(0, lastWithDash.length() - 1) + "ieth";
}
else {
lastReplace = lastWithDash + "th";
}
replace = lastSplit[0] + "-" + lastReplace;
}
else {
if ( ordinalMap.containsKey(last) ) {
replace = ordinalMap.get(last);
}
else if ( last.endsWith("y") ) {
replace = last.substring(0, last.length() - 1) + "ieth";
}
else {
replace = last + "th";
}
}
split[split.length - 1] = replace;
return String.join(" ", split);
}
private static final String[] nums = new String[] {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
private static final String[] tens = new String[] {"zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
private static final String numToString(long n) {
return numToStringHelper(n);
}
private static final String numToStringHelper(long n) {
if ( n < 0 ) {
return "negative " + numToStringHelper(-n);
}
int index = (int) n;
if ( n <= 19 ) {
return nums[index];
}
if ( n <= 99 ) {
return tens[index/10] + (n % 10 > 0 ? "-" + numToStringHelper(n % 10) : "");
}
String label = null;
long factor = 0;
if ( n <= 999 ) {
label = "hundred";
factor = 100;
}
else if ( n <= 999999) {
label = "thousand";
factor = 1000;
}
else if ( n <= 999999999) {
label = "million";
factor = 1000000;
}
else if ( n <= 999999999999L) {
label = "billion";
factor = 1000000000;
}
else if ( n <= 999999999999999L) {
label = "trillion";
factor = 1000000000000L;
}
else if ( n <= 999999999999999999L) {
label = "quadrillion";
factor = 1000000000000000L;
}
else {
label = "quintillion";
factor = 1000000000000000000L;
}
return numToStringHelper(n / factor) + " " + label + (n % factor > 0 ? " " + numToStringHelper(n % factor ) : "");
}
}
- Output:
1 = first 2 = second 3 = third 4 = fourth 5 = fifth 11 = eleventh 65 = sixty-fifth 100 = one hundredth 101 = one hundred first 272 = two hundred seventy-second 23456 = twenty-three thousand four hundred fifty-sixth 8007006005004003 = eight quadrillion seven trillion six billion five million four thousand third
jq
Adapted from Wren
Also works with gojq and fq, the Go implementations
One point of interest in the following is that the program checks not only that its integer input is within the scope of the program, but also that it is within the capability of the C or Go platform. In particular, `check_ok` checks for the platform's precision of integer arithmetic.
For further remarks on this point, see the comments that are included in the test data.
# integer division for precision when using gojq
def idivide($j):
. as $i
| ($i % $j) as $mod
| ($i - $mod) / $j ;
def lpad($len): tostring | ($len - length) as $l | (" " * $l)[:$l] + .;
def small:
["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"];
# Up to 1e63 (vigintillion)
def illions:
["", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion",
" sextillion", " septillion", " octillion", " nonillion", " decillion", " undecillion",
" duodecillion", " tredecillion", " quattuordecillion", " quindecillion",
" sexdecillion", " septendecillion", " octadecillion", " novemdecillion",
" vigintillion"
];
def illions($i):
if $i >= (illions|length) then "\($i * 3) zeros is beyond the scope of this exercise" | error
else illions[$i]
end;
def irregularOrdinals: {
"one": "first",
"two": "second",
"three": "third",
"five": "fifth",
"eight": "eighth",
"nine": "ninth",
"twelve": "twelfth"
};
def check_ok:
def ieee754:
9007199254740993==9007199254740992;
if ieee754
then if (. > 0 and (. + 1) == .) or (. < 0 and (. - 1) == .)
then "The number \(.) is too large for this platform" | error
else .
end
else .
end;
# error courtesy of illions/1 if order of magnitude is too large
def say:
check_ok
| { t: "", n: .}
| if .n < 0 then .t = "negative " | .n *= -1 else . end
| if .n < 20
then .t += small[.n]
elif .n < 100
then .t += tens[.n | idivide(10)]
| .s = .n % 10
| if .s > 0 then .t += "-" + small[.s] else . end
elif .n < 1000
then .t += small[.n | idivide(100)] + " hundred"
| .s = .n % 100
| if .s > 0 then .t += " " + (.s|say) else . end
else .sx = ""
| .i = 0
| until (.n <= 0;
.p = .n % 1000
| .n = (.n | idivide(1000))
| if .p > 0
then .ix = (.p|say) + illions(.i)
| if .sx != "" then .ix += " " + .sx else . end
| .sx = .ix
else .
end
| .i += 1 )
| .t += .sx
end
| .t ;
def sayOrdinal:
{n: ., s: say}
| .r = (.s | explode | reverse | implode)
| .i1 = (.r|index(" "))
| if .i1 then .i1 = (.s|length) - 1 - .i1 else . end
| .i2 = (.r|index("-"))
| if .i2 then .i2 = (.s|length) - 1 - .i2 else . end
# Set .i to 0 iff there was no space or hyphen:
| .i = (if .i1 or .i2 then 1 + ([.i1,.i2] | max) else 0 end)
# Now s[.i:] is the last word:
| irregularOrdinals[.s[.i:]] as $x
| if $x then .s[:.i] + $x
elif .s | endswith("y")
then .s[:-1] + "ieth"
else .s + "th"
end;
# Sample inputs
(1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456,
8007006005004003,
9007199254740991,
2e12,
9007199254740993, # too large for jq
# 1e63 is vigintillion so gojq should be able to handle 999 * 1e63
999000000000000000000000000000000000000000000000000000000000000000,
# ... but not 1000 vigintillion
1000000000000000000000000000000000000000000000000000000000000000000
)
| "\(lpad(10)) => \(sayOrdinal)"
- Output:
The output using gojq is shown first. The tail of the output using jq is then shown to illustrate what happens when the program determines the given integer is too large for jq's built-in support for integer arithmetic.
Using gojq
1 => first 2 => second 3 => third 4 => fourth 5 => fifth 11 => eleventh 65 => sixty-fifth 100 => one hundredth 101 => one hundred first 272 => two hundred seventy-second 23456 => twenty-three thousand four hundred fifty-sixth 8007006005004003 => eight quadrillion seven trillion six billion five million four thousand third 9007199254740991 => nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-first 2000000000000 => two trillionth 9007199254740993 => nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-third 999000000000000000000000000000000000000000000000000000000000000000 => nine hundred ninety-nine vigintillionth gojq: error: 66 zeros is beyond the scope of this exercise
Tail of output using the C implementation
2000000000000 => two trillionth jq: error (at <unknown>): The number 9007199254740992 is too large for this platform
Julia
This makes use of code posted on this site by MichaeLeroy for a similar task at Number_names#Julia. The function num2text is used (but not included here) as posted from that location.
const irregular = Dict("one" => "first", "two" => "second", "three" => "third", "five" => "fifth",
"eight" => "eighth", "nine" => "ninth", "twelve" => "twelfth")
const suffix = "th"
const ysuffix = "ieth"
function numtext2ordinal(s)
lastword = split(s)[end]
redolast = split(lastword, "-")[end]
if redolast != lastword
lastsplit = "-"
word = redolast
else
lastsplit = " "
word = lastword
end
firstpart = reverse(split(reverse(s), lastsplit, limit=2)[end])
firstpart = (firstpart == word) ? "": firstpart * lastsplit
if haskey(irregular, word)
word = irregular[word]
elseif word[end] == 'y'
word = word[1:end-1] * ysuffix
else
word = word * suffix
end
firstpart * word
end
const testcases = [1 2 3 4 5 11 65 100 101 272 23456 8007006005004003]
for n in testcases
println("$n => $(numtext2ordinal(num2text(n)))")
end
- Output:
1 => first 2 => second 3 => third 4 => fourth 5 => fifth 11 => eleventh 65 => sixty-fifth 100 => one hundredth 101 => one hundred and first 272 => two hundred and seventy-second 23456 => twenty-three thousand four hundred and fifty-sixth 8007006005004003 => eight quadrillion seven trillion six billion five million four thousand and third
Kotlin
This makes use of the code at https://rosettacode.org/wiki/Number_names#Kotlin, which I also wrote, and adjusts it to output the corresponding ordinal. Although, for good measure, the program can deal with negative integers, zero and UK-style numbers (the insertion of 'and' at strategic places, no 'milliards' I promise!) none of these are actually tested in line with the task's requirements.
// version 1.1.4-3
typealias IAE = IllegalArgumentException
val names = mapOf(
1 to "one",
2 to "two",
3 to "three",
4 to "four",
5 to "five",
6 to "six",
7 to "seven",
8 to "eight",
9 to "nine",
10 to "ten",
11 to "eleven",
12 to "twelve",
13 to "thirteen",
14 to "fourteen",
15 to "fifteen",
16 to "sixteen",
17 to "seventeen",
18 to "eighteen",
19 to "nineteen",
20 to "twenty",
30 to "thirty",
40 to "forty",
50 to "fifty",
60 to "sixty",
70 to "seventy",
80 to "eighty",
90 to "ninety"
)
val bigNames = mapOf(
1_000L to "thousand",
1_000_000L to "million",
1_000_000_000L to "billion",
1_000_000_000_000L to "trillion",
1_000_000_000_000_000L to "quadrillion",
1_000_000_000_000_000_000L to "quintillion"
)
val irregOrdinals = mapOf(
"one" to "first",
"two" to "second",
"three" to "third",
"five" to "fifth",
"eight" to "eighth",
"nine" to "ninth",
"twelve" to "twelfth"
)
fun String.toOrdinal(): String {
val splits = this.split(' ', '-')
var last = splits[splits.lastIndex]
return if (irregOrdinals.containsKey(last)) this.dropLast(last.length) + irregOrdinals[last]!!
else if (last.endsWith("y")) this.dropLast(1) + "ieth"
else this + "th"
}
fun numToOrdinalText(n: Long, uk: Boolean = false): String {
if (n == 0L) return "zeroth" // or alternatively 'zeroeth'
val neg = n < 0L
val maxNeg = n == Long.MIN_VALUE
var nn = if (maxNeg) -(n + 1) else if (neg) -n else n
val digits3 = IntArray(7)
for (i in 0..6) { // split number into groups of 3 digits from the right
digits3[i] = (nn % 1000).toInt()
nn /= 1000
}
fun threeDigitsToText(number: Int) : String {
val sb = StringBuilder()
if (number == 0) return ""
val hundreds = number / 100
val remainder = number % 100
if (hundreds > 0) {
sb.append(names[hundreds], " hundred")
if (remainder > 0) sb.append(if (uk) " and " else " ")
}
if (remainder > 0) {
val tens = remainder / 10
val units = remainder % 10
if (tens > 1) {
sb.append(names[tens * 10])
if (units > 0) sb.append("-", names[units])
}
else sb.append(names[remainder])
}
return sb.toString()
}
val strings = Array<String>(7) { threeDigitsToText(digits3[it]) }
var text = strings[0]
var andNeeded = uk && digits3[0] in 1..99
var big = 1000L
for (i in 1..6) {
if (digits3[i] > 0) {
var text2 = strings[i] + " " + bigNames[big]
if (text.length > 0) {
text2 += if (andNeeded) " and " else ", "
andNeeded = false
}
else andNeeded = uk && digits3[i] in 1..99
text = text2 + text
}
big *= 1000
}
if (maxNeg) text = text.dropLast(5) + "eight"
if (neg) text = "minus " + text
return text.toOrdinal()
}
fun numToOrdinalText(s: String, uk: Boolean = false): String {
val d = s.toDoubleOrNull() ?: throw IAE("String is not numeric")
if (d !in Long.MIN_VALUE.toDouble() .. Long.MAX_VALUE.toDouble())
throw IAE("Double is outside the range of a Long Integer")
val n = d.toLong()
if (n.toDouble() != d) throw IAE("String does not represent a Long Integer")
return numToOrdinalText(n, uk)
}
fun main(args: Array<String>) {
val la = longArrayOf(1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003)
println("Using US representation:")
for (i in la) println("${"%16d".format(i)} = ${numToOrdinalText(i)}")
val sa = arrayOf("123", "00123.0", "1.23e2")
for (s in sa) println("${"%16s".format(s)} = ${numToOrdinalText(s)}")
}
- Output:
Using US representation: 1 = first 2 = second 3 = third 4 = fourth 5 = fifth 11 = eleventh 65 = sixty-fifth 100 = one hundredth 101 = one hundred first 272 = two hundred seventy-second 23456 = twenty-three thousand, four hundred fifty-sixth 8007006005004003 = eight quadrillion, seven trillion, six billion, five million, four thousand, third 123 = one hundred twenty-third 00123.0 = one hundred twenty-third 1.23e2 = one hundred twenty-third
Nim
As in the Python solution, we reuse the output of spellInteger
from the
Number_names task.
import strutils, algorithm, tables
const irregularOrdinals = {"one": "first",
"two": "second",
"three": "third",
"five": "fifth",
"eight": "eighth",
"nine": "ninth",
"twelve": "twelfth"}.toTable
const
tens = ["", "", "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"]
huge = ["", "", "million", "billion", "trillion", "quadrillion",
"quintillion", "sextillion", "septillion", "octillion", "nonillion",
"decillion"]
# Forward reference.
proc spellInteger(n: int64): string
proc nonzero(c: string; n: int64; connect = ""): string =
if n == 0: "" else: connect & c & spellInteger(n)
proc lastAnd(num: string): string =
if ',' in num:
let pos = num.rfind(',')
var (pre, last) = if pos >= 0: (num[0 ..< pos], num[pos+1 .. num.high])
else: ("", num)
if " and " notin last: last = " and" & last
result = [pre, ",", last].join()
else:
result = num
proc big(e, n: int64): string =
if e == 0:
spellInteger(n)
elif e == 1:
spellInteger(n) & " thousand"
else:
spellInteger(n) & " " & huge[e]
iterator base1000Rev(n: int64): int64 =
var n = n
while n != 0:
let r = n mod 1000
n = n div 1000
yield r
proc spellInteger(n: int64): string =
if n < 0:
"minus " & spellInteger(-n)
elif n < 20:
small[int(n)]
elif n < 100:
let a = n div 10
let b = n mod 10
tens[int(a)] & nonzero("-", b)
elif n < 1000:
let a = n div 100
let b = n mod 100
small[int(a)] & " hundred" & nonzero(" ", b, " and")
else:
var sq = newSeq[string]()
var e = 0
for x in base1000Rev(n):
if x > 0: sq.add big(e, x)
inc e
reverse sq
lastAnd(sq.join(", "))
proc num2ordinal(n: SomeInteger|SomeFloat): string =
let n = n.int64
var num = spellInteger(n)
let hyphen = num.rsplit('-', 1)
var number = num.rsplit(' ', 1)
var delim = ' '
if number[^1].len > hyphen[^1].len:
number = hyphen
delim = '-'
if number[^1] in irregularOrdinals:
number[^1] = delim & irregularOrdinals[number[^1]]
elif number[^1].endswith('y'):
number[^1] = delim & number[^1][0..^2] & "ieth"
else:
number[^1] = delim & number[^1] & "th"
result = number.join()
when isMainModule:
const
tests1 = [int64 1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003, 123]
tests2 = [0123.0, 1.23e2]
for num in tests1:
echo "$1 => $2".format(num, num2ordinal(num))
for num in tests2:
echo "$1 => $2".format(num, num2ordinal(num))
- Output:
1 => first 2 => second 3 => third 4 => fourth 5 => fifth 11 => eleventh 65 => sixty-fifth 100 => one hundredth 101 => one hundred and first 272 => two hundred and seventy-second 23456 => twenty-three thousand, four hundred and fifty-sixth 8007006005004003 => eight quadrillion, seven trillion, six billion, five million, four thousand, and third 123 => one hundred and twenty-third 123.0 => one hundred and twenty-third 123.0 => one hundred and twenty-third
Perl
Adding zero to the input forces a numeric conversion (any identity operation would suffice).
use Lingua::EN::Numbers 'num2en_ordinal';
printf "%16s : %s\n", $_, num2en_ordinal(0+$_) for
<1 2 3 4 5 11 65 100 101 272 23456 8007006005004003 123 00123.0 '00123.0' 1.23e2 '1.23e2'>;
- Output:
1 : first 2 : second 3 : third 4 : fourth 5 : fifth 11 : eleventh 65 : sixty-fifth 100 : one hundredth 101 : one hundred and first 272 : two hundred and seventy-second 23456 : twenty-three thousand four hundred and fifty-sixth 8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand and third 123 : one hundred and twenty-third 00123.0 : one hundred and twenty-third 00123.0 : one hundred and twenty-third 1.23e2 : one hundred and twenty-third 1.23e2 : one hundred and twenty-third
Phix
Standard builtin
constant tests = {1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003, 123, 00123.0, 1.23e2, 0b1111011, 0o173, 0x7B, 861/7} for i=1 to length(tests) do puts(1,ordinal(tests[i])&'\n') end for
- Output:
first second third fourth fifth eleventh sixty-fifth one hundredth one hundred and first two hundred and seventy-second twenty-three thousand, four hundred and fifty-sixth eight quadrillion, seven trillion, six billion, five million, four thousand, and third one hundred and twenty-third one hundred and twenty-third one hundred and twenty-third one hundred and twenty-third one hundred and twenty-third one hundred and twenty-third one hundred and twenty-third
Prolog
test_ordinal(Number):-
number_name(Number, ordinal, Name),
writef('%w: %w\n', [Number, Name]).
main:-
test_ordinal(1),
test_ordinal(2),
test_ordinal(3),
test_ordinal(4),
test_ordinal(5),
test_ordinal(11),
test_ordinal(15),
test_ordinal(21),
test_ordinal(42),
test_ordinal(65),
test_ordinal(98),
test_ordinal(100),
test_ordinal(101),
test_ordinal(272),
test_ordinal(300),
test_ordinal(750),
test_ordinal(23456),
test_ordinal(7891233),
test_ordinal(8007006005004003).
Module for spelling numbers in US English:
:- module(number_name, [number_name/3]).
small_name(0, zero, zeroth).
small_name(1, one, first).
small_name(2, two, second).
small_name(3, three, third).
small_name(4, four, fourth).
small_name(5, five, fifth).
small_name(6, six, sixth).
small_name(7, seven, seventh).
small_name(8, eight, eighth).
small_name(9, nine, ninth).
small_name(10, ten, tenth).
small_name(11, eleven, eleventh).
small_name(12, tewlve, twelfth).
small_name(13, thirteen, thirteenth).
small_name(14, fourteen, fourteenth).
small_name(15, fifteen, fifteenth).
small_name(16, sixteen, sixteenth).
small_name(17, seventeen, seventeenth).
small_name(18, eighteen, eighteenth).
small_name(19, nineteen, nineteenth).
small_name(20, twenty, twentieth).
small_name(30, thirty, thirtieth).
small_name(40, forty, fortieth).
small_name(50, fifty, fiftieth).
small_name(60, sixty, sixtieth).
small_name(70, seventy, seventieth).
small_name(80, eighty, eightieth).
small_name(90, ninety, ninetieth).
big_names([big(100, hundred, hundredth),
big(1000, thousand, thousandth),
big(1000000, million, millionth),
big(1000000000, billion, billionth),
big(1000000000000, trillion, trillionth),
big(1000000000000000, quadrillion, quadrillionth),
big(1000000000000000000, quintillion, quintillionth),
big(1000000000000000000000, sextillion, sextillionth),
big(1000000000000000000000000, septillion, septillionth)]).
big_name(Number, Big):-
big_names(Names),
big_name(Names, Number, Big).
big_name([Big], _, Big):-
!.
big_name([Big1, Big2|_], Number, Big1):-
Big2 = big(N2, _, _),
Number < N2,
!.
big_name([_|Names], Number, Big):-
big_name(Names, Number, Big).
get_big_name(big(_, C, _), cardinal, C).
get_big_name(big(_, _, O), ordinal, O).
get_small_name(Number, cardinal, Name):-
small_name(Number, Name, _),
!.
get_small_name(Number, ordinal, Name):-
small_name(Number, _, Name).
number_name(Number, Type, Name):-
Number < 20,
!,
get_small_name(Number, Type, Name).
number_name(Number, Type, Name):-
Number < 100,
!,
N is Number mod 10,
(N = 0 ->
get_small_name(Number, Type, Name)
;
N1 is Number - N,
get_small_name(N1, cardinal, Name1),
get_small_name(N, Type, Name2),
atomic_list_concat([Name1, '-', Name2], Name)
).
number_name(Number, Type, Name):-
big_name(Number, big(P, C, O)),
N is Number // P,
number_name(N, cardinal, Name1),
M is Number mod P,
(M = 0 ->
get_big_name(big(P, C, O), Type, Name2)
;
number_name(M, Type, Name3),
atomic_list_concat([C, ' ', Name3], Name2)
),
atomic_list_concat([Name1, ' ', Name2], Name).
- Output:
1: first 2: second 3: third 4: fourth 5: fifth 11: eleventh 15: fifteenth 21: twenty-first 42: forty-second 65: sixty-fifth 98: ninety-eighth 100: one hundredth 101: one hundred first 272: two hundred seventy-second 300: three hundredth 750: seven hundred fiftieth 23456: twenty-three thousand four hundred fifty-sixth 7891233: seven million eight hundred ninety-one thousand two hundred thirty-third 8007006005004003: eight quadrillion seven trillion six billion five million four thousand third
Python
As with the Go solution, this uses the output of spell_integer
from the
Number_names task.
irregularOrdinals = {
"one": "first",
"two": "second",
"three": "third",
"five": "fifth",
"eight": "eighth",
"nine": "ninth",
"twelve": "twelfth",
}
def num2ordinal(n):
conversion = int(float(n))
num = spell_integer(conversion)
hyphen = num.rsplit("-", 1)
num = num.rsplit(" ", 1)
delim = " "
if len(num[-1]) > len(hyphen[-1]):
num = hyphen
delim = "-"
if num[-1] in irregularOrdinals:
num[-1] = delim + irregularOrdinals[num[-1]]
elif num[-1].endswith("y"):
num[-1] = delim + num[-1][:-1] + "ieth"
else:
num[-1] = delim + num[-1] + "th"
return "".join(num)
if __name__ == "__main__":
tests = "1 2 3 4 5 11 65 100 101 272 23456 8007006005004003 123 00123.0 1.23e2".split()
for num in tests:
print("{} => {}".format(num, num2ordinal(num)))
#This is a copy of the code from https://rosettacode.org/wiki/Number_names#Python
TENS = [None, None, "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"]
HUGE = [None, None] + [h + "illion"
for h in ("m", "b", "tr", "quadr", "quint", "sext",
"sept", "oct", "non", "dec")]
def nonzero(c, n, connect=''):
return "" if n == 0 else connect + c + spell_integer(n)
def last_and(num):
if ',' in num:
pre, last = num.rsplit(',', 1)
if ' and ' not in last:
last = ' and' + last
num = ''.join([pre, ',', last])
return num
def big(e, n):
if e == 0:
return spell_integer(n)
elif e == 1:
return spell_integer(n) + " thousand"
else:
return spell_integer(n) + " " + HUGE[e]
def base1000_rev(n):
# generates the value of the digits of n in base 1000
# (i.e. 3-digit chunks), in reverse.
while n != 0:
n, r = divmod(n, 1000)
yield r
def spell_integer(n):
if n < 0:
return "minus " + spell_integer(-n)
elif n < 20:
return SMALL[n]
elif n < 100:
a, b = divmod(n, 10)
return TENS[a] + nonzero("-", b)
elif n < 1000:
a, b = divmod(n, 100)
return SMALL[a] + " hundred" + nonzero(" ", b, ' and')
else:
num = ", ".join([big(e, x) for e, x in
enumerate(base1000_rev(n)) if x][::-1])
return last_and(num)
Output
1 => first 2 => second 3 => third 4 => fourth 5 => fifth 11 => eleventh 65 => sixty-fifth 100 => one hundredth 101 => one hundred and first 272 => two hundred and seventy-second 23456 => twenty-three thousand, four hundred and fifty-sixth 8007006005004003 => eight quadrillion, seven trillion, six billion, five million, four thousand, and third 123 => one hundred and twenty-third 00123.0 => one hundred and twenty-third 1.23e2 => one hundred and twenty-third
Quackery
name$
is defined at Number names#Quackery.
switch
, case
, and otherwise
are defined at Metaprogramming#Quackery.
[ name$
dup -2 split nip
[ switch
$ "ne" case
[ -3 split drop
$ "first" join ]
$ "wo" case
[ -3 split drop
$ "second" join ]
$ "ee" case
[ -3 split drop
$ "ird" join ]
$ "ve" case
[ -2 split drop
$ "fth" join ]
$ "ht" case
[ $ "h" join ]
$ "ty" case
[ -1 split drop
$ "ieth" join ]
otherwise
[ $ "th" join ] ] ] is nameth$ ( n --> $ )
' [ 1 2 3 4 5 11 65 100 101 272 23456 8007006005004003 ]
witheach
[ dup echo say " = " nameth$ echo$ cr ]
- Output:
1 = first 2 = second 3 = third 4 = fourth 5 = fifth 11 = eleventh 65 = sixty fifth 100 = one hundredth 101 = one hundred and first 272 = two hundred and seventy second 23456 = twenty three thousand and four hundred and fifty sixth 8007006005004003 = eight quadrillion, seven trillion, six billion, five million, four thousand and third
Raku
(formerly Perl 6)
Rakudo version 2019.07.1 is updated to Unicode version 12.1. Unicode version 12.0 introduced some new numeric digits, which changed the output here a bit. This will work with earlier versions of Rakudo, but will yield slightly different results.
This would be pretty simple to implement from scratch; it would be straightforward to do a minor modification of the Number names task code. Much simpler to just use the Lingua::EN::Numbers module from the Raku ecosystem though. It will easily handles ordinal number conversions.
We need to be slightly careful of terminology. In Raku, 123, 00123.0, & 1.23e2 are not all integers. They are respectively an Int (integer), a Rat (rational number) and a Num (floating point number). (The fourth numeric is a Complex) For this task it doesn't much matter as the ordinal routine coerces its argument to an Int, but to Raku they are different things. We can further abuse allomorphic and String types and role mixins for some somewhat non-intuitive results as well.
Note that the different allomorphic integer forms of 123 are evaluated on use, not on assignment. They can be passed around in parameters, but until they are used numerically, they retain their stringy characteristics and are distinctive, determinable through introspection. The numerics are evaluated on assignment, hence the stringified output not exactly matching the input format. The mixin role returns different things depending on what context you evaluate it under. When evaluated as a string it is 17, numerically, it is 123.
Raku uses Unicode natively. If a glyph has a Unicode 'Numeric Digit' (<:Nd>) property, it is treated as a numeric digit, and may be used as one.
It is not really clear what is meant by "Write a driver and a function...". Well, the function part is clear enough; driver not so much. Perhaps this will suffice.
use Lingua::EN::Numbers;
# The task
+$_ ?? printf( "Type: \%-14s %16s : %s\n", .^name, $_, .&ordinal ) !! say "\n$_:" for
# Testing
'Required tests',
1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003,
'Optional tests - different forms of 123',
'Numerics',
123, 00123.0, 1.23e2, 123+0i,
'Allomorphs',
|<123 1_2_3 00123.0 1.23e2 123+0i 0b1111011 0o173 0x7B 861/7>,
'Numeric Strings',
|'1_2_3 00123.0 1.23e2 123+0i 0b1111011 0o173 0x7B 861/7'.words,
'Unicode Numeric Strings',
# (Only using groups of digits from the same Unicode block. Technically,
# digits from any block could be combined with digits from any other block.)
|(^0x1FFFF).grep( { .chr ~~ /<:Nd>/ and .unival == 1|2|3 }).rotor(3)».chr».join,
'Role Mixin',
'17' but 123;
- Output:
Required tests: Type: Int 1 : first Type: Int 2 : second Type: Int 3 : third Type: Int 4 : fourth Type: Int 5 : fifth Type: Int 11 : eleventh Type: Int 65 : sixty-fifth Type: Int 100 : one hundredth Type: Int 101 : one hundred first Type: Int 272 : two hundred seventy-second Type: Int 23456 : twenty-three thousand, four hundred fifty-sixth Type: Int 8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand third Optional tests - different forms of 123: Numerics: Type: Int 123 : one hundred twenty-third Type: Rat 123 : one hundred twenty-third Type: Num 123 : one hundred twenty-third Type: Complex 123+0i : one hundred twenty-third Allomorphs: Type: IntStr 123 : one hundred twenty-third Type: IntStr 1_2_3 : one hundred twenty-third Type: RatStr 00123.0 : one hundred twenty-third Type: NumStr 1.23e2 : one hundred twenty-third Type: ComplexStr 123+0i : one hundred twenty-third Type: IntStr 0b1111011 : one hundred twenty-third Type: IntStr 0o173 : one hundred twenty-third Type: IntStr 0x7B : one hundred twenty-third Type: RatStr 861/7 : one hundred twenty-third Numeric Strings: Type: Str 1_2_3 : one hundred twenty-third Type: Str 00123.0 : one hundred twenty-third Type: Str 1.23e2 : one hundred twenty-third Type: Str 123+0i : one hundred twenty-third Type: Str 0b1111011 : one hundred twenty-third Type: Str 0o173 : one hundred twenty-third Type: Str 0x7B : one hundred twenty-third Type: Str 861/7 : one hundred twenty-third Unicode Numeric Strings: Type: Str 123 : one hundred twenty-third Type: Str ١٢٣ : one hundred twenty-third Type: Str ۱۲۳ : one hundred twenty-third Type: Str ߁߂߃ : one hundred twenty-third Type: Str १२३ : one hundred twenty-third Type: Str ১২৩ : one hundred twenty-third Type: Str ੧੨੩ : one hundred twenty-third Type: Str ૧૨૩ : one hundred twenty-third Type: Str ୧୨୩ : one hundred twenty-third Type: Str ௧௨௩ : one hundred twenty-third Type: Str ౧౨౩ : one hundred twenty-third Type: Str ೧೨೩ : one hundred twenty-third Type: Str ൧൨൩ : one hundred twenty-third Type: Str ෧෨෩ : one hundred twenty-third Type: Str ๑๒๓ : one hundred twenty-third Type: Str ໑໒໓ : one hundred twenty-third Type: Str ༡༢༣ : one hundred twenty-third Type: Str ၁၂၃ : one hundred twenty-third Type: Str ႑႒႓ : one hundred twenty-third Type: Str ១២៣ : one hundred twenty-third Type: Str ᠑᠒᠓ : one hundred twenty-third Type: Str ᥇᥈᥉ : one hundred twenty-third Type: Str ᧑᧒᧓ : one hundred twenty-third Type: Str ᪁᪂᪃ : one hundred twenty-third Type: Str ᪑᪒᪓ : one hundred twenty-third Type: Str ᭑᭒᭓ : one hundred twenty-third Type: Str ᮱᮲᮳ : one hundred twenty-third Type: Str ᱁᱂᱃ : one hundred twenty-third Type: Str ᱑᱒᱓ : one hundred twenty-third Type: Str ꘡꘢꘣ : one hundred twenty-third Type: Str ꣑꣒꣓ : one hundred twenty-third Type: Str ꤁꤂꤃ : one hundred twenty-third Type: Str ꧑꧒꧓ : one hundred twenty-third Type: Str ꧱꧲꧳ : one hundred twenty-third Type: Str ꩑꩒꩓ : one hundred twenty-third Type: Str ꯱꯲꯳ : one hundred twenty-third Type: Str 123 : one hundred twenty-third Type: Str 𐒡𐒢𐒣 : one hundred twenty-third Type: Str 𐴱𐴲𐴳 : one hundred twenty-third Type: Str 𑁧𑁨𑁩 : one hundred twenty-third Type: Str 𑃱𑃲𑃳 : one hundred twenty-third Type: Str 𑄷𑄸𑄹 : one hundred twenty-third Type: Str 𑇑𑇒𑇓 : one hundred twenty-third Type: Str 𑋱𑋲𑋳 : one hundred twenty-third Type: Str 𑑑𑑒𑑓 : one hundred twenty-third Type: Str 𑓑𑓒𑓓 : one hundred twenty-third Type: Str 𑙑𑙒𑙓 : one hundred twenty-third Type: Str 𑛁𑛂𑛃 : one hundred twenty-third Type: Str 𑜱𑜲𑜳 : one hundred twenty-third Type: Str 𑣡𑣢𑣣 : one hundred twenty-third Type: Str 𑱑𑱒𑱓 : one hundred twenty-third Type: Str 𑵑𑵒𑵓 : one hundred twenty-third Type: Str 𑶡𑶢𑶣 : one hundred twenty-third Type: Str 𖩡𖩢𖩣 : one hundred twenty-third Type: Str 𖭑𖭒𖭓 : one hundred twenty-third Type: Str 𝟏𝟐𝟑 : one hundred twenty-third Type: Str 𝟙𝟚𝟛 : one hundred twenty-third Type: Str 𝟣𝟤𝟥 : one hundred twenty-third Type: Str 𝟭𝟮𝟯 : one hundred twenty-third Type: Str 𝟷𝟸𝟹 : one hundred twenty-third Type: Str 𞥑𞥒𞥓 : one hundred twenty-third Role Mixin: Type: Str+{<anon|1>} 17 : one hundred twenty-third
REXX
/*REXX programs spells out ordinal numbers (in English, using the American system). */
numeric digits 3000 /*just in case the user uses gihugic #s*/
parse arg n /*obtain optional arguments from the CL*/
if n='' | n="," then n= 1 2 3 4 5 11 65 100 101 272 23456 8007006005004003
pgmOpts= 'ordinal quiet' /*define options needed for $SPELL#.REX*/
do j=1 for words(n) /*process each of the specified numbers*/
x=word(n, j) /*obtain a number from the input list. */
os=$spell#(x pgmOpts) /*invoke REXX routine to spell ordinal#*/
say right(x, max(20, length(x) ) ) ' spelled ordinal number ───► ' os
end /*j*/
- output when using the default inputs:
1 spelled ordinal number ───► first 2 spelled ordinal number ───► second 3 spelled ordinal number ───► third 4 spelled ordinal number ───► fourth 5 spelled ordinal number ───► fifth 11 spelled ordinal number ───► eleventh 65 spelled ordinal number ───► sixty-fifth 100 spelled ordinal number ───► one hundredth 101 spelled ordinal number ───► one hundred first 272 spelled ordinal number ───► two hundred seventy-second 23456 spelled ordinal number ───► twenty-three thousand four hundred fifty-sixth 8007006005004003 spelled ordinal number ───► eight quadrillion seven trillion six billion five million four thousand third
The $SPELL#.REX routine can be found here ───► $SPELL#.REX.
Rust
struct NumberNames {
cardinal: &'static str,
ordinal: &'static str,
}
impl NumberNames {
fn get_name(&self, ordinal: bool) -> &'static str {
if ordinal {
return self.ordinal;
}
self.cardinal
}
}
const SMALL_NAMES: [NumberNames; 20] = [
NumberNames {
cardinal: "zero",
ordinal: "zeroth",
},
NumberNames {
cardinal: "one",
ordinal: "first",
},
NumberNames {
cardinal: "two",
ordinal: "second",
},
NumberNames {
cardinal: "three",
ordinal: "third",
},
NumberNames {
cardinal: "four",
ordinal: "fourth",
},
NumberNames {
cardinal: "five",
ordinal: "fifth",
},
NumberNames {
cardinal: "six",
ordinal: "sixth",
},
NumberNames {
cardinal: "seven",
ordinal: "seventh",
},
NumberNames {
cardinal: "eight",
ordinal: "eighth",
},
NumberNames {
cardinal: "nine",
ordinal: "ninth",
},
NumberNames {
cardinal: "ten",
ordinal: "tenth",
},
NumberNames {
cardinal: "eleven",
ordinal: "eleventh",
},
NumberNames {
cardinal: "twelve",
ordinal: "twelfth",
},
NumberNames {
cardinal: "thirteen",
ordinal: "thirteenth",
},
NumberNames {
cardinal: "fourteen",
ordinal: "fourteenth",
},
NumberNames {
cardinal: "fifteen",
ordinal: "fifteenth",
},
NumberNames {
cardinal: "sixteen",
ordinal: "sixteenth",
},
NumberNames {
cardinal: "seventeen",
ordinal: "seventeenth",
},
NumberNames {
cardinal: "eighteen",
ordinal: "eighteenth",
},
NumberNames {
cardinal: "nineteen",
ordinal: "nineteenth",
},
];
const TENS: [NumberNames; 8] = [
NumberNames {
cardinal: "twenty",
ordinal: "twentieth",
},
NumberNames {
cardinal: "thirty",
ordinal: "thirtieth",
},
NumberNames {
cardinal: "forty",
ordinal: "fortieth",
},
NumberNames {
cardinal: "fifty",
ordinal: "fiftieth",
},
NumberNames {
cardinal: "sixty",
ordinal: "sixtieth",
},
NumberNames {
cardinal: "seventy",
ordinal: "seventieth",
},
NumberNames {
cardinal: "eighty",
ordinal: "eightieth",
},
NumberNames {
cardinal: "ninety",
ordinal: "ninetieth",
},
];
struct NamedNumber {
cardinal: &'static str,
ordinal: &'static str,
number: usize,
}
impl NamedNumber {
fn get_name(&self, ordinal: bool) -> &'static str {
if ordinal {
return self.ordinal;
}
self.cardinal
}
}
const N: usize = 7;
const NAMED_NUMBERS: [NamedNumber; N] = [
NamedNumber {
cardinal: "hundred",
ordinal: "hundredth",
number: 100,
},
NamedNumber {
cardinal: "thousand",
ordinal: "thousandth",
number: 1000,
},
NamedNumber {
cardinal: "million",
ordinal: "millionth",
number: 1000000,
},
NamedNumber {
cardinal: "billion",
ordinal: "billionth",
number: 1000000000,
},
NamedNumber {
cardinal: "trillion",
ordinal: "trillionth",
number: 1000000000000,
},
NamedNumber {
cardinal: "quadrillion",
ordinal: "quadrillionth",
number: 1000000000000000,
},
NamedNumber {
cardinal: "quintillion",
ordinal: "quintillionth",
number: 1000000000000000000,
},
];
fn big_name(n: usize) -> &'static NamedNumber {
for i in 1..N {
if n < NAMED_NUMBERS[i].number {
return &NAMED_NUMBERS[i - 1];
}
}
&NAMED_NUMBERS[N - 1]
}
fn number_name(n: usize, ordinal: bool) -> String {
if n < 20 {
return String::from(SMALL_NAMES[n].get_name(ordinal));
} else if n < 100 {
if n % 10 == 0 {
return String::from(TENS[n / 10 - 2].get_name(ordinal));
}
let s1 = TENS[n / 10 - 2].get_name(false);
let s2 = SMALL_NAMES[n % 10].get_name(ordinal);
return format!("{}-{}", s1, s2);
}
let big = big_name(n);
let mut result = number_name(n / big.number, false);
result.push(' ');
if n % big.number == 0 {
result.push_str(big.get_name(ordinal));
} else {
result.push_str(big.get_name(false));
result.push(' ');
result.push_str(&number_name(n % big.number, ordinal));
}
result
}
fn test_ordinal(n: usize) {
println!("{}: {}", n, number_name(n, true));
}
fn main() {
test_ordinal(1);
test_ordinal(2);
test_ordinal(3);
test_ordinal(4);
test_ordinal(5);
test_ordinal(11);
test_ordinal(15);
test_ordinal(21);
test_ordinal(42);
test_ordinal(65);
test_ordinal(98);
test_ordinal(100);
test_ordinal(101);
test_ordinal(272);
test_ordinal(300);
test_ordinal(750);
test_ordinal(23456);
test_ordinal(7891233);
test_ordinal(8007006005004003);
}
- Output:
1: first 2: second 3: third 4: fourth 5: fifth 11: eleventh 15: fifteenth 21: twenty-first 42: forty-second 65: sixty-fifth 98: ninety-eighth 100: one hundredth 101: one hundred first 272: two hundred seventy-second 300: three hundredth 750: seven hundred fiftieth 23456: twenty-three thousand four hundred fifty-sixth 7891233: seven million eight hundred ninety-one thousand two hundred thirty-third 8007006005004003: eight quadrillion seven trillion six billion five million four thousand third
Sidef
var lingua_en = frequire('Lingua::EN::Numbers')
var tests = [1,2,3,4,5,11,65,100,101,272,23456,8007006005004003]
tests.each {|n|
printf("%16s : %s\n", n, lingua_en.num2en_ordinal(n))
}
- Output:
1 : first 2 : second 3 : third 4 : fourth 5 : fifth 11 : eleventh 65 : sixty-fifth 100 : one hundredth 101 : one hundred and first 272 : two hundred and seventy-second 23456 : twenty-three thousand four hundred and fifty-sixth 8007006005004003 : eight quadrillion, seven trillion, six billion, five million, four thousand and third
Swift
fileprivate class NumberNames {
let cardinal: String
let ordinal: String
init(cardinal: String, ordinal: String) {
self.cardinal = cardinal
self.ordinal = ordinal
}
func getName(_ ordinal: Bool) -> String {
return ordinal ? self.ordinal : self.cardinal
}
class func numberName(number: Int, ordinal: Bool) -> String {
guard number < 100 else {
return ""
}
if number < 20 {
return smallNames[number].getName(ordinal)
}
if number % 10 == 0 {
return tens[number/10 - 2].getName(ordinal)
}
var result = tens[number/10 - 2].getName(false)
result += "-"
result += smallNames[number % 10].getName(ordinal)
return result
}
static let smallNames = [
NumberNames(cardinal: "zero", ordinal: "zeroth"),
NumberNames(cardinal: "one", ordinal: "first"),
NumberNames(cardinal: "two", ordinal: "second"),
NumberNames(cardinal: "three", ordinal: "third"),
NumberNames(cardinal: "four", ordinal: "fourth"),
NumberNames(cardinal: "five", ordinal: "fifth"),
NumberNames(cardinal: "six", ordinal: "sixth"),
NumberNames(cardinal: "seven", ordinal: "seventh"),
NumberNames(cardinal: "eight", ordinal: "eighth"),
NumberNames(cardinal: "nine", ordinal: "ninth"),
NumberNames(cardinal: "ten", ordinal: "tenth"),
NumberNames(cardinal: "eleven", ordinal: "eleventh"),
NumberNames(cardinal: "twelve", ordinal: "twelfth"),
NumberNames(cardinal: "thirteen", ordinal: "thirteenth"),
NumberNames(cardinal: "fourteen", ordinal: "fourteenth"),
NumberNames(cardinal: "fifteen", ordinal: "fifteenth"),
NumberNames(cardinal: "sixteen", ordinal: "sixteenth"),
NumberNames(cardinal: "seventeen", ordinal: "seventeenth"),
NumberNames(cardinal: "eighteen", ordinal: "eighteenth"),
NumberNames(cardinal: "nineteen", ordinal: "nineteenth")
]
static let tens = [
NumberNames(cardinal: "twenty", ordinal: "twentieth"),
NumberNames(cardinal: "thirty", ordinal: "thirtieth"),
NumberNames(cardinal: "forty", ordinal: "fortieth"),
NumberNames(cardinal: "fifty", ordinal: "fiftieth"),
NumberNames(cardinal: "sixty", ordinal: "sixtieth"),
NumberNames(cardinal: "seventy", ordinal: "seventieth"),
NumberNames(cardinal: "eighty", ordinal: "eightieth"),
NumberNames(cardinal: "ninety", ordinal: "ninetieth")
]
}
fileprivate class NamedPower {
let cardinal: String
let ordinal: String
let number: UInt64
init(cardinal: String, ordinal: String, number: UInt64) {
self.cardinal = cardinal
self.ordinal = ordinal
self.number = number
}
func getName(_ ordinal: Bool) -> String {
return ordinal ? self.ordinal : self.cardinal
}
class func getNamedPower(_ number: UInt64) -> NamedPower {
for i in 1..<namedPowers.count {
if number < namedPowers[i].number {
return namedPowers[i - 1]
}
}
return namedPowers[namedPowers.count - 1]
}
static let namedPowers = [
NamedPower(cardinal: "hundred", ordinal: "hundredth",
number: 100),
NamedPower(cardinal: "thousand", ordinal: "thousandth",
number: 1000),
NamedPower(cardinal: "million", ordinal: "millionth",
number: 1000000),
NamedPower(cardinal: "billion", ordinal: "billionth",
number: 1000000000),
NamedPower(cardinal: "trillion", ordinal: "trillionth",
number: 1000000000000),
NamedPower(cardinal: "quadrillion", ordinal: "quadrillionth",
number: 1000000000000000),
NamedPower(cardinal: "quintillion", ordinal: "quintillionth",
number: 1000000000000000000)
]
}
public func numberName(number: UInt64, ordinal: Bool) -> String {
if number < 100 {
return NumberNames.numberName(number: Int(truncatingIfNeeded: number),
ordinal: ordinal)
}
let p = NamedPower.getNamedPower(number)
var result = numberName(number: number/p.number, ordinal: false)
result += " "
if number % p.number == 0 {
result += p.getName(ordinal)
} else {
result += p.getName(false)
result += " "
result += numberName(number: number % p.number, ordinal: ordinal)
}
return result
}
func printOrdinal(_ number: UInt64) {
print("\(number): \(numberName(number: number, ordinal: true))")
}
printOrdinal(1)
printOrdinal(2)
printOrdinal(3)
printOrdinal(4)
printOrdinal(5)
printOrdinal(11)
printOrdinal(15)
printOrdinal(21)
printOrdinal(42)
printOrdinal(65)
printOrdinal(98)
printOrdinal(100)
printOrdinal(101)
printOrdinal(272)
printOrdinal(300)
printOrdinal(750)
printOrdinal(23456)
printOrdinal(7891233)
printOrdinal(8007006005004003)
- Output:
1: first 2: second 3: third 4: fourth 5: fifth 11: eleventh 15: fifteenth 21: twenty-first 42: forty-second 65: sixty-fifth 98: ninety-eighth 100: one hundredth 101: one hundred first 272: two hundred seventy-second 300: three hundredth 750: seven hundred fiftieth 23456: twenty-three thousand four hundred fifty-sixth 7891233: seven million eight hundred ninety-one thousand two hundred thirty-third 8007006005004003: eight quadrillion seven trillion six billion five million four thousand third
VBA
Inspired by the Phix solution. Uses Number names
Private Function ordinal(s As String) As String
Dim irregs As New Collection
irregs.Add "first", "one"
irregs.Add "second", "two"
irregs.Add "third", "three"
irregs.Add "fifth", "five"
irregs.Add "eighth", "eight"
irregs.Add "ninth", "nine"
irregs.Add "twelfth", "twelve"
Dim i As Integer
For i = Len(s) To 1 Step -1
ch = Mid(s, i, 1)
If ch = " " Or ch = "-" Then Exit For
Next i
On Error GoTo 1
ord = irregs(Right(s, Len(s) - i))
ordinal = Left(s, i) & ord
Exit Function
1:
If Right(s, 1) = "y" Then
s = Left(s, Len(s) - 1) & "ieth"
Else
s = s & "th"
End If
ordinal = s
End Function
Public Sub ordinals()
tests = [{1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003, 123, 00123.0, 1.23E2}]
init
For i = 1 To UBound(tests)
Debug.Print ordinal(spell(tests(i)))
Next i
End Sub
- Output:
first second third fourth fifth eleventh sixty-fifth one hundredth one hundred and first two hundred and seventy-second twenty-three thousand, four hundred and fifty-sixth eight quadrillion, seven trillion, six billion, five million, four thousandth one hundred and twenty-third one hundred and twenty-third
V (Vlang)
As with the Kotlin solution, this uses the output of say
from the
Number_names task.
fn main() {
for n in [i64(1), 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 8007006005004003,
] {
println(say_ordinal(n))
}
}
fn say_ordinal(n i64) string {
mut s := say(n)
mut i := s.last_index('-') or {s.last_index(' ') or {-1}}
i++
// Now s[:i] is everything upto and including the space or hyphen
// and s[i:] is the last word; we modify s[i:] as required.
// Since LastIndex returns -1 if there was no space/hyphen,
// `i` will be zero and this will still be fine.
ok := s[i..] in irregular_ordinals
x := irregular_ordinals[s[i..]]
if ok {
s = s[..i] + x
} else if s[s.len-1..s.len] == 'y' {
s = s[..i] + s[i..s.len-1] + "ieth"
} else {
s = s[..i] + s[i..] + "th"
}
return s
}
// Below is a copy of https://rosettacode.org/wiki/Number_names#Go
const (
small = ["zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen",
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
tens = ["", "", "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"]
illions = ["", " thousand", " million", " billion",
" trillion", " quadrillion", " quintillion"]
irregular_ordinals = {
"one": "first",
"two": "second",
"three": "third",
"five": "fifth",
"eight": "eighth",
"nine": "ninth",
"twelve": "twelfth",
}
)
fn say(nn i64) string {
mut n := nn
mut t := ''
if n < 0 {
t = "negative "
// Note, for math.MinInt64 this leaves n negative.
n = -n
}
if n < 20{
t += small[n]
} else if n < 100{
t += tens[n/10]
s := n % 10
if s > 0 {
t += "-" + small[s]
}
} else if n < 1000{
t += small[n/100] + " hundred"
s := n % 100
if s > 0 {
t += " " + say(s)
}
} else {
// work right-to-left
mut sx := ""
for i := 0; n > 0; i++ {
p := n % 1000
n /= 1000
if p > 0 {
mut ix := say(p) + illions[i]
if sx != "" {
ix += " " + sx
}
sx = ix
}
}
t += sx
}
return t
}
- Output:
first second third fourth fifth eleventh sixty-fifth one hundredth one hundred first two hundred seventy-second twenty-three thousand four hundred fifty-sixth eight quadrillion seven trillion six billion five million four thousand third
Wren
This reuses the say
function from the Number names task.
Note that it is not safe to use this script for numbers with an absolute magnitude >= 2^53 as integers cannot be expressed exactly by Wren's Num type beyond that limit.
var small = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
var tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
var illions = ["", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion"]
var irregularOrdinals = {
"one": "first",
"two": "second",
"three": "third",
"five": "fifth",
"eight": "eighth",
"nine": "ninth",
"twelve": "twelfth"
}
var say
say = Fn.new { |n|
var t = ""
if (n < 0) {
t = "negative "
n = -n
}
if (n < 20) {
t = t + small[n]
} else if (n < 100) {
t = t + tens[(n/10).floor]
var s = n % 10
if (s > 0) t = t + "-" + small[s]
} else if (n < 1000) {
t = t + small[(n/100).floor] + " hundred"
var s = n % 100
System.write("") // guards against VM recursion bug
if (s > 0) t = t + " " + say.call(s)
} else {
var sx = ""
var i = 0
while (n > 0) {
var p = n % 1000
n = (n/1000).floor
if (p > 0) {
System.write("") // guards against VM recursion bug
var ix = say.call(p) + illions[i]
if (sx != "") ix = ix + " " + sx
sx = ix
}
i = i + 1
}
t = t + sx
}
return t
}
var sayOrdinal = Fn.new { |n|
var s = say.call(n)
var r = s[-1..0]
var i1 = r.indexOf(" ")
if (i1 != -1) i1 = s.count - 1 - i1
var i2 = r.indexOf("-")
if (i2 != -1) i2 = s.count - 1 - i2
var i = (i1 > i2) ? i1 : i2
i = i + 1
// Now s[0...i] is everything up to and including the space or hyphen
// and s[i..-1] is the last word; we modify s[i..-1] as required.
// Since indexOf returns -1 if there was no space/hyphen,
// `i` will be zero and this will still be fine.
var x = irregularOrdinals[s[i..-1]]
if (x) {
return s[0...i] + x
} else if (s[-1] == "y") {
return s[0...i] + s[i..-2] + "ieth"
} else {
return s[0...i] + s[i..-1] + "th"
}
}
for (n in [1, 2, 3, 4, 5, 11, 65, 100, 101, 272, 23456, 9007199254740991]) {
System.print(sayOrdinal.call(n))
}
- Output:
first second third fourth fifth eleventh sixty-fifth one hundredth one hundred first two hundred seventy-second twenty-three thousand four hundred fifty-sixth nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-first
zkl
fcn nth(n,th=True){
var [const]
nmsth=T("","first","second","third","fourth","fifth","sixth","seventh","eighth","ninth"),
nms1=T("","one","two","three","four","five","six","seven","eight","nine"),
nms10=T("ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"),
nms10th=T("tenth","eleventh","twelfth","thirteenth","fourteenth","fifteenth","sixteenth","seventeenth","eighteenth","nineteenth"),
nms20=T("twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"),
nms1000=T("thousand","million","billion","trillion","quadrillion"); // 3,6,9,12,15
if (n<0) String("negative ",nth(-n,th));
else if(n<10) th and nmsth[n] or nms1[n];
else if(n<20) th and nms10th[n-10] or nms10[n-10];
else if(n<10) th and nmsth[n] or nms1[n];
else if(n<100){
m,txt := n%10,nms20[n/10-2];
if(m) String(txt,dash(n%10,"-",th));
else String(txt[0,-1],"ieth");
}
else if(n<1000) String(nms1[n/100]," hundred",dash(n%100," ",th));
else{
n=n.toInt(); // yuck, only here to handle floats, 1.23-->"first"
ds:=(n.numDigits()-1)/3*3; // 1e3->3, 1e4-->3, 1e5-->3, 1e6-->6, 1e7-->6
z:=(10).pow(ds); // 1234-->1000, 12345-->10000
thou:=ds/3 - 1; // 1000-->0, 10000-->0, 2,000,000-->1
nnn,ys := n/z, n%z;
String((if(nnn<10) nms1[nnn] else nth(nnn,False)),
" ",nms1000[thou],
if(ys==0) "th" else String(" ",nth(ys,th)));
}
}
fcn dash(n,d,th){ if(n) String(d,nth(n,th)) else (th and "th" or "") }
testNs:=L(1,2,3,4,5,11,65,100,101,272,23456,8007006005004003,
123,00123.0,1.23e2,);
foreach n in (testNs){
if(n.isType(Float)) println("%16.2f --> %s".fmt(n,nth(n)));
else println("%16d --> %s".fmt(n,nth(n)));
}
- Output:
1 --> first 2 --> second 3 --> third 4 --> fourth 5 --> fifth 11 --> eleventh 65 --> sixty-fifth 100 --> one hundredth 101 --> one hundred first 272 --> two hundred seventy-second 23456 --> twenty-three thousand four hundred fifty-sixth 8007006005004003 --> eight quadrillion seven trillion six billion five million four thousand third 123 --> one hundred twenty-third 123.00 --> one hundred twenty-third 123.00 --> one hundred twenty-third