Listing 1: tsqrt function and test program
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
static unsigned short linearInterpolation(unsigned short, unsigned short,
unsigned short, int);
/* Lookup table: table[i] = 128*16*SquareRoot(i) */
static unsigned short table[129];
static const unsigned short *pTable = table;
/**********
* Initialize the lookup table
***********/
static void initialize_table(void) {
int i;
for (i=0; i<129; i++)
table[i] = (unsigned short) (sqrt((double)i) * (128*16) + 0.5);
}
/**********
* Calculate scaled square root
* result = 128 * SquareRoot(input)
***********/
unsigned short tsqrt(
unsigned short x /* Integer whose square root is desired */
) {
unsigned short result;
if (x <= 127)
result = (pTable[(int)x] + 8) / 16;
else if (x <= 511)
result = (linearInterpolation(x, 128, 4, 32) + 4) / 8;
else if (x <= 2047)
result = (linearInterpolation(x, 512, 16, 32) + 2) / 4;
else if (x <= 8191)
result = (linearInterpolation(x, 2048, 64, 32) + 1) / 2;
else if (x <= 32767)
result = linearInterpolation(x, 8192, 256, 32);
else if (x <= 65535)
result = (unsigned short) (linearInterpolation(x, 32768, 1024, 32) * 2);
else
result = 128*256; /* How did this happen? */
return result;
}
/**********
* Perform linear interpolation:
* result has same scaling as the table entries.
***********/
static unsigned short linearInterpolation(
unsigned short x, /* Integer whose square root is desired */
unsigned short min, /* Minimum end of this range */
unsigned short dx, /* x1-x0 for this range */
int base /* base index for this range */
) {
int index0;
unsigned short x0, y0, y1, y;
index0 = (int) (((x - min) / dx) + base);
x0 = (unsigned short) ((index0 - base) * dx + min);
y0 = pTable[index0];
y1 = pTable[index0+1];
y = (unsigned short) (((long)(x - x0) * (y1 - y0) + (long)(y0*dx) +
(dx/2)) / dx);
return y;
}
/**********
* Initialize the lookup table,
* Compute error and percent error over entire input domain.
***********/
void main(void) {
long maxErrorInteger[6];
double maxPercentErrorInteger[6];
double maxErrorValue[6];
double maxPercentErrorValue[6];
int subdomain;
long x;
/* Initialize the lookup table */
initialize_table();
/* Clear the maximum error arrays */
for (subdomain=0; subdomain<6; subdomain++) {
maxErrorInteger[subdomain] = 0;
maxPercentErrorInteger[subdomain] = 0;
maxErrorValue[subdomain] = 0;
maxPercentErrorValue[subdomain] = 0;
}
/* Test tsqrt() results, saving maximum error in each subdomain */
for (x=0,subdomain=0; x<65536; x++) {
long errorInteger;
double percentErrorInteger, errorValue, percentErrorValue;
double tableValue, goldenValue;
unsigned short tableInteger, goldenInteger;
tableInteger = tsqrt((unsigned short)x);
goldenValue = sqrt((double)x);
tableValue = (double)tableInteger / 128.;
goldenInteger = ((unsigned long) (goldenValue * (128*16) + 0.5) + 8) / 16;
errorInteger = (long)goldenInteger - (long)tableInteger;
if (errorInteger < 0) errorInteger = -errorInteger;
if (goldenInteger == 0)
percentErrorInteger = 0;
else
percentErrorInteger = (double)errorInteger /
(double)goldenInteger * 100;
errorValue = goldenValue - tableValue;
if (errorValue < 0) errorValue = -errorValue;
if (goldenValue == 0)
percentErrorValue = 0;
else
percentErrorValue = errorValue / goldenValue * 100;
if (errorInteger > maxErrorInteger[subdomain])
maxErrorInteger[subdomain] = errorInteger;
if (percentErrorInteger > maxPercentErrorInteger[subdomain])
maxPercentErrorInteger[subdomain] = percentErrorInteger;
if (errorValue > maxErrorValue[subdomain])
maxErrorValue[subdomain] = errorValue;
if (percentErrorValue > maxPercentErrorValue[subdomain])
maxPercentErrorValue[subdomain] = percentErrorValue;
if ((x == 127) || (x == 511) || (x == 2047) || (x == 8191) ||
(x == 32767))
subdomain++;
}
(void) printf(" Integer Floating Point\n");
(void) printf("Range maxError maxPercentError maxError
maxPercentError\n");
for (subdomain=0; subdomain<6; subdomain++) {
(void) printf("%3d %d %8f%% %8f %8f%%\n",
subdomain, maxErrorInteger[subdomain], maxPercentErrorInteger[subdomain],
maxErrorValue[subdomain], maxPercentErrorValue[subdomain]);
}
}