Spelling of ordinal numbers: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|zkl}}: change output format)
(Added Kotlin)
Line 40: Line 40:
<br><br>
<br><br>


=={{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.
<lang scala>// 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)}")
}</lang>

{{out}}
<pre>
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
</pre>


=={{header|Perl 6}}==
=={{header|Perl 6}}==

Revision as of 13:03, 9 September 2017

Spelling of ordinal numbers is a 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:

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



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. <lang scala>// 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)}")

}</lang>

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

Works with: Rakudo version 2017.08

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.

<lang perl6>use Lingua::EN::Numbers::Cardinal;

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

  1. Required tests

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

  1. Optional tests

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

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

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

<lang 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"),
    nms20=T("twenty","thirty","fourty","fifty","sixty","seventy","eighty","ninety"),
    nms1000=T("thousand","million","billion","trillion","quadrillion"); // 3,6,9,12,15
  if(n<10)        th and nmsth[n] or nms1[n];
  else if(n<20)   String(nms10[n-20],th and "th" or "");
  else if(n<100)  String(nms20[n/10-2],dash(n%10,"-",th));
  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)));

  }

} fcn dash(n,d,th){ if(n) String(d,nth(n,th)) else (th and "th" or "") }</lang> <lang zkl>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)));

}</lang>

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