Durango Bill’s
“C” Program to generate Cabtaxi Numbers
(Source Code)
Return to the main
Ramanujan page
Web page generated via KompoZer
//*****************************************************************************
//
//
Cabtaxi.c
//
by
//
Bill Butler
//
// May 5, 2008 version (as opposed to multiple earlier versions)
//
// This program finds CabTaxi numbers where the number can be formed in at
// least 7 different ways by either the sum of two cubes and/or the difference
// of two cubes. The tables below illustrate low orders of CabTaxi numbers.
// (Specifically CabTaxi(2) and CabTaxi(3)).
//
// For the sum of two cubes, 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 = 0, 1, 2, 3, 4, etc.
// and the 2nd column gives the cube for each of these numbers: 0, 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
//
J^3 1 8 27 64
125 216 343 512 729 1000 1331 1728
// I I^3 -------------------------------------------------------------
//
0 0 |
1 8 27 64 125
216 343 512 729 1000 1331 1728
//
1 1 |
2 9 28 65 126
217 344 513 730 1001 1332 1729
//
2 8 | 9
16 35 72 133 224 351
520 737 1008 1339 1736
//
3 27 | 28
35 54 91 152 243 370
539 756 1027 1358 1755
//
4 64 | 65
72 91 128 189 280 407
576 793 1064 1395 1792
//
5 125 | 126 133 152 189
250 341 468 637 854 1125 1456 1853
//
6 216 | 217 224 243 280
341 432 559 728 945 1216 1547 1944
//
7 343 | 344 351 370 407
468 559 686 855 1072 1343 1674 2071
//
8 512 | 513 520 539 576
637 728 855 1024 1241 1512 1843 2240
// 9 729 | 730 737 756 793 854 945 1072 1241 1458 1729 2060 2457
// 10 1000 | 1001 1008 1027 1064 1125 1216 1343 1512 1729 2000 2331 2728
// 11 1331 | 1332 1339 1358 1395 1456 1547 1674 1674 1843 2060 2331 2662
// 12 1728 | 1729 1736 1755 1792 1853 1944 2071 2240 2457 2728 3059 3456
//
// We note that except for the "0" row, the upper right triangle is a mirror
// image of the lower left triangle. Thus, from here on, we will ignore the
// lower left triangle.
//
// This next table is similar to the table above except the values are the
// differences of two cubes. Specifically, the values in the table equal
// I^3 - J^3. If the upper right triangle were included, it would just give
// the negative values of those seen in the lower left triangle.
//
//
J 0 1
2 3 4
5 6 7
8 9 10 11 12
//
J^3 0 1 8
27 64 125 216 343 512 729
1000 1331 1728
// I I^3 ------------------------------------------------------------------
// 0 0 | 0
// 1 1 | 1 0
// 2 8 | 8 7 0
// 3 27 | 27 26 19 0
// 4 64 | 64 63 56 37 0
// 5 125 | 125 124 117 98 61 0
// 6 216 | 216 215 208 189 152 91 0
// 7 343 | 343 342 335 316 279 218 127 0
//
8 512 | 512 511 504 485
448 387 296 169 0
//
9 729 | 729 728 721 702
665 604 513 386 217 0
//
10 1000 | 1000 999 992 973
936 875 784 657 488 271
0
// 11 1331 | 1331 1330 1323 1304 1267 1206 1115 988 819 602 331 0
// 12 1728 | 1728 1727 1720 1701 1664 1603 1512 1385 1216 999 728 397 0
//
// Note: Additional diagrams in the NextGroup() routine show how these tables
// are processed.
//
// CabTaxi(2) is defined as the lowest number that can be formed by the sum
// and/or difference of 2 cubes in two different ways. (Ignore the zeros in
// table 2.)
//
// If we search the upper right portion of the first table and also search the
// lower table, we find that the lowest number that appears exactly twice is
// 91. It appears at row 3 column 4 in the first table and row 6 column 5 in
// the second table.
//
// Thus CabTaxi(2) = 91
// = 3^3 + 4^3
// = 6^3 - 5^3
//
// Similarly the two tables can be searched for the lowest number that appears
// three times - which turns out to be 728.
//
// Thus CabTaxi(3) = 728
// = 6^3 + 8^3 Row 6 column 8 in the first table
// = 9^3 - 1^3 Row 9 column 1 in the second table
// = 12^3 - 10^3 Row 12 column 10 in the second table
//
// The process can be extended to higher orders for CabTaxi(N). Of course the
// tables above would have to be extended to much larger sizes.
//
// If we are to extend the process of finding additional CabTaxi numbers to
// higher order matches (e.g. CabTaxi(10)), three major problems become
// apparent.
// 1) The tables 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 two tables are confined to specific areas. In
// the first table, 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.
//
// Similar sloping bands exist in the second table, but these slope from upper
// left to lower right.. We also note that bands for the difference of two
// cubes will tend to parallel the main diagonal. Thus processing within the
// program for the difference of two cubes will sequentially search down the
// diagonals whereas the search for the sum of two cubes portion will
// sequentially search down the columns.
//
// The program sequentially generates these bands. The new bands (one from the
// I^3 + J^3 table and another from the I^3 - J^3 table) are used for the
// current search process. Then these old bands are discarded and new bands
// are generated for the next batch. 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 initially uses
// ~600 billion for the band width (see IncLkUp[] table), but since the
// density of both the I^3 + J^3 and I^3 - J^3 pairs decreases with larger
// numbers, the magnitude of the numbers that define a band width is allowed
// to expand with time.
//
// The "NextGroup()" routine generates about 10 to 40 million (depends on
// MaxHashData) I^3 and J^3 sums / differences for each new band/group.
// (Stabilizes at this rate after a few iterations.) As these numbers are
// generated they are inserted into a hash table. (The hash index uses bits
// 16 to 39 (see below) (16 to 40 on the Skulltrail) of the sum / differences
// of the two cubes.) Actual storage is via link lists that begin at each hash
// index.
//
// After a group has been generated, the "CheckGroup()" routine checks the
// number of entries that have been stored in each of the link lists that
// begin at each hash index. If there are at least "N" entries in any link
// list ("N" was entered by the user), then the CheckGroup() routine also
// checks the link list to see how many of these also match the rest of the
// bits for the sum-of-cubes / difference-of-cubes. If there are at least "N"
// of these, then a solution has been found.
//
// Components within the I^3 + J^3 sums and I^3 - J^3 differences become much
// larger than any standard computer hardware can handle. Thus these large
// cubes are separated into sections that can be handled by ordinary 16, 32
// and 64 bit integer arithmetic. Large numbers are represented as follows:
//
//
//
<---- Bit ID's within variables ---->
//
//
63
24 23
0
15 0
// ------------------------------------------ --------------
//
|
high bits |
Hash | | Low 16 bits |
// ------------------------------------------ --------------
//
79
40 39
16
15 0
//
//
<---- Bit ID's within a number
---->
//
// The above variables are unsigned 64 and 16 bit integers. The Skulltrail
// uses a larger hash index of 0 to 24 instead of the 0 to 23 shown above.
//
// The combined 64 + 16 = 80 bits can represent numbers up to 2^80 ~= 1.2E+24
//
// Note: Only the low 16 bits, the Hash bits, and the next 32 bits are saved
// for the result so the output results can only go to 2^(16 + 24 + 32) = 2^72
// = 4.72E21.
//
// However, the program will crash if/when the search goes past ArrayLimit^3.
// (ArrayLimit can be increased as needed.)
//
// The search can begin at any location above 1.0E+14
//
//
// Programmer's notes:
//
// The program will run as is if it is compiled and run via
// the lcc win32 "C" compiler.
// http://www.cs.virginia.edu/~lcc-win32/
// http://www.q-software-solutions.de/downloaders/get_name
//
// The compiled version will require over 400 MB of RAM. If you have more RAM
// memory, the program will run faster if you increase the numbers in the
// "#define" statements as suggested below. No other changes to the code are
// needed.
//
// The program uses "Global Variables" as they are an efficient memory storage
// system if the program is a stand-alone system. Global variables are not
// recommended for larger projects.
//
// CabTaxi(7) = 11,302,198,488 ~= 1.13E+10
// CabTaxi(8) = 137,513,849,003,496 ~= 1.37E+14
// CabTaxi(9) = 424,910,390,480,793,000 ~= 4.249E+17
// CabTaxi(10) <= 933,528,127,886,302,221,000 <= 9.336E+20
// CabTaxi(11) <= 261,858,398,098,545,372,249,216 <= 2.62E+23
//
//***************************************************************************
#include
<stdheaders.h>
// The usual stdio.h, stdlib.h, etc
// "ArrayLimit"
controls how far you want to search. The program
// will search
for CabTaxis up to ArrayLimit^3. (and then crash
// without
warning.) Both ArrayLimit and MaxHashData can be
// increased as
memory allows. (Optional increases in IncLkUp[].)
// No other modifications to the code are needed
// Skulltrail
is using 9800000
#define ArrayLimit 6000000 // This is the Pentium 4 version that
//
only searches to 2.16E20
// Program will crash if/when
// search
passes ArrayLimit^3
// Must stay
below (2^80)^(1/3)
// = 106,528,681
// Increase
this number if you have
// the
available RAM.
#define MaxHashData 13000000 // Skulltrail is using 40000000
// If
possible/convenient, "MaxHashData"
// will be
optimal if it is a little
// larger than "HashSize"
// Increase this number if
you have
// the available RAM.
#define HashSize
16777216
// Skulltrail is using 33554432 (2^25)
#define HashMask (HashSize-1)
#define
NbrHashBits 24
// Programmer must make sure that these
// are coordinated powers of
2.
// Procedure
declarations
void
InitSys(void);
// Initialize
the program
void
NextGroup(void);
// Generate next band of numbers
void
CheckGroup(void);
// Search for duplicate entries
void
Solution(int, int);
// Called by CheckGroup() to
output a
// solution..
void Bin2Dbl(unsigned long long, unsigned short); // Converts 2-piece binary
// to 2-piece
"double"
void
UpdtUpperLim(void);
// Update Upper Limit and Increment
void
MakeCube(int);
// Cubes the
integer and places the
// results in
global variables
//
"High64bits", and "Low16bits"
void CalcCubeDiff(unsigned long long, int);
// Two integers
are passed to the routine.
// "X" and
"dx". The routine calculates
// the
difference of (X + dx)^3 - X^3
// and places
the result in High64bits and
// Low16bits.
void
CalcIandJ(int);
// Reconstructs the I and J values
that
// were part of
the original I^3 +/- J^3
//
sums/differences
long long GCD(long long, long long);
// Finds the
Greatest Common Divisor of
// the two
parameters and returns this GCD
void
PauseMsg(void);
// Pauses the program at key points
//
NcubedHigh[i] = Bits 16 to 79 of I^3
unsigned long long NcubedHigh[ArrayLimit+1];
unsigned short NcubedLow[ArrayLimit+1]; // NcubedLow[i] = 16 rightmost bits of
// I^3. The
above arrays are used to look
// up the cubes
of numbers when forming
// the I^3 +
J^3 sums.
int
NextI[ArrayLimit+1];
// Keeps track of the next "I" to
try when
// forming
trial I^3 + J^3 sums.
int
LowestJ;
// Lowest J to use for each call to
// NextGroup().
"J" is an index into
// NextI[]
long long NextJforDiag[ArrayLimit+1]; // Note: The rows and columns in
// the I^3 -
J^3 table will extend beyond
// 2^32. Thus
can't use 32 bit integers.
// Keeps track
of where to start for each
// diagonal
when generating the I^3 - J^3
// differences.
Processing usage is
// similar to
that for NextI[] except I^3
// - J^3 goes
down the diagonals.
// If "I" - "J"
= 1, then diagonal = 1
// If "I" - "J"
= 2, then diagonal = 2
// etc.
unsigned
long long NextDiagI3J3[ArrayLimit+1];
// When I^3-J^3 becomes too
// big for
current Diagonal, save it for
// the next
call to NextGroup()
unsigned short NextDiagLow16[ArrayLimit+1]; // Same for the low 16 bits
// The size of
the next 2 arrays matches
// the hash
index/mask size. Link lists
// for the
match tests (below) start here.
unsigned HashHd[HashSize]; // Link heads for hash table.
unsigned short ChainLen[HashSize]; // Chain length.
// As trial I^3
+ J^3 and I^3 - J^3 numbers
// are formed
for each new "band"/group,
// pertinent
data is stored in these link
// lists.
// The
following arrays can contain up to
// 13,000,000
elements on the Pentium 4,
// and
40,000,000 for the Skulltrail
int
IorDiag[MaxHashData];
// For I^3 + J^3 sums, this
contains the
// value for
"I". For I^3 - J^3, the value
// of the
diagonal is stored as a negative
// number.
Specifically this will equal
// J - I.
int
Link[MaxHashData];
// Links for link lists.
unsigned HighBits[MaxHashData]; // Bits above the hash index are
// stored here.
unsigned short Lowest16bits[MaxHashData]; // Low16bits are bits 0 to 15 from
// the I^3 +
J^3 and I^3 - J^3 results.
unsigned long long High64bits; // The MakeCube()and CalcCubeDiff()
unsigned
short Low16bits;
// routines store their results here.
long
long Ival;
// The
CalcIandJ() routine reconstructs
long
long Jval;
// the I
and J that were used for I^3 +/-
// J^3. The
results are stored here.
double
DblHigh;
// 2
piece binary numbers are converted to
double
DblLow;
//
decimal numbers such that the true
// number
equals DblHigh * 1.0E9 + DblLow.
// DblLow will
contain the decimal digits
// for units,
thousands, and millions,
// while
DblHigh will contain the decimal
// digits for
"billions" and higher.
long
long PairAtI[100];
// Solutions are stored here
long long PairAtJ[100];
char
Databuff[100];
// Dummy array for user
input.
unsigned
NbrPairs;
// User input for
minimum number of pairs
// required for
output display. (>= 7)
unsigned long long UpperLim; // For each new group, find cube sums/
// differences
up to this limit.
// UpperLim
increases by
unsigned long long 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.
// Note, the
lowest 16 bits of the I^3,
// J^3 calcs
are truncated for these
// calculations.
// The
Increment Look Up array is used to give
// "Increment"
a good running head start for any
// arbitrary
starting point.
// Note: If you
have to decrease "MaxHashData" to
// something
below 13000000 due to memory
//
restrictions, you will also have to decrease the
// numbers in
this look-up table
// Optional
increase if you increase "MaxHashData"
// Skulltrail
is about double the following
double IncLkUp[] = { // Multiply these values by 65,536 to get
// the true
size for "Increment".
1.0E7,
// Start = 1.0E14 to 1.0E15
2.0E7,
// Start = 1.0E15 to 1,0E16
4.5E7,
// Start = 1.0E16 to 1.0E17
1.0E8,
// Start = 1.0E17 to 1,0E18
2.0E8,
// Start = 1.0E18 to 1.0E19
4.5E8,
// Start = 1.0E19 to 1,0E20
1.0E9,
// Start = 1.0E20 to 1.0E21
2.0E9,
// Start = 1.0E21 to 1,0E22 (Not used)
4.0E9,
// Start = 1.0E22 to 1.0E23 (Not used)
8.0E9
// Start = 1.0E23 to 1.0E24 (Not used)
};
int
NbrStored;
//
Nbr of items in hash table/I3J3 arrays
int
StatusFlag;
// Set by
user for display/no-display of
// status data
while program runs.
int
MaxMultiple;
// Ask user for
the largest multiple
// to output in
the solutions.
// e.g. Enter
"1" for primitives only
// or 10,000
for all solutions.
int
SolNbr;
// This is output info that counts the
// number of
"N-way" solutions for the
// current
program run.
time_t
ltime;
// Used to get the time
double
OldTime, NewTime;
// Used to calculate the search
rate
double OldDblHigh, NewDblHigh;
int main(void) {
InitSys();
// Initialize system.
while(1) {
// Do until user stops the program
NextGroup();
// Form next
group of cube sums & diff.
CheckGroup();
// Look for
matches.
// Process up
to 13,000,000
UpdtUpperLim();
// trial I^3 + J^3 plus I^3
- J^3
// each iter.
(40,000,000 on Skulltrail)
// Increment
increases by 1/128 as
// array space
allows.
if (StatusFlag) {
// Optional status
check
Bin2Dbl(UpperLim, 0);
printf("Upper Limit is now %15.7g\n", DblHigh * 1.0E9);
Bin2Dbl(Increment, 0);
printf("Increment is now %15.7g\n", DblHigh * 1.0E9);
PauseMsg();
// Can optionally take this out,
but be
}
// ready to use
the "Pause" key
}
return 0;
}
//****************************************************************************
//
//
InitSys
//
// This routine initializes the system. The Ncubed[] arrays are filled with
// cubes such that NcubedHigh[i]*(2^16) + NcubedLow[i] = i^3. There is no
// overflow / precision problem up to 2^80 ~= 1.2089E+24. Alternately, this
// could allow "ArrayLimit" to have as many as 106,528,681 elements.
//
// Note: The program allows you to begin your search at any arbitrary
// starting point. Thus, 2 or more computers/cores could each be running the
// program to simultaneously search different zones in the number field.
//
// When the I^3 + J^3 sums and differences are formed, they are split into two
// pieces. The lowest 16 bits are in an unsigned short variable and the
// remaining bits are in a 64 bit unsigned long long variable. The lowest 24
// bits of this long long variable are used as a hash index. (Skulltrail
// version uses 25 bits.)
//
// The hash index system greatly speeds up the process of finding matching
// pairs of I^3 + J^3 = K^3 + L^3, = M^3 - N^3, etc.
//
// The NextGroup() routine will generate a large group of trial I^3 + J^3
// sums and I^3 - J^3 differences.
//
// For the I^3 + J^3 portion of the search, for each column, the search starts
// at either
//
// 1) row 0
// or
// 2) where it stopped on the last iteration
//
// and sequences down until either
//
// 1) the I^3 + J^3 sum exceeds the Upper Limit
// or
// 2) the downward search reaches the main diagonal.
//
// This routine initializes the NextI[] array such that the search will
// "start" at "where it stopped on the last iteration".
//
// The I^3 - J^3 portion of the search searches sequentially down each
// diagonal. The first diagonal searched is to the left of the main diagonal,
// the next one is to the left of the previous, etc. Within each diagonal,
// each call to NextGroup() starts where it left off last time (remembered in
// NextJforDiag[]) and continues down the diagonal until the I^3 - J^3
// difference reaches the current Upper Limit. This routine also initializes
// the NextJforDiag[] array using the user entered start point.
//
// The search can start at any number >= 1.0E+14. A good value for "Increment"
// is found via the IncLkUp[] table for any arbitrary starting point.
// 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 cluster just under 13 million per iteration. (Just
// under 40,000,000 on the Skulltrail.)
//
//**************************************************************************
void InitSys(void) {
int j, diag;
double a, b, c, result;
double start, limit, Jdbl, Icubed;
long long NextJ;
puts(" cabtaxi.c");
puts(" by");
puts(" Bill Butler\n");
puts("This program finds CabTaxi 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 CabTaxi number.\n");
puts("Enter 7 for output of 7 or more pairs");
puts("Enter 8 for output of 8 or more pairs");
puts("Etc.");
gets(Databuff);
NbrPairs = atoi(Databuff);
do {
puts("\nEnter a number for the largest multiple of a");
puts("primitive solution that you want to output.");
puts("For example: Enter \"1\" for primitives only");
puts("or Enter \"10000\" to output everything.");
puts("Hint: Use to control the rate that solutions are displayed");
gets(Databuff);
MaxMultiple = atoi(Databuff);
} while (MaxMultiple < 1);
limit = ArrayLimit;
// Convert to double for calc
limit *= 0.9999 * limit * limit;
do {
printf("\nWhere do you want to start the search? 1.0E+14 <= start <= %g\n",
limit);
puts("(Suggest a very small percent below true start point.)");
gets(Databuff);
start = atof(Databuff);
} while ((start < 1.0E+14) || (start > limit));
limit = 1.0e15;
// Look up value for "Increment"
j = 0;
// given this starting point.
while (start >= limit) {
j++;
limit *= 10.0;
}
Increment = IncLkUp[j];
// Both convert to long long
UpperLim = IncLkUp[j] + floor(start/65536.0);
// Multiply both "Increment" and
// UpperLim by 2^16 to get true
// size.
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\n");
for (j = 1; j <= ArrayLimit; j++) {
MakeCube(j);
// Calculates j^3
NcubedHigh[j] = High64bits;
// Leftmost 64 bits
NcubedLow[j] = Low16bits;
// Rightmost 16
bits
}
// Initialize the NextI[] array
LowestJ = ceil(cbrt(start/2.0)); // LowestJ marks where
// to start search on each call to
// NextGroup().
// Overwrite the default "0's" in NextI[] with the calculated next "I's"
// until the upward sloping curved line intersects the Row 0 line in the
// "Excel" diagram. The search will start at column J = LowestJ, and move
// right. The curved line traces: I^3 + J^3 = start. Thus for each "J"
// that will be used, we have to calculate the starting "I's" until the
// calculated "I" drops below 0.
j = LowestJ;
// This is the index
into NextI[]
Jdbl = j;
//
Floating point version for calcs
while (1) {
Icubed = start - Jdbl * Jdbl * Jdbl; // From: I^3 + J^3 = "start"
if (Icubed < 0.0)
// Not valid if result will
be < 0
break;
NextI[j] = ceil(cbrt(Icubed));
j++;
Jdbl += 1.0;
}
// Initialize arrays for diagonals
// To initialize the search for the I^3 - J^3 table, we have to find the
// location of the first element in each diagonal that is greater than the
// user entered "start" value. Each entry in the I^3 - J^3 array is
// calculated by I^3 - J^3 where the diagonal is I - J = "D".
//
// If we use an algegraic "X" for "J", then for each diagonal, we have to
// solve (X + D)^3 - X^3 - "start" = 0 for "X"
// and then use the next highest integer
//
// (X + D)^3 - X^3 - start = 0 expands to:
// (3)(X^2)(D) + (3)(X)(D^2) + D^3 - start = 0
//
// This can be solved for "X" via the "Quadratic Formula" where:
// A = 3D
// B = 3(D^2)
// C = D^3 - start
//
// Finally we find the integer ceiling for this result.
puts("Initializing the diagonal arrays\n");
for (diag = 1; ; diag++) {
// Sequentially move left until "J"
a = 3.0 * diag;
//
reaches column 0.
b = a * diag;
c = diag;
// Start by converting to a "double"
c *= c * c;
c -= start;
result = (-b + sqrt(b*b - 4*a*c)) / (2*a); // Quadratic formula
if (result < 0.0)
// (You should have paid attention)
break;
// (during your high school
algebra)
NextJ = ceil(result);
// (class)
NextJforDiag[diag] = NextJ;
CalcCubeDiff(NextJ, diag);
// Also set up for first round of
NextDiagI3J3[diag] = High64bits; // I^3 - J^3 differences.
NextDiagLow16[diag] = Low16bits;
}
for ( ;diag <= ArrayLimit; diag++) { // Initialize rest of I^3 - J^3 arrays
NextDiagI3J3[diag] = NcubedHigh[diag];
NextDiagLow16[diag] = NcubedLow[diag];
}
NewTime = (double) clock();
// Initialize for search rate
NewTime = NewTime / (double) CLOCKS_PER_SEC;
NewDblHigh = start / 1.0E9;
puts("\nThe search started at:");
time(<ime);
printf("%s\n", ctime(<ime));
}
//*************************************************************************
//
//
NextGroup
//
// This routine generates the next group of I^3 + J^3 sums and I^3 - J^3
// differences, and places these values in the hash arrays. The magnitude of
// the generated values will be larger than those generated in the last group,
// but will be limited by the current Upper Limit. The quantity of these trial
// "I^3 + J^3" sums and I^3 - J^3 differences will average just under 13
// million for each call to the routine. (Skulltrail version is just under 40
// million.)
//
// The diagrams below illustrate how the tables are processed to generate the
// current group. Both diagrams assume that the last round ended with an old
// Upper Limit of 501. The "Increment" is assumed to be 500 which produces a
// new Upper Limit of 1001.
//
//
J 1 2
3 4 5
6 7 8
9 10 11 12
//
J^3 1 8 27 64
125 216 343 512 729 1000 1331 1728
// I I^3 -------------------------------------------------------------
//
0 0 |
1 8 27 64 125
216 343 | | \|/ 1331
1728
//
1 1 |
2 9 28 65 126
217 344 | | 1001 1332 1729
//
2 8 | 9
16 35 72 133 224
351 | | 1008 1339 1736
//
3 27 | 28
35 54 91 152 243
370 | | 1027 1358 1755
//
4 64 | 65
72 91 128 189 280 407
| | 1064 1395 1792
//
5 125 | 126 133 152 189
250 341 468 | | 1125
1456 1853
//
6 216 | 217 224 243 280
341 432 | | \|/ 1216
1547 1944
//
7 343 | 344 351 370 407
468 559 \|/ \|/ 1072 1343 1674 2071
//
8 512 | 513 520 539 576
637 728 855 1024 1241 1512 1843 2240
// 9 729 | 730 737 756 793 854 945 1072 1241 1458 1729 2060 2457
// 10 1000 | 1001 1008 1027 1064 1125 1216 1343 1512 1729 2000 2331 2728
// 11 1331 | 1332 1339 1358 1395 1456 1547 1674 1674 1843 2060 2331 2662
// 12 1728 | 1729 1736 1755 1792 1853 1944 2071 2240 2457 2728 3059 3456
//
// The routine processes the columns in left to right order. The first element
// in each column that is processed is denoted by the tail of each arrow. If
// the old Upper Limit was 501, then all values less than 501 were processed
// in earlier rounds. In the current call to the routine, each column is
// processed downward until the new Upper Limit of 1001 is reached or until
// the main diagonal is reached. When processing reaches this limit, the
// number for the next lower row is saved in NextI[] to show where processing
// should begin on the subsequent call to the routine.
//
// The second table is similar to the table above except the values are the
// differences of two cubes. Specifically, the values in the table represent
// I^3 - J^3. Here, processing is along each diagonal from upper left to lower
// right. The rightmost diagonal is processed first followed by the other
// diagonals in right to left order. Diagonals are identified by a small
// integer (the ID number of the diagonal - which is equal I - J) instead of
// the arrows shown in the first diagram. Again, the elements that are
// processed are those that are >= the old Upper Limit of 501 and less than
// the new Upper Limit of 1001.
//
//
J 0 1
2 3 4
5 6 7
8 9 10 11 12
//
J^3 0 1 8
27 64 125 216 343 512 729
1000 1331 1728
// I I^3 ------------------------------------------------------------------
// 0 0 | 0
// 1 1 | 1 0
// 2 8 | 8 7 0
// 3 27 | 27 26 19 0
// 4 64 | 64 63 56 37 0
// 5 125 | 125 124 117 98 61 0
// 6 216 | 216 215 208 189 152 91 0
// 7 343 | 343 342 335 316 279 218 127 0
//
8 512 | 8
7 6 485 448 387
296 169 0
//
9 729 | 9
8 7 6
5 4 3 386
217 0
//
10 1000 | 10 9
8 7 6
5 4 3 488
271 0
//
11 1331 | 1331 1330 1323 1304 1267 1206 1115
4 3 2
331 0
//
12 1728 | 1728 1727 1720 1701 1664 1603 1512 1385
1216 3 2 397 0
//
(Long tail forms here)
// Note: The long tail will extend past 2^32. Thus long long integers are used.
//
// Each result that is used for the current round is stored in the hash arrays.
// The I^3 + J^3 or I^3 - J^3 result is split up as follows. Bits 0 to 15 are
// saved in the Lowest16bits[] array for later matching. Bits 16 to 39 are
// used for the hash index. (The Skulltrail version uses bits 16 to 40 for the
// hash index.) Bits 40 to 71 are saved in HighBits[]. For the I^3 + J^3
// calculations, "I" is saved as the first part of an I/J pair. For the
// I^3 - J^3 portion, the diagonal (equals I - J) is saved as a negative
// value.
//
//*************************************************************************
void NextGroup(void) {
int Count, i, j, diag;
long long LLj;
unsigned long long i3j3high;
unsigned work32;
Count = 0; // Count nbr. of I^3, J^3 results 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" examples.
// The routine processes I^3 + J^3 numbers first and then I^3 - J^3
// numbers
// The main loop for I^3 + J^3 portion has been split into two parts. In
// the first portion, the iterative step down each column in the "Excel
// spreadsheet" will run into the "main diagonal" which will terminate
// operations for this column. After the first few columns, the only exit
// condition will be the "if (i3j3high < UpperLim)" test. Thus the
// second portion of the code only tests this condition (slight reduction
// in code size speeds up the search).
j = LowestJ;
// Start at this J index
do { // Start "J" loop. Each "j" increment moves 1 col to right in the
// Excel table.
Will process all "i" for this col. until either
// i > j
(reach the diagonal) or reach UpperLim. This first
// portion of
the main loop will normally execute just a few times.
for (i = NextI[j]; i <= j; i++) {
work32 = NcubedLow[i] + NcubedLow[j]; // Start sum by adding low bits
i3j3high = (work32 >> 16);
// Forms "Carry"
i3j3high += NcubedHigh[i] + NcubedHigh[j]; // Then add high cubes
// If within upper limit then
if (i3j3high < UpperLim) {
// include it
in the group
Lowest16bits[++Count] = work32;
// Will use these for matches
HighBits[Count] = (i3j3high >> NbrHashBits);
IorDiag[Count] = i;
// Save the I that was used
work32 = i3j3high;
// Construct hash index
work32 &= HashMask;
// Just use low 24 bits
Link[Count] = HashHd[work32];
// Update link list
HashHd[work32] = Count;
ChainLen[work32]++;
// Increment count for link list
}
else
//
Repeat until too big
break;
}
// If loop ended by "i" test ("i" increased until it dropped below the
// diagonal in the "spreadsheet"), then "i" will equal "j" + 1. Else
// exit from loop was via "break" (sum of cubes exceeded upper limit),
// and "i" will be <= "j".
NextI[j] = i;
// Save for next group.
j++;
// Move right 1
col in spreadsheet.
if (i >= j)
// If won't use this "j" again.
LowestJ = j;
} while ((i + 2) > j);
// Loop exits
after the first couple
// of columns have been processed.
// "i + 2" is needed to prevent
// overshoot problem.
// When processing gets to here, then "i" did not reach the spreadsheet
// diagonal. Thus from here, the only test required will be that I^3
// plus J^3 reaches the upper limit.
do {
//
Continue with the other columns
// until I^3 + J^3 is > UpperLimit
// even with "i" = 0. This portion of
// the loop will execute millions of
// times.
i = NextI[j];
work32 = NcubedLow[i] + NcubedLow[j];
// Start sum by adding low bits
i3j3high = (work32 >> 16);
// Forms "Carry"
i3j3high += NcubedHigh[i] + NcubedHigh[j];// Then add high cubes
// Process all I^3 + J^3 in this
// column until too big, then move
// 1 column to the right.
while (i3j3high < UpperLim) {
Lowest16bits[++Count] = work32;
// Will use these for matches
HighBits[Count] = (i3j3high >> NbrHashBits);
IorDiag[Count] = i;
//
Save the I that was used.
work32 = i3j3high;
// Construct hash index
work32 &= HashMask;
//
Just use low 24 bits
Link[Count] = HashHd[work32];
// Update link list
HashHd[work32] = Count;
ChainLen[work32]++;
//
Increment count for link list
// Form I^3 + J^3 for next "I"
i++;
work32 = NcubedLow[i] + NcubedLow[j]; // Start sum by adding low bits
i3j3high = (work32 >> 16);
// Forms
"Carry"
i3j3high += NcubedHigh[i] + NcubedHigh[j]; // Then add cubes
}
// Repeat until too big
NextI[j] = i;
//
Save for next group.
j++;
// Move right 1
col in spreadheet.
} while (i);
// Loop exits when right edge of
// band/group intercepts
// Row = 0 in the spreadsheet.
// Now process the I^3 - J^3 portion
diag = 1;
// Init
for first diagonal
do {
// For all active diagonals
LLj = NextJforDiag[diag];
// Get next "J"
for this diagonal
i3j3high = NextDiagI3J3[diag];
// Get the i3j3 & Low16bits that
Low16bits = NextDiagLow16[diag];
// were too big on the last round
// Move down diagonal until I3J3
while (i3j3high < UpperLim) {
// is too big
Lowest16bits[++Count] = Low16bits; // Will use these for matches
HighBits[Count] = (i3j3high >> NbrHashBits);
IorDiag[Count] = -diag;
// Save the
diagonal as a negative
work32 = i3j3high;
// Construct hash index
work32 &= HashMask;
Link[Count] = HashHd[work32];
// Update link list
HashHd[work32] = Count;
ChainLen[work32]++;
// Increment count for link list
// Calculate next trial i3j3
LLj++;
// Move down
diagonal
CalcCubeDiff(LLj, diag);
// Find difference of
cubes
i3j3high = High64bits;
// Get high 64
bits
}
// Loop continues down diagonal
// until i3j3 is larger than U. L.
NextJforDiag[diag] = LLj;
// When too big,
save data for
NextDiagI3J3[diag] = i3j3high;
// next call to routine
NextDiagLow16[diag] = Low16bits;
diag++;
// Move
left to next diagonal
} while (LLj);
// Repeat until at left edge
NbrStored = Count;
// Optional status check.
// Averages just under 13,000,000 per
// crack. (40,000,000 for Skulltrail)
if (StatusFlag) {
printf("This iter. stored %'d trial I^3 +/- J^3 sums\n", NbrStored);
printf("Must stay < %'d\n", MaxHashData);
}
}
//************************************************************************
//
//
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 CabTaxi solution may exist. A count is then
// made to see how many exact matches exist. If the number of exact matches
// is >= "NbrPairs" (entered by the user) then a solution exists and the
// Solution() routine is called to display it.
//
// Statistician's note: The number of elements in the link list chains
// (= ChainLen[HashIndex]) will closely approximate "Poisson Distribution"
// where the mean will equal "NbrStored" / "HashSize". In turn "NbrStored"
// will average 3 to 4 percent under "MaxHashData".
// (The vast majority of the time, the portion of the code inside the
// "if (ChainLen[HashIndex] >= LocalPairs)" test will not execute.)
//
//************************************************************************
void CheckGroup(void) {
int Link1, Link2, Count, StopCount;
int register HashIndex, LocalPairs;
LocalPairs = NbrPairs;
// Setting this up as a local
// variable may speed up program
// For all hash heads
for (HashIndex = HashMask; HashIndex >= 0; HashIndex--) {
if (ChainLen[HashIndex] >= LocalPairs) {// If chain is long enough,
// check for a possible solution.
//
if (ChainLen[HashIndex] > 50)
// See if hashing is OK
// printf("ChainLen[%'d] = %d\n", HashIndex, ChainLen[HashIndex]);
// Check the list for this hash.
// StopCount controls how many
times
// that "Link1" moves forward
StopCount = ChainLen[HashIndex] - LocalPairs;
for (Link1 = HashHd[HashIndex]; StopCount >= 0;
StopCount--, Link1 = Link[Link1]) {
Count = 1;
// Will count number
of high and
// low matches
for (Link2 = Link[Link1]; Link2; Link2 = Link[Link2]) {
if (Lowest16bits[Link1] != Lowest16bits[Link2])
continue;
if (HighBits[Link1] == HighBits[Link2])
Count++;
// Increment
count if complete match
}
if (Count >= LocalPairs)
// If
true, then solution exists
Solution(HashIndex, Link1);
}
// End of search link list loop
}
// End of check ChainLen[] test
HashHd[HashIndex] = 0;
//
Clear garbage for next round
ChainLen[HashIndex] = 0;
}
}
//*************************************************************************
//
//
Solution
//
// This routine is called when a solution exists starting at the data
// referenced by the passed parameters.
//
//*************************************************************************
void Solution(int HashIndex, int Link1) {
int i, Count, Link2, GCDivInt;
long long GCDiv, work;
// Calculate the Cabtaxi number
work = HighBits[Link1];
// Reconstruct all the high bits
work <<= NbrHashBits;
work += HashIndex;
Bin2Dbl(work, Lowest16bits[Link1]); // Convert binary to "English"
Count = 1;
// Count number
of matches.
CalcIandJ(IorDiag[Link1]);
// Reconstruct
the original I & J
PairAtI[Count] = Ival;
// I for the first pair
PairAtJ[Count] = Jval;
// J for the first pair
for (Link2 = Link[Link1]; Link2; Link2 = Link[Link2]) {
// Must match both sections
if (Lowest16bits[Link2] != Lowest16bits[Link1])
continue;
if (HighBits[Link2] == HighBits[Link1]) {
Count++;
CalcIandJ(IorDiag[Link2]);
// Reconstruct the original I and
PairAtI[Count] = Ival;
// J for the
other pairs
PairAtJ[Count] = Jval;
}
}
// Get Greatest Common Divisor
GCDiv = GCD(PairAtI[Count], PairAtJ[Count]);
for (i = Count - 1; i; i--) {
GCDiv = GCD(GCDiv, PairAtI[i]);
GCDiv = GCD(GCDiv, PairAtJ[i]);
}
GCDivInt = GCDiv;
// Convert back to simple
integer
// If Greatest Common Divisor is
// <= the user-entered multiple
if (GCDivInt <= MaxMultiple) {
// size, then output the result.
if (Count >= 9)
// "Wake up" something
significant
puts("\n*************** AT LEAST A 9-WAY SOLUTION ****************");
SolNbr++;
printf("\nSolution Number %d\n", SolNbr);
printf("%d pairs exist at: %'.0lf * E9 + %'.0lf\n", Count, DblHigh, DblLow);
for (i = Count; i ; i--)
// Display all
pairs
printf(" Pair at I =
%16'lld J = %16'lld\n", PairAtI[i], PairAtJ[i]);
printf("The Greatest Common Divisor for this solution is: %'8d\n", GCDivInt);
time(<ime);
printf("%s", ctime(<ime));
OldTime = NewTime;
// Calculate and output
NewTime = (double) clock();
// the search rate
NewTime = NewTime / (double) CLOCKS_PER_SEC;
OldDblHigh = NewDblHigh;
NewDblHigh = DblHigh;
if (NewTime > (OldTime + 1.0))
printf("Search rate = %g per second\n\n",
1.0E9 * (NewDblHigh - OldDblHigh) / (NewTime - OldTime));
}
}
//*************************************************************************
//
//
MakeCube
//
// This routine cubes the passed integer number and places the lowest 16
// binary bits of the result in the global integer variable "Low16bits"
// and the remaing bits into High64bits (long long). The InitSys() routine
// loads these results into the Ncubed arrays.
//
// The multiplication process is carried out via 32 bit and 64 bit binary
// arithmetic with a final split of the lowest 16 bits into "Low16bits",
// and the remainder into "High64bits".
//
// The passed number "AnInteger" is known to be < 2^32. This is converted
// to a "long long" number which can be safely squared without any precision
// problems. This result is then split into two seperate 32-bit sections that
// are again converted to "long long" binary numbers. Each of these can be
// safely multiplied by the original "AnInteger" again without any precision
// error.
//
// Finally, the lowest 16 bits are placed in the global variable "Low16bits",
// and everything else is placed in "High64bits".
//
//**************************************************************************
void MakeCube(int AnInteger) {
unsigned long long UpperHalf, LowerHalf;
unsigned work;
// "AnInteger" will be < 2^32. Thus
// there is enough precision in an
// ordinary "long long" variable for
// the first multiplication.
UpperHalf = AnInteger;
// Convert to
"long long"
UpperHalf *= UpperHalf;
// Square it
// Split it into two pieces
work = UpperHalf;
// Get lowest 32 bits
LowerHalf = work;
// Lower Half has the lower 32 bits
UpperHalf >>= 32;
// Only the upper 32 bits remain
UpperHalf *= AnInteger;
// Form cube of
AnInteger
LowerHalf *= AnInteger;
Low16bits = LowerHalf;
// Only uses
last 16 bits
LowerHalf >>= 16;
// Get rid of lowest 16 binary bits
UpperHalf <<= 16;
// Align upper and lower bits
UpperHalf += LowerHalf;
// Add the two
sections
High64bits = UpperHalf;
// Store final
result
}
//**************************************************************************
//
//
CalcCubeDiff
//
// This routine calculates the difference between two cubes and places the
// results in global variables High64bits and Low16bits. A long long integer
// "X" and a regular integer "dx" are passed to the routine. The routine
// calculates (X + dx)^3 - X^3 and places the 64 high bits of the result in
// High64bits and the low 16 bits in Low16bits.
//
// For precision purposes, it is known that the result will be less than
// 1.0E24 ~= 2^80. Thus all component arithmetic will be OK as long as the
// max size stays within 80 bits.
//
// Instead of trying to calculate (X + dx)^3 - X^3 directly, the routine uses
// the following algebraic expansion:
//
// (X + dx)^3 - X^3
// = 3 * X^2 * dx + 3 * X * dx^2 + dx^3
// = (3 * X * dx) * (X + dx) + dx^3
//
//**************************************************************************
void CalcCubeDiff(unsigned long long X, int dx) {
unsigned long long SumHigh, SumLow;
unsigned long long Work;
// First, calculate (3 * X * dx)
SumHigh = X;
// Maximum of 35 bits
SumHigh *= (3 * dx);
//
Maximum of 35 + 2 + 24 = 61 bits
SumLow = SumHigh & 65535;
// Get low 16 bits
SumHigh >>= 16;
// Upper bits. SumHigh can never
// overflow since it is known that the
// result will be <= 80 bits, and
// SumHigh doesn't have the low 16 bits
Work = X + dx;
// Next term (Maximum of 35 bits)
SumHigh *= Work;
// Multiply both by (X + dx)
SumLow *= Work;
// Maximum of 16 + 35 bits
SumHigh += NcubedHigh[dx];
// Add both parts of dx^3
SumLow += NcubedLow[dx];
Low16bits = SumLow;
// Get the low 16 bits
SumLow >>= 16;
// Get rid of low 16 bits
SumHigh += SumLow;
// Add a big carry
High64bits = SumHigh;
// Save
rest of I^3 - J^3
}
//***************************************************************************
//
//
CalcIandJ
//
// In the NextGroup() routine, instead of saving both the I and J values
// (and both would have to be long long variables), the routine only stored
// I or the diagonal involved as normal integers. (If the diagonal was saved,
// it was saved as a negative value.) This saves a large amount of array space.
// However, this requires that the original "I" and "J" values must be
// reconstructed on the rare occasions when a solution is found.
//
// If the value in IorDiag[] was a positive value, then the original "I" was
// saved. In this case, the value for I will be less than 2^24. Thus to
// reconstruct the value for J, we use the equation I^3 + J^3 = solution
// value. "I" as stated above, was saved in IorDiag[] and the solution value
// has already been calculated as floating point numbers which have been
// stored in global variables "DblHigh" and "DblLow".
//
// If the value in IorDiag[] is negative, then the diagonal was saved as a
// negative value. Thus the original values for I and J in
// I^3 - J^3 = solution-value have to be calculated.
//
// In this case the value of the diagonal (as a positive value) equals I - J.
//
// The original equation
// I^3 - J^3 = solution value
// expands to:
// (J + diagonal)^3 - J^3 - solution value = 0
// which becomes:
// (3)(J^2)(diagonal) + (3)(J)(diagonal^2) + diagonal^3 - solution value = 0
// which can be solved for "J" via the quadratic formula.
// a = 3*diagonal
// b = 3*diagonal^2
// c = diagonal^3 - solution value
// J = (-b+sqrt(b*b - 4*a*c))/(2*a)
// and "I" will equal J + diagonal
//
// In both of the above cases, the resulting values for I and J are stored in
// Ival and Jval where they can be accessed by the solution routine.
//
//****************************************************************************
void CalcIandJ(int IorDiagonal) {
double Icubed, Jcubed, DblIorDiag;
double DblJ, a, b, c;
DblIorDiag = IorDiagonal;
//
Convert to a double
// If IorDiagonal is positive,
if (DblIorDiag >= 0.0) {
//
then get I and J for I^3 + J^3
Icubed = DblIorDiag * DblIorDiag * DblIorDiag;
// Then use: solution = I^3 + J^3
Jcubed = DblHigh*1.0E9 + DblLow - Icubed;
Jval = round(cbrt(Jcubed));
// Saves result and converts to LL
Ival = IorDiagonal;
// Also converts to long long
}
else {
// Else the diagonal was saved
DblIorDiag = -DblIorDiag;
// Convert to a
positive double
a = 3.0 * DblIorDiag;
b = a * DblIorDiag;
c = DblIorDiag * DblIorDiag * DblIorDiag - 1.0E9 * DblHigh - DblLow;
DblJ = (-b + sqrt(b*b - 4.0*a*c)) / (2.0*a);
Jval = -round(DblJ);
// Save as a negative value
Ival = round(DblJ + DblIorDiag);
}
}
//************************************************************************
//
//
Bin2Dbl
//
// This routine converts the 2-piece binary number that is passed to the
// routine to a 2-piece floating point number (each result piece is double).
// The two unsigned integers passed to the routine are components that
// would be a complete binary number represented by the following:
// Binary number = BigInteger * (2^16) + SmallInt.
// It is known that BigInteger is a 64 bit unsigned long long and
// SmallInt is an unsigned short. The whole purpose is to end up with
// something recognizable as a decimal number.
//
//************************************************************************
void Bin2Dbl(unsigned long long BigInteger, unsigned short SmallInt) {
double BilResult, UnitResult;
double BilIncr, UnitIncr;
unsigned long long work;
// First get the decimal value of
the
// small integer
BilResult = 0.0;
UnitResult = SmallInt; // SmallInt is < 2^16.
// Initialize increments for
decimal numbers
BilIncr = 0.0;
// These two are the decimal
equivalent
UnitIncr = 65536.0; // of 2^16.
work = BigInteger;
while (work) {
if (work & 1) {
// If rightmost
binary digit in work is a 1
BilResult += BilIncr;
// then add in the current increment
UnitResult += UnitIncr;
if (UnitResult >= 1.0E9) { // Check for carry
UnitResult -= 1.0E9;
BilResult += 1.0;
}
}
UnitIncr += UnitIncr;
// Double the increment values for the next
BilIncr += BilIncr; // round.
if (UnitIncr >= 1.0E9) {
UnitIncr -= 1.0E9;
BilIncr += 1.0;
}
work >>= 1;
// Shift next bit into position.
}
DblHigh = BilResult;
// Put result in global
variables
DblLow = UnitResult;
}
//**********************************************************************
//
//
UpdtUpperLim
//
// After each group of cube pairs has been generated and checked for
// duplicates, the number field is expanded so that a new group of paired
// cubes may be processed. The new group of candidates will exist in the
// number range bounded by "Old Upper Limit" to "New Upper Limit" where
// "New Upper Limit" = "Old Upper Limit" plus the current "Increment". The
// current Increment is allowed to increase with time so that the number of
// trial sums that are generated will stabilize at just under 13,000,000
// new candidates per iteration. (Just under 40,000,000 for Skulltrail.)
//
// Note: If UpperLimit and Increment were treated as full 80 bit binary
// numbers, the lowest 16 bits would have to be included. Since the program
// only deals with large numbers, the lowest 16 bits are truncated for the
// Upper Limit tests. As long as "Increment" is >= 2^7 (and it is initialized
// to much bigger than this), the incrementing process will proceed normally.
//
//**********************************************************************
void UpdtUpperLim(void) {
unsigned long long WorkBits;
// If the number of trial cube pairs stored on
// the last iteration was significantly less than
// the maximum that could be used without a
// MaxHashData overflow, then the increment can
// be increased by about 1/128 so that the next
// iteration will generate a larger group size.
if (NbrStored < (MaxHashData - MaxHashData/25)) {
WorkBits = Increment;
WorkBits >>= 7;
// Get 1/128 of the former Increment
Increment += WorkBits;
}
// Update UpperLimit with increment
UpperLim += Increment;
}
//******************************************************************
//
// Misc. Routines
//
//******************************************************************
/* This routine finds the greatest common divisor. */
long long GCD(long long IntOne, long long IntTwo) {
long long larger, smaller, Remainder;
if (IntOne < 0)
IntOne = -IntOne;
if (IntTwo < 0)
IntTwo = -IntTwo;
if (IntOne > IntTwo) {
larger = IntOne;
smaller = IntTwo;
}
else {
smaller = IntOne;
larger = IntTwo;
}
if (!smaller)
return(larger);
do {
Remainder = larger - smaller * (larger/smaller);
larger = smaller;
smaller = Remainder;
} while (smaller);
return(larger);
}
void
PauseMsg(void) {
// Pause before
displaying
// CRT data.
puts("\nPress RETURN to continue");
gets(Databuff);
}