Durango Bill’s
“C” Program to generate Ramanujan Numbers
(Source Code)



Return to the main Ramanujan page

Web page generated via KompoZer


//*************************************************************************
//
//                                Ramanujans.c
//                                    by
//                                Bill Butler
//
//  This program finds Ramanujan numbers. A Ramanujan number is a number
//  formed by the sum of two cubes in 2 or more different ways. For example:
//
//  12^3 + 1^3 = 9^3 + 10^3 = 1729
//
//  There are an infinite number of other paired cubes that have a common sum.
//
//  Also, the number of pairs can be extended to higher orders.
//
//  For example, the first quadruple, Taxicab(4), occurs at:
//
//        13,322^3 + 16,630^3 =
//        10,200^3 + 18,072^3 =
//        5,436^3 + 18,948^3 =
//        2,421^3 + 19,083^3 = 6,963,472,309,248  ( 6963472309248 )
//        (Takes about 30 seconds using this program on a 3GHz processor)
//        (Also nails Taxicab(5) in less than 3 1/4 hrs.)
//
//  Imagine that the following table is an Excel speadsheet. The first row
//  across the top counts upward for J = 1, 2, 3, 4, etc. The second row gives
//  the cube for each of these numbers: 1, 8, 27, 64, etc. Similarly, the first
//  column counts upward for I = 1, 2, 3, 4, etc. and the 2nd column gives the
//  cube for each of these numbers: 1, 8, 27, 64, etc. The rest of the cells in
//  the spreadsheet are the sum of two cubes using the respective rows and
//  columns.
//
//           J    1    2    3    4    5    6    7    8    9   10   11   12   13
//           J^3  1    8   27   64  125  216  343  512  729 1000 1331 1728 2197
//  I  I^3   ------------------------------------------------------------------
//  1    1   |    2    9   28   65  126  217  344  513  730 1001 1332 1729 2198
//  2    8   |    9   16   35   72  133  224  351  520  737 1008 1339 1736 2205
//  3   27   |   28   35   54   91  152  243  370  539  756 1027 1358 1755 2224
//  4   64   |   65   72   91  128  189  280  407  576  793 1064 1395 1792 2261
//  5  125   |  126  133  152  189  250  341  468  637  854 1125 1456 1853 2322
//  6  216   |  217  224  243  280  341  432  559  728  945 1216 1547 1944 2413
//  7  343   |  344  351  370  407  468  559  686  855 1072 1343 1674 2071 2540
//  8  512   |  513  520  539  576  637  728  855 1024 1241 1512 1843 2240 2709
//  9  729   |  730  737  756  793  854  945 1072 1241 1458 1729 2060 2457 2926
// 10 1000   | 1001 1008 1027 1064 1125 1216 1343 1512 1729 2000 2331 2728 3197
// 11 1331   | 1332 1339 1358 1395 1456 1547 1674 1674 1843 2060 2331 2662 3059
// 12 1728   | 1729 1736 1755 1792 1853 1944 2071 2240 2457 2728 3059 3456 3925
// 13 2197   | 2198 2205 2224 2261 2322 2413 2540 2709 2926 3197 3528 3925 4394
//
//  The table can be extended for as many rows and columns as needed. The lower
//  left triangle of the table is a mirror image of the upper right triangle.
//  Thus, the lower left triangle can be ignored.
//
//  Within the upper right triangle, we want to look for two identical numbers.
//  After some  searching, we note that the number 1729 appears twice. It is
//  found at row 1, column 12; and again at row 9, column 10. Thus 1^3 + 12^3
//  equals 9^3 + 10^3 equals 1729. Hence, 1729 is a Ramanujan number. If we
//  infinitely increased the size of the table, we could find an infinite
//  number of other paired cube sums. Also, we could find an infinite number of
//  "triples". The bad news is that the first of these "Ramanujan triples"
//  occurs at:
//  (Row 228, Column 423), (Row 167, Column 436), and (Row 255, Column 414)
//  for 228^3 + 423^3  =  167^3 + 436^3  =  255^3 + 414^3, which all share a
//  common cell entry of 87,539,319.
//
//  If we are to extend the process of finding additional Ramanujan triples or
//  even higher order matches (e.g. Ramanujan quadruples), three major problems
//  become apparent. 1) The table will become very large. 2) The search time
//  will become prohibitive. 3) The size of the numbers in the cells will
//  run into precision problems. (Too many digits for standard computer
//  hardware.)
//
//  We note that numbers in the table are confined to specific areas. Numbers
//  from 1 to 1,000 appear only in the upper left corner. Numbers between 1,000
//  and 2,000 occur in a band that extends from upper right to lower left.
//  Numbers between 2,000 and 3,000 exist only in another band that begins off
//  the right side of the table and extends down to the left. If we are looking
//  for possible number matches, we only have to look at one band at a time.
//
//  The program sequentially generates these bands. Each new band is used for
//  the current search process. Then this old band is discarded and a new band
//  is generated. The problem then is to search all of the numbers within a
//  band to see if duplicates exist. The example above uses a band width of
//  1,000 for the search area. The program initialially uses 10 billion for
//  the band width (for 4 & 5 pair combinations), but since the density of the
//  I^3 + J^3 sums decreases with larger numbers, this band width is allowed
//  to expand with time.
//
//  The program generates a little over 2.4 million numbers at a time for each
//  new band. (Stabilizes at this rate after a few dozen iterations.) These
//  numbers are inserted into a hash table, and then the hash table is searched
//  to see if duplicate entries exist. If there are enough entries for any hash
//  number, then the associated link list of results for this hash number are
//  searched for actual solutions.
//
//  The algorithm (especially the hash index portion) is very efficient and
//  appears to be at least 10 times faster than the "heap" algorithm used by
//  David Wilson who published the first Ramanujan quintuple.
//
//  If the search is continued to include the lowest known Ramanujan sextuple,
//  (= Taxicab(6)), numbers in the table would have 23 decimal digits. No
//  simple data representation (or standard computer hardware) has this much
//  precision. Thus numbers are split into two pieces. One part includes the
//  rightmost 9 decimal digits and is maintained as "int" variables. The
//  remaining leftmost 14 decimal digits are maintained as "double" variables.
//  The integer portion does double duty as it is used to construct the hash
//  indexes.
//
//  The program has been updated from an old ANSI "C" version that ran under
//  DOS on a 80486 computer. (And that was a copy of a version that ran on a
//  80386 computer, and that was a copy of the original that I wrote for a
//  32032 32-bit National Semiconductor co-processor board that I added to an
//  IBM PC-XT back in the early 80's. (Those were the days when you sold your
//  soul for 1 MB of direct RAM addressing - no PC/DOS segmentation. Anybody
//  remember what "EDLIN" was?)
//
//  This program may be used, copied, modified, etc. without any obligation by
//  any person for any not-for-profit purpose. I would appreciate that this or
//  any derivative version would include a note crediting me with the original
//  program/algorithm. (e.g. "Original algorithm by Bill Butler.")
//
//  Final note: The program runs best if you have >= 1 GB of RAM. It runs as is
//  under Windows XP when compiled by the lcc-win32 C compiler as a "console"
//  program.
//
//***************************************************************************



