#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#define RANDOMSEED 15021965
#define VALUESEED 12135172739435486027ull
#define NUMVALUES 1024
typedef unsigned short UINT16;
#define MAX_UINT16 USHRT_MAX
#ifdef MSFT_CC
typedef unsigned __int64 UINT64;
#else
typedef unsigned long long UINT64;
#endif
int numBitsSet[MAX_UINT16];
UINT64 minTerm[64];
/*
*
* This program generates 64-bit hashkey-tables with a
* guaranteed minimum Hamming distance.
*
* According to R. W. Hamming, 1950, the Hamming distance between two
* numbers is the number of different bit positions in their binary
* representation. Example: the Hamming distance of 17 and 18 is 2:
*
* 17 ^= 1001
* 18 ^= 1010
* ^^
* The Hamming distance of a set of numbers is the smallest Hamming
* distance of all pairs of the set.
*
* I recommend to generate tables with a Hamming distance of 24.
*
* @author Raimund Heid, Feb 16 1999
*
*/
/*
* Count the number of bits set in 'v'. This routine is only
* used to generate a table.
*/
UINT16 countNumberOfSetBits(UINT64 v)
{
int count = 0, i;
for (i = 0; i < 16; i++)
{
count += (v >> i) & 1;
}
return (UINT16) count;
}
/*
* Get the number of bits set in 'v'.
*/
int getNumberOfSetBits(UINT64 v)
{
return numBitsSet[v & 0xFFFF] + numBitsSet[(v >> 16) & 0xFFFF] +
numBitsSet[(v >> 32) & 0xFFFF] + numBitsSet[(v >> 48) & 0xFFFF];
}
/*
* Check if 'candidate' would be a legal member in 'v': see if
* it differs in at least 'minDistance' bit positions from every
* value in 'v'.
*/
int isLegalMember(UINT64 candidate, UINT64 v[NUMVALUES], int minDistance)
{
unsigned int i;
for (i = 0; i < NUMVALUES; i++)
{
if (getNumberOfSetBits(candidate ^ v[i]) < minDistance)
{
return 0;
}
}
return 1;
}
/*
* Generate a set of Hamming numbers.
*
* @param amount the amount of numbers in the set
* @param minDistance the minimum Hamming distance between all pairs
* in the set.
*/
void getHammingNumbers(UINT64 vector[NUMVALUES], int minDistance)
{
const UINT64 MAX16 = 0xFFFF;
UINT64 min = 1, nextCandidate = VALUESEED, i;
int j;
for (i = 0; i <= MAX16; i++)
{
numBitsSet[i] = countNumberOfSetBits(i);
}
for (j = 0; j < 64; j++)
{
minTerm[j] = min;
min *= 2;
}
for (j = 0; j < NUMVALUES; j++)
{
nextCandidate ^= minTerm[rand() % 64];
while (!isLegalMember(nextCandidate, vector, minDistance))
{
nextCandidate ^= minTerm[rand() % 64];
}
vector[j] = nextCandidate;
printf("*");
fflush(stdout);
if (j % 100 == 0 && j > 0)
{
printf(" %d ", j);
fflush(stdout);
}
}
printf("\n");
}
/*
* Generate a C/C++ header file and write the generated Hamming numbers
* into an array definition.
*/
void generateHeaderFile(const char *filename, int distance)
{
UINT64 vector[NUMVALUES];
FILE *file;
int ap = 0;
unsigned int j, k;
getHammingNumbers(vector, distance);
file = fopen(filename, "wb");
fprintf(file, "/* Generated file -- do not edit! */\n");
fprintf(file, "/* Hamming distance: %d */\n\n", distance);
fprintf(file, "UINT64 GENERATED_KEYTABLE[16][64] ={");
for (j = 0; j < 16; j++)
{
fprintf(file, "\n{");
for (k = 0; k < 64; k++)
{
fprintf(file, "%lluull, ", vector[ap++]);
if (k % 2 == 1)
{
fprintf(file, "\n");
}
}
fprintf(file, "}");
if (j < 15)
{
fprintf(file, ",");
}
}
fprintf(file, "};\n\n");
fclose(file);
}
/*
* Read some arguments from the command line and start the whole stuff.
*/
int main(int argc, char *argv[])
{
int distance = 24;
srand(RANDOMSEED);
if (argc == 3)
{
int arg = atoi(argv[2]);
distance = (arg > 0 ? arg : distance);
generateHeaderFile(argv[1], distance);
}
else
{
printf("usage: hamming <filename> <distance>\n");
return -1;
}
return 0;
}