/* * [AmericanOrdinals.java] * * Summary: Convert number into words, American ordinals. * * Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.1 1999-01-21 */ package com.mindprod.inwords; /** * Convert number into words, American ordinals. *

* -12345 -> "minus twelve thousand forty-fifth" * This is the scheme used in the USA and Canada. * It uses the AmericanEnglish class. *

* Why is this code written in an unusual way? see inwords.use * * @author Roedy Green, Canadian Mind Products * @version 1.1 1999-01-21 * @since 1999 */ public final class AmericanOrdinals extends AmericanEnglish implements ToWords { private static final int FIRST_COPYRIGHT_YEAR = 1999; /** * undisplayed copyright notice * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 1999-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; private static final String MINUS = "minus"; private static final String ZERO = "zeroth"; private static final String[] combiningGroupName = { /* * American: unit, hundred, thousand, million, billion, trillion, * quadrillion, quintillion */ "", "hundred", "thousand", "million", "billion", "trillion", "quadrillion", "quintillion" }; private static final String[] combiningTys = { /* 0, 10, 20, 30 ... 90 */ "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; private static final String[] terminalGroupName = { /* * We only need up to a quintillion, since a long is about 9 * 10 ^ 18 */ /* * American: unit, hundred, thousand, million, billion, trillion, * quadrillion, quintillion */ "", "hundredth", "thousandth", "millionth", "billionth", "trillionth", "quadrillionth", "quintillionth" }; private static final String[] terminalLowName = { /* zero is shown as "" since it is never used in combined forms */ /* 0 .. 19 */ "", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth" }; private static final String[] terminalTys = { /* 0, 10, 20, 30 ... 90 */ "", "", "twentieth", "thirtieth", "fortieth", "fiftieth", "sixtieth", "seventieth", "eightieth", "ninetieth" }; private static final int[] divisor = { /* * HowToProcess many of this group is needed to form one of the succeeding group. */ /* * American: unit, hundred, thousand, million, billion, trillion, * quadrillion, quintillion */ 100, 10, 1000, 1000, 1000, 1000, 1000, 1000 }; /** * test harness * * @param args not used */ public static void main( String[] args ) { Test.test( new AmericanOrdinals() ); } // end main /** * convert long integer into American English words. e.g. -12345 -> "minus twelve thousand forty-fifth" Handles * negative and positive integers on range -Long.MAX_VALUE .. Long.MAX_VALUE; It cannot handle Long.MIN_VALUE; * * @param num number to convert to words * * @return words * @noinspection WeakerAccess */ public String toWords( long num ) { if ( num == 0 ) { return ZERO; } boolean negative = ( num < 0 ); if ( negative ) { num = -num; } String s = ""; // Work least significant digit to most, right to left. // until high order part is all 0s. for ( int group = 0; num > 0; group++ ) { int remdr = ( int ) ( num % divisor[ group ] ); num = num / divisor[ group ]; // check for 1100 .. 1999, 2100..2999, ... 5200..5999 // but not 1000..1099, 2000..2099, ... // Special case written as fifty-nine hundred. // e.g. thousands digit is 1..5 and hundreds digit is 1..9 // Only when no further higher order. if ( group == 1/* doing hundreds */ && 1 <= num && num <= 5 ) { if ( remdr > 0 ) { remdr += num * 10; num = 0; } // end if } // end if if ( remdr == 0 ) { continue; } String t; boolean terminalNumber = ( group == 0 ); boolean terminalGroup = ( s.length() == 0 ); if ( terminalNumber ) { if ( remdr < 20 ) { t = terminalLowName[ remdr ]; } else if ( remdr < 100 ) { int units = remdr % 10; int tens = remdr / 10; if ( units == 0 ) { t = ( terminalTys[ tens ] ); } else { t = combiningTys[ tens ] + "-" + terminalLowName[ units ]; } } else { t = super.toWords( remdr ); } } else { t = super.toWords( remdr ); } s = t + " " + ( terminalGroup ? terminalGroupName[ group ] : combiningGroupName[ group ] ) + " " + s; } // end for s = s.trim(); if ( negative ) { s = MINUS + " " + s; } return s; } // end inWords } // end AmericanOrdinals