# Spelling of ordinal numbers

*is a*

**Spelling of ordinal numbers****draft**programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

**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:

1^{st}2^{nd}3^{rd}4^{th}5^{th}6^{th}7^{th}··· 99^{th}100^{th}··· 1000000000^{th}···

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 American version of numbers will be used here (as opposed to the British).

**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

## Julia[edit]

This makes use of code posted on this site by MichaeLeroy for a similar task at https://rosettacode.org/wiki/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", "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[edit]

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

## Perl 6[edit]

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::Cardinal module from the Perl 6 ecosystem though. It easily handles ordinal numbers even though that is not its primary focus.

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). 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 for some somewhat non-intuitive results as well.

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::Cardinal;

printf( "\%16s : %s\n", $_, ordinal($_) ) for

# Required tests

|<1 2 3 4 5 11 65 100 101 272 23456 8007006005004003>,

# Optional tests

|<123 00123.0 1.23e2 123+0i 0b1111011 0o173 0x7B 861/7>;

- 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 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

## REXX[edit]

/*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.

## zkl[edit]

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