3
\$\begingroup\$

This JavaScript code generates the full name of the numeral scales for large numbers under the "Short Scale Numeral System" using the Conway-Guy system for forming number prefixes.

Some very brief information on how this is done can be found at the end of this Wikipedia article.

However, I have tried in this article to give more details on how this can be generated and coded programmatically and an explanation of the system.

The code handles numeral scales names up to 1000^999 (i.e. the number 1 followed by 3000 zeros).

The naming procedure for large numbers is based on taking the number power of the number and concatenating the Latin roots for its units, tens, and hundreds place, together with the suffix "llion".

Note the sequence and order of the concatenation is from lowest to largest (this opposite to how we pronounce and write numbers such as 123 [one hundred twenty-three]).

This way, numbers up to 10^3000 (or 1000^ 999) may be named easily.

The choice of Latin roots and the concatenation procedure is as follows:

For small powers from 1 to 9: Use standard dictionary (i.e. million, billion, trillion, etc. up to nonillion).

For larger powers (between 10 and 999): prefixes are constructed based on a system described by John Horton Conway and Richard K. Guy using the Latin roots.

The Conway-Guy System for forming prefixes is included in the following table:

enter image description here

The Scale Name can be generated by concatenating the Unit Name, Tens Name, Hundreds Name, and adding "llion" to the end of the concatenated string as illustrated below:

enter image description here

However, concatenation is not that straight forwards because four (4) of the Unit Names (tre (3), se (6), septe (7), and nove (9)) cannot be concatenated directly "as is" and require modification depending on the Tens Name or Hundred Name that follows them.

For example: unit name "tri (3)" need to be changed to "tres" if it is to be concatenated with (say) 20 (viginti) or with 300 (tricinti).

Similarly, "se" need to be changed to "ses" or "sex", "septe" and "nove" also need to be changed to "septem" and "novem" or "septen" and "noven" respectively depending on the tens or hundreds name.

Therefore, for each Tens Name and Hundreds Name there is a corresponding Unit Name that can precede it for the purpose concatenation (this is the purpose of so ugly array).

The illustrative tables below list the changes needed for each Unit Name depending on the Tens Name and the Hundreds Name.

enter image description here

enter image description here

One additional requirement to be considered when concatenating the various names is that Unit Names ending in "a" need to be changed to end with "i" when they are to be concatenated with the word "llion". Names ending with "a" only exist in the Tens Names!

For example:

The number 10^31 ==> "triginta" becomes "triginti" + "llion" ==> trigintillion

The number 10^81 ==> "octoginta" becomes "octoginti" + "llion" ==> octogintintillion

The handling of this situation is catered for in the "Tens" array; the last element made as Boolean True being a marker.

Additional Examples are shown in the image below:

enter image description here

The input to the function is a number which is the power of the base 1000.

  • 1 means 1000^1 = 1,000
  • 2 means 1000^2 = 1,000,000 (million)
  • 3 means 1000^3 = 1,000,000,000 (billion)

The code function is made to generate the Scale Names for the Short Scale Numeral System used in (USA, UK, Canada, i.e. System using Billion instead of Milliard). You can read about the differences between the Short and Long Scale Numeral Systems here.

The reason for the code line Power -=1; is that the formula for generating a Scale Name under the Short Scale System for a number n is 10^(3n+3). You can see that from (say) the number "trillion" where "tri" means 3 but the number trillion is 10^4 and not 10^3. So, the prefix Latin names do not correlate to the power number.

The code can be modified easily to generate the strings for the Long Scale System using the same arrays. In this case, the maximum power is 10^6000 (i.e. 1 with 6000 zeros).

Test code is included that tests various numbers.

Also included in the testing (however, currently commented) is testing to generate the Scale Names for the powers from 0 to 999. (However, note that the Stack Exchange console will only print out the last 50 lines).

Although the function is not intended to handle powers from 0 to 10, I have included them with a quick check for completeness with full dictionary names for speed.