#include <stdheaders.h>         //  The usual stdio.h, stdlib.h, etc

            //  "ArrayLimit" controls how far you want to search. The program
            //  will search for Ramanujans up to ArrayLimit^3. (No other
            //  modifications to the code are needed.)
            //  DO NOT use anything > 30000000.
            //  At 30,000,000 for ArrayLimit, the author was able to run time
            //  trials up to 2.15E22, and successfully run a test to see if it
            //  would find the best known candidate for Taxicab(6). (Started a
            //  short distance lower than this.) However, when the program was
            //  running with "ArrayLimit" at 30,000,000 at the same time that
            //  several other programs were running, the author's computer
            //  (1 GB RAM) crashed and corrupted Norton's "Go Back" files.
            //  Norton's "System Works" had to be uninstalled and then
            //  reinstalled. (System "Commit Charge" was not known, but an
            //  overload is possible.)

#define ArrayLimit 10000000     //  Program will crash if/when search passes
                                //  ArrayLimit^3

                                //  Procedure declarations
void InitSys(void);             //  Initialize the program
void NextGroup(void);           //  Generate next band of numbers
void CheckGroup(void);          //  Search for duplicate entries
void MakeCube(int);             //  Cubes the integer and places the results
                                //  in global variables CubedHigh and CubedLow
void pausemsg(void);            //  Pauses the program at key points


                                //  Note: Each 10000000 increase in ArrayLimit
                                //  uses another 160 MB of RAM. ArrayLimit of
                                //  30000000 is good enough for Taxicab(6).
                                //  (But estimated run time is 7 years.)
double NcubedHigh[ArrayLimit+1];//  NcubedHigh[i] = leftmost 14 digits of i^3
int NcubedLow[ArrayLimit+1];    //  NcubedLow[i] = 9 rightmost digits of i^3
                                //  These arrays are used to look up the cubes
                                //  of numbers when forming the I^3 + J^3 sums
int NextJ[ArrayLimit+1];        //  Keeps track of the next "J" to try when
                                //  forming trial I^3 + J^3.

                                //  The size of the next 2 arrays matches
                                //  the 22 bit hash size. Link lists for
                                //  the data arrays below start here.
unsigned HashHd[4194304];       //  Link heads for hash table.
int ChainLen[4194304];          //  Chain length.

                                //  As trial I^3 + J^3 numbers are generated
                                //  for each new "band"/group, they are
                                //  stored in these link lists. (Purists might
                                //  want to use a structure array, but time
                                //  trials for both encoding methods showed
                                //  that simple arrays execute faster.)

double I3J3High[3000000];       //  Leftmost 14 digits of I^3 + J^3
int I3J3Low[3000000];           //  9 rightmost digits of I^3 + J^3
int Ival[3000000];              //  The "I" in I^3 + J^3
int Jval[3000000];              //  The "J" in I^3 + J^3
int Link[3000000];              //  Link lists.

double CubedHigh;               //  The MakeCube() routine is passed an integer
int CubedLow;                   //  number. It cubes this number and places the
                                //  lowest (rightmost) 9 decimal digits in
                                //  CubedLow and the remaining digits in
                                //  CubedHigh. These are then copied into the
                                //  Ncubed arrays.

char Databuff[100];             //  Dummy array for user input.

int NbrPairs;                   //  User input for minimum number of pairs
                                //  required for output display. (=2,3,4,or 5)

double InitValues[10] = {       //  Initial upper limit & increment. Will keep
    0.0, 0.0, 2000.0,           //  output display in roughly sorted order.
    20000000.0,
    10000000000.0,
    10000000000.0 };

double UpperLim;                //  For each new group, find cube sums up to
                                //  this limit. UpperLim increases by
double Increment;               //  "Increment" for each new group. In turn,
                                //  "Increment" intermittently increases as
                                //  array storage allows. "Increment" is the
                                //  same as the "band width" phrase used in
                                //  the Excel Spreadsheet example.

int NbrStored;                  //  Nbr. of items in hash table/I3J3 arrays.
unsigned Bit22Mask = 4194303;   //  Mask for 22 bit index into Hash Table

int StatusFlag;                 //  Set by user for display/no-display of
                                //  status data while program runs.




int main(void) {

  InitSys();                        //  Initialize system.

  while(1) {                        //  Do until user stops the program
    NextGroup();                    //  Form next group of cube sums.
    CheckGroup();                   //  Look for matches.
                                    //  Process a little over 2,400,000
    if (NbrStored < 2400000)        //  trial I^3 + J^3 each iter.
      Increment *= 1.05;            //  Increases by 5 % as array space allows
    UpperLim += Increment;          //  Set up for next group

    if (StatusFlag) {               //  Optional status check
      printf("Upper Limit is now %g\n", UpperLim);
      printf("Increment is now %g\n", Increment);
    }
  }
  return 0;
}



//****************************************************************************
//
//                                    InitSys
//
//  This routine initializes the system. The Ncubed[] arrays are filled with
//  cubes such that NcubedHigh[i]*E9 + NcubedLow[i] = I^3. 23+ digits of
//  precision can be handled.
//
//  Note: The program allows you to begin your search at any arbitrary
//  starting point. Thus, 2 or more computers could each be running the program
//  to simultaneously search different zones in the number field.
//
//  The NcubedLow[] array contains the integer bit version of the last 9
//  decimal digits of all the I^3's. These will be used to form a hash index.
//  The hash index system greatly speeds up the process of finding matching
//  pairs of I^3 + J^3 = K^3 + L^3, etc. (The actual hash index adds the bit
//  portions of I^3 + J^3, and uses bits 8 to 29 of the result as the hash
//  index. Note: The least significant bit is bit "0".)
//
//  The NextGroup() routine will generate a large group of trial I^3 + J^3
//  numbers. The "J's" that will be used in this routine will be >= "I" until
//  the sum of I^3 + J^3 reaches the upper limit for the current group. (Group
//  size is kept within bounds by stopping the process at "UpperLim".). This
//  routine initializes the NextJ[] array for this process.
//
//  "UpperLim" and "Increment" are initially set to 10 billion for the first
//  iteration. (Valid for 4 & 5 pairs. Lower values for pairs = 2 & 3).
//  Subsequently "UpperLim" will be increased by "Increment" to include larger
//  trial values of I^3 + J^3. The density of I^3 + J^3 numbers becomes sparser
//  as the number field expands. Therefore, "Increment" is allowed to become
//  larger with time. Thus, the number of trial I^3 + J^3 numbers that will be
//  looked at will gradually cluster at a little over 2.4 million per
//  iteration.
//
//**************************************************************************

void InitSys(void) {

  int i;
  double start, Difference, Idbl, Jcalc;

  puts("             ramanujans.c");
  puts("                 by");
  puts("             Bill Butler\n");

  puts("This program finds Ramanujan numbers.");
  puts("It will run until you manually stop the program.\n");

  puts("The number that you enter below will determine how many pairs");
  puts("are required to display the associated Ramanujan number.\n");

  puts("Enter 2 for output of 2 or more pairs (Pauses on 3 pairs)");
  puts("Enter 3 for output of 3 or more pairs (Pauses on 4 pairs)");
  puts("Enter 4 for output of 4 or more pairs (Pauses on 5 pairs)");
  puts("Enter 5 for output of 5 or more pairs (Pauses on 6 pairs)");
  puts("(For output from 2, 3, 4 use \"Pause\" key as needed)");

  gets(Databuff);
  NbrPairs = atoi(Databuff);


  start = ArrayLimit;                           //  Convert to double for calc
  printf("\nWhere do you want to start the search? (0 <= start <= %g)\n",
        0.999999 * start * start * start);
  puts("(Suggest a very small percent below true start point if > 0.)");
  gets(Databuff);
  start = atof(Databuff);

  puts("\nDo you want to display status results (1 for yes  0 for no)?");
  puts("(If yes, don't forget that real data may scroll off the screen.)");
  gets(Databuff);
  StatusFlag = atoi(Databuff);

  puts("\nInitializing the cubes table");
  puts("(Will take a few seconds.)\n");

  for (i = 1; i <= ArrayLimit; i++) {
    MakeCube(i);                                //  Calculates i^3
    NcubedHigh[i] = CubedHigh;                  //  Leftmost 14 digits
    NcubedLow[i] = CubedLow;                    //  Rightmost 9 digits

                                                //  Initialize NextJ[]
    Idbl = i;                                   //  Convert to double
    Difference = start - Idbl*Idbl*Idbl;        //  Derived from nbr = I^3+J^3
    if (Difference < 0.0)                       //  If calc will be negative
      NextJ[i] = i;                             //  then ordinary start point
    else {                                      //  Else calc which J to use
      Jcalc = pow(Difference, 1.0/3.0) + 1.0;   //  Calculated value for J.
                                                //  Adding 1.0 avoids an array
                                                //  overflow problem
      if (Jcalc > Idbl)                         //  If this is bigger than "i"
        NextJ[i] = Jcalc;                       //  use the calculated value
      else                                      //  Else
        NextJ[i] = i;                           //  use the normal value.
    }
    /*    Optional debug check
    printf("At i = %d NcubedHigh = %'.0lf * E9  NcubedLow = %'d  NextJ = %d\n",
        i, NcubedHigh[i], NcubedLow[i], NextJ[i]);
    */
  }

  UpperLim = InitValues[NbrPairs] + start;      //  Initial upper limit.
  Increment = InitValues[NbrPairs];             //  Initial increment.

  puts("Starting search\n");
}



//*************************************************************************
//
//                                NextGroup
//
//  This routine generates the next group of I^3 + J^3 sums and places these
//  sums in the hash arrays. The number of these trial "I^3 + J^3" sums that
//  are processed will average a little over 2.4 million.
//
//*************************************************************************

void NextGroup(void) {

  int Count, i, j;
  unsigned i3j3sumLow;                  //  Does double duty as hash index
  double LimNbr, i3j3sumHigh;           //  Forces "LimNbr" to a "Register"
                                        //  position. Otherwise "UpperLim"
                                        //  could be used.

  for (i = 4194303; i >= 0; i--) {      //  Clear old garbage.
    HashHd[i] = 0;
    ChainLen[i] = 0;
  }
  Count = 0;                            //  Count nbr. of I^3+J^3 in the group
                                        //  and where to put data
                                        //  Note: Usage of the "i" & "j" vars.
                                        //  in this loop matches the "I" & "J"
                                        //  row/col labels in the "Excel
                                        //  Spreadsheet" example.
  i = 1;                                //  First "I" for I^3 (Start on row 1)
  LimNbr = UpperLim;                    //  Sets up reg. variable
  do {                                  //  Do for all "i" in group (Will move
                                        //  down until I^3 + J^3 is too big)
    j = NextJ[i];                       //  First "J" for J^3 (Leftmost column
                                        //  for current row in current group)
                                        //  Do for all "J" such that
    while(1) {                          //  I^3 + J^3 is < UpperLim
      i3j3sumHigh = NcubedHigh[i] + NcubedHigh[j];    //  Forms I^3 + J^3
      i3j3sumLow = NcubedLow[i] + NcubedLow[j];
      if (i3j3sumLow >= 1000000000) {   //  If carry overflow (>= 1 billion),
        i3j3sumLow -= 1000000000;       //  decrease integer portion by 1e9
        i3j3sumHigh += 1.0;             //  and increment the "billions"
      }
                                        //  If within upper limit then
      if ((i3j3sumHigh * 1.0E9 + i3j3sumLow) < LimNbr) {
        Count++;                        //  include it in the group.
        I3J3High[Count] = i3j3sumHigh;  //  Add to the hash arrays.
        I3J3Low[Count] = i3j3sumLow;
        Ival[Count] = i;
        Jval[Count] = j;
        i3j3sumLow >>= 8;               //  Generate the
        i3j3sumLow &= Bit22Mask;        //  hash index

        Link[Count] = HashHd[i3j3sumLow];    //  Update link list
        HashHd[i3j3sumLow] = Count;
        ChainLen[i3j3sumLow]++;
        j++;                            //  Move 1 col to right in
      }                                 //  "Excel spreadsheet"
      else                              //  Repeat until too big
        break;
    }
    NextJ[i] = j;                       //  Set up for next group. Move down
    i++;                                //  1 row in "Excel spreadsheet".
  } while (j > i);                      //  Loop exits when right edge of
                                        //  band/group intercepts the sloping
                                        //  diagonal in the spreadsheet. At
                                        //  this point, "i" will equal "j".

  NbrStored = Count;
                                        //  Optional status check.
                                        //  Averages ~2,400,000+ per crack.
  if (StatusFlag) {
    printf("This iter. stored %'d trial I^3 + J^3 sums\n", NbrStored);
    puts("Must stay < 3,000,000\n");
  }
}



//************************************************************************
//
//                                CheckGroup
//
//  This routine checks the hash arrays to see if any matches exist. If the
//  quantity of numbers stored in any hash link list is >= the user defined
//  display number, an actual Ramanujan solution may exist. If true, the
//  link list chain is checked to see if at least "NbrPairs" entries are
//  identical. If true, then the information is output.
//
//  The variable "NbrPairs" (see start of program) controls how many pairs
//  have to exist for the Ramanujan number before this info is output.
//
//************************************************************************

void CheckGroup(void) {

  int HashIndex, Ilink, Jlink;
  int Count;
  int StopNbr;
                                            //  For all hash heads
  for (HashIndex = 0; HashIndex <= 4194303; HashIndex++) {
    if ((ChainLen[HashIndex] - NbrPairs) < 0)    //  Chain is too short for output.
      continue;
                                            //  Optional check to see if
                                            //  hash algorithm is efficient.
/*
    printf("Link list[%d] has %d members\n", HashIndex,    ChainLen[HashIndex]);
*/
                                            //  Check the list for this hash.
                                            //  StopNbr controls how many times
                                            //  that "Ilink" moves forward
    StopNbr = ChainLen[HashIndex] - NbrPairs;
    for (Ilink = HashHd[HashIndex]; StopNbr >= 0;
            StopNbr--, Ilink = Link[Ilink]) {
      Count = 1;                            //  Will count number of identical
                                            //  I3J3 sums
      for (Jlink = Link[Ilink]; Jlink; Jlink = Link[Jlink]) {
        if (I3J3Low[Jlink] != I3J3Low[Ilink])    //  Not a match if either is
          continue;                              //  different.
        if (I3J3High[Jlink] != I3J3High[Ilink])
          continue;
                                        //  If to here, the I3J3 sum at Jlink
                                        //  matches the I3J3 sum at Ilink
        Count++;
      }
      if (Count < NbrPairs)                 //  If not enough pair matches,
        continue;                           //  then keep looking.

      printf("\n%d pairs exist at Ramanujan Number:    %'.0lf * E+9 + %'d\n",
        Count, I3J3High[Ilink], I3J3Low[Ilink]);
      for (Jlink = Ilink; Jlink; Jlink = Link[Jlink]) {
        if (I3J3Low[Jlink] != I3J3Low[Ilink])    //  Both must match for a
          continue;                              //  paired solution
        if (I3J3High[Jlink] != I3J3High[Ilink])
          continue;
        printf("   Pair at  I = %'d   J = %'d\n", Ival[Jlink], Jval[Jlink]);
      }
      if (Count > NbrPairs)                 //  Pause if big match
        pausemsg();
    }
  }
}



//*************************************************************************
//
//                                    MakeCube
//
//  This routine cubes the passed integer number and places the lowest 9
//  decimal digits of the result in the global integer variable "CubedLow"
//  and the high 14 digits into CubedHigh (double). Subsequently these
//  results are loaded into the Ncubed arrays.
//
//  The multiplication process is similar to ordinary base 10 arithmetic
//  (and its associated "carry") except base 10,000,000 is used.
//
//  The passed number "AnInteger" is known to be <= 3E7. This is converted
//  to a "double" number which can be safely squared without any precision
//  problems. This result is then split into three seperate sections that
//  have the equivalent of 7 decimal digits each. Each of these can be safely
//  multiplied by the original "AnInteger" again without any precision error.
//
//  Finally, the end result is placed into two variables with the lowest 9
//  decimal digits stored in one variable and the high 14 digits in the other.
//  These two variables are then placed in the global variables "CubedHigh"
//  and "CubedLow". (The latter becomes an integer variable.)
//
//**************************************************************************

void MakeCube(int AnInteger) {


  double HighDigits, MidDigits, LowDigits, temp, Original;

                                        //  "AnInteger" will be <= 3E7. Thus
                                        //  there is enough precision in an
                                        //  ordinary "double" variable for
                                        //  the first multiplication.
  Original = AnInteger;                 //  Convert to "double"
  temp = Original * Original;           //  Initially this will be <= 9E14
                                        //  Split it into high, mid, low digits
  LowDigits = fmod(temp, 10000000.0);   //  These will be the low 7 digits
  MidDigits = (temp - LowDigits) / 10000000.0;    //  This is the "carry"
                                        //  Now reduce MidDigits to 7 digits
  temp = fmod(MidDigits, 10000000.0);   //  This will be the middle 7 digits
  HighDigits = (MidDigits - temp) / 10000000.0;    //  Another "carry"
  MidDigits = temp;                     //  At this point "AnInteger" has been
                                        //  been squared. The lowest 7 digits are
                                        //  in "LowDigits", the next 7 digits are
                                        //  in "MidDigits", and the remaining
                                        //  digits are in "HighDigits".
  LowDigits *= Original;                //  Mult. all three by "Original" to get
  MidDigits *= Original;                //  cube. Then will have to sort out the
  HighDigits *= Original;               //  pieces. After this multiplication, the
                                        //  true cubed result would be:
                                        //  HighDigits*E14+MidDigits*E7+LowDigits

  temp = fmod(MidDigits, 100.0);        //  Get last 2 digits from MidDigits
  MidDigits -= temp;                    //  Remove last two digits
  MidDigits /= 100.0;                   //  Shift right two decimal digits
                                        //  so it measures "Billions"
  LowDigits += 10000000.0 * temp;       //  All 9 low digits are in LowDigits
                                        //  (But still has some higher digits)

  temp = fmod(LowDigits, 1000000000.0); //  These are the final lowest 9 digits
  MidDigits += (LowDigits - temp) / 1000000000.0;    //  Add carry to Mid Digits
  MidDigits += 100000.0 * HighDigits;   //  The 14 high digits are in place

  CubedHigh = MidDigits;                //  Store final result
  CubedLow = temp;                      //  Also converts it to an integer
}




//******************************************************************
//
//                    Misc. Routines
//
//******************************************************************

void pausemsg(void) {

  puts("\nLarge number of pairs exist");
  puts("Press RETURN to continue");
  gets(Databuff);
}