/************************************************************************
* @Function    : numberScaleNameShortScale()
* @Purpose     : Construct full name of the Short Scale Numeral System
*                Using the Conway-Guy system for forming number prefixes
*
* @Version     : 0.02
* @Author      : Mohsen Alyafei
* @Date        : 12 Jun 2020
* @Param       : {number} [Power=0] the power numeral of the base 1000
*                e.g. 1 means 1000^1 = 1,000
*                e.g. 2 means 1000^2 = 1,000,000 (million)
*                e.g. 3 means 1000^3 = 1,000,000,000 (billion)
*
* @Returns     : {string} The name of the large number
* @Example     :
* numberScaleNameShortScale(4);
* // => trillion
*
* numberScaleNameShortScale(21);
* // => vigintillion
*
* @Description : Handles power from 0 to 999
*                The larget scale name is therefor the umber with
*                3,000 zeros (Novenonagintanongentillion)
* @Reference   : https://en.wikipedia.org/wiki/Names_of_large_numbers
*
* For powers n from 1 to 10, prefixes are constructed based on
* standard dictionary entry.
* For larger powers of n (between 11 and 999), prefixes are constructed
* based on the system described by John Horton Conway and Richard K. Guy.
*************************************************************************/

function numberScaleNameShortScale(Power=0) {
// Do this first and get out quick as it is the most used 99% of the time
// You may delete following line if only interested in Powers above 10 (i.e. 1,000^11 and above)
if (Power<11) return ["","thousand","million","billion","trillion","quadrillion","quintillion","sextillion","septillion","octillion","nonillion"][Power];

Power-=1; // Adjust the sequence above power of 10 as these are now systematic

let TensList = [
    [""            ,["","","","" ,"","","" ,"" ,"","" ,false]],
    ["deci"        ,["","","","" ,"","","" ,"n","","n",false]], // 10
    ["viginti"     ,["","","","s","","","s","m","","m",false]], // 20
    ["triginta"    ,["","","","s","","","s","n","","n",true ]], // 30
    ["quadraginta" ,["","","","s","","","s","n","","n",true ]], // 40
    ["quinquaginta",["","","","s","","","s","n","","n",true ]], // 50
    ["sexaginta"   ,["","","","" ,"","","" ,"n","","n",true ]], // 60
    ["septuaginta" ,["","","","" ,"","","" ,"n","","n",true ]], // 70
    ["octoginta"   ,["","","","" ,"","","x","m","","m",true ]], // 80
    ["nonaginta"   ,["","","","" ,"","","" ,"" ,"","" ,true ]]  // 90
];
let HundredsList = [
    [""            ,["","","","" ,"","","" ,"" ,"","" ]],
    ["centi"       ,["","","","" ,"","","x","n","","n"]], // 100
    ["ducenti"     ,["","","","" ,"","","" ,"n","","n"]], // 200
    ["trecenti"    ,["","","","s","","","s","n","","n"]], // 300
    ["quadringenti",["","","","s","","","s","n","","n"]], // 400
    ["quingenti"   ,["","","","s","","","s","n","","n"]], // 500
    ["sescenti"    ,["","","","" ,"","","" ,"n","","n"]], // 600
    ["septingenti" ,["","","","" ,"","","" ,"n","","n"]], // 700
    ["octingenti"  ,["","","","" ,"","","x","m","","m"]], // 800
    ["nongenti"    ,["","","","" ,"","","" ,"" ,"","" ]]  // 900
];

 let Hund     = Math.floor(Power / 100),      // Hundred Digit
     Ten      = Math.floor(Power % 100 / 10), // Ten Digit
     Unit     = Power % 10 % 10,              // Unit Digit
     UnitName = ["","un","duo","tre","quattuor","quin","se","septe","octo","nove"][Unit], // Get Unit Name from Array
     TenName  = TensList [Ten][0],            // Get Tens Name from Array
     HundName = HundredsList[Hund][0];        // Get Hundreds Name from Array

// convert Ten names ending with "a" to "i" if it was prceeding the "llion" word
if (!Hund && TensList[Ten][1][10]) TenName = TenName.slice(0,-1)+"i";

// Pickup and add the correct suffix to the Unit Name (s,x,n, or m)
 if (Ten) TenName           =      TensList[Ten] [1][Unit]+TenName;
 if (Hund && !Ten) HundName =  HundredsList[Hund][1][Unit]+HundName;

 return UnitName + TenName + HundName + "llion"; // Create name
}

//=========================================
//             Test Codes
//=========================================

function test(n,should) {
    var result = numberScaleNameShortScale(n);
    if (result !== should) {
        console.log(`${n} Output   : ${result}`);
        console.log(`${n} Should be: ${should}`);
        return 1;
    }
}

var r=0; // test tracker
r |= test(2,"million");
r |= test(3,"billion");
r |= test(4,"trillion");
r |= test(5,"quadrillion");
r |= test(6,"quintillion");
r |= test(7,"sextillion");
r |= test(8,"septillion");
r |= test(9,"octillion");
r |= test(10,"nonillion");
r |= test(11,"decillion");
r |= test(12,"undecillion");
r |= test(13,"duodecillion");
r |= test(14,"tredecillion");
r |= test(15,"quattuordecillion");
r |= test(16,"quindecillion");
r |= test(17,"sedecillion");
r |= test(18,"septendecillion");
r |= test(19,"octodecillion");
r |= test(20,"novendecillion");
r |= test(21,"vigintillion");
r |= test(22,"unvigintillion");
r |= test(23,"duovigintillion");
r |= test(24,"tresvigintillion");
r |= test(25,"quattuorvigintillion");
r |= test(26,"quinvigintillion");
r |= test(27,"sesvigintillion");
r |= test(28,"septemvigintillion");
r |= test(29,"octovigintillion");
r |= test(30,"novemvigintillion");
r |= test(31,"trigintillion");
r |= test(32,"untrigintillion");
r |= test(33,"duotrigintillion");
r |= test(34,"trestrigintillion");
r |= test(35,"quattuortrigintillion");
r |= test(36,"quintrigintillion");
r |= test(37,"sestrigintillion");
r |= test(38,"septentrigintillion");
r |= test(39,"octotrigintillion");
r |= test(40,"noventrigintillion");
r |= test(41,"quadragintillion");
r |= test(51,"quinquagintillion");
r |= test(61,"sexagintillion");
r |= test(71,"septuagintillion");
r |= test(81,"octogintillion");
r |= test(91,"nonagintillion");
r |= test(101,"centillion");
r |= test(102,"uncentillion");
r |= test(111,"decicentillion");
r |= test(112,"undecicentillion");
r |= test(121,"viginticentillion");
r |= test(122,"unviginticentillion");
r |= test(131,"trigintacentillion");
r |= test(141,"quadragintacentillion");
r |= test(151,"quinquagintacentillion");
r |= test(161,"sexagintacentillion");
r |= test(171,"septuagintacentillion");
r |= test(181,"octogintacentillion");
r |= test(191,"nonagintacentillion");
r |= test(201,"ducentillion");
r |= test(251,"quinquagintaducentillion");
r |= test(301,"trecentillion");
r |= test(351,"quinquagintatrecentillion");
r |= test(378,"septenseptuagintatrecentillion");
r |= test(401,"quadringentillion");
r |= test(451,"quinquagintaquadringentillion");
r |= test(454,"tresquinquagintaquadringentillion");
r |= test(501,"quingentillion");
r |= test(601,"sescentillion");
r |= test(701,"septingentillion");
r |= test(801,"octingentillion");
r |= test(901,"nongentillion");
r |= test(999,"octononagintanongentillion");

if (r==0) console.log("All Passed.");

// Uncomment the following line to list all names from 0 to 999
// for (i=0;i<1000;i++) {console.log(i+": "+numberScaleNameShortScale(i));}

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.