See what's going on with flipcode!




This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Fixed Point Routines
  Submitted by



The following is an exercise in performance and accuracy of basic conversions from floating point to various fixed point formats, as well as a faster version of floor(), ceil() and a few others. Quite a few variants are offered. The results are tested against the compiler's native routines.

Some of the variants are little known techniques and use some tricky manipulation of the IEEE floating point values, without actually using the floating point unit. Also note that the timings listed in the file are for a standard Pentium. You may find that a PII or PIII will have drastically different results.

I wrote this during my DOS days with Watcom, which had a horrible 100+ cycle penalty for casting a float to an int. I still often use this stuff, even though I've abandoned fixed-point a long time ago. Just try replacing Visual Studio's __chop() routine with a faster equivalent and watch your performance go up.

Download Associated File: FConvert.cpp (40,657 bytes)

// ----------------------------------------------------------------------------
// Copyright 2000, Paul Nettle. All rights reserved.
//
// Fast floating point substitution routines
//
// This file has been entered into the public domain by the author.
// ----------------------------------------------------------------------------
//
//      COMPILE WITH WATCOM
//
// ----------------------------------------------------------------------------
//
//	Routine		Equivalent C code
//      -----------------------------------------
//	ICHOP		(int) value
//	FCHOP		(float) ((int) value)
//	IFLOOR		(int) floor(value)
//	FFLOOR		floor(value)
//	ICEIL		(int) ceil(value)
//	FCEIL		ceil(value)
//	FFRAC		value - floor(value)
//	SUB_PIX		ceil(value) - value
//	FTOX24		(int) (value * 0x1000000)
//	FTOX16		(int) (value * 0x10000)
//	FTOX8		(int) (value * 0x100)
//	IS_NEG		(bool) (value1 < 0.0f)
//	IS_LESS		(bool) (value1 < value2)
//	IS_LEQUAL	(bool) (value1 <= value2)
//	IS_GREATER	(bool) (value1 > value2)
//	IS_GEQUAL	(bool) (value1 >= value2)
//
// ----------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

// ---------------------------------------------------------------------------- #define ABS(a) ((a) < 0 ? -(a) : (a))

// ---------------------------------------------------------------------------- static unsigned char chptab[512]; static unsigned char f24tab[512]; static unsigned char f16tab[512]; static unsigned char fx8tab[512]; static unsigned int msktab[256]; static unsigned short _savedControl; static unsigned short _fchopControl; static unsigned short _ffloorControl; static unsigned short _fceilControl;

// ---------------------------------------------------------------------------- static unsigned int timerLo, timerHi, timerAdjust, writeValue;

static unsigned int _t_conv_int[2] = {0,0x43380000}; static unsigned int _t_conv24_08[2] = {0,0x42B80000}; static unsigned int _t_conv16_16[2] = {0,0x42380000}; static unsigned int _t_conv08_24[2] = {0,0x41B80000}; static unsigned int _t_fxfl[2];

// ---------------------------------------------------------------------------- void startTimer(); #pragma aux startTimer = \ "db 0x0F, 0x31" \ "mov timerLo,eax" \ "mov timerHi,edx" \ modify exact [edx eax];

// ---------------------------------------------------------------------------- int stopTimer(); #pragma aux stopTimer = \ "db 0x0F, 0x31" \ "sub eax,timerLo" \ value [eax] \ modify exact [edx eax];

// ---------------------------------------------------------------------------- short FINIT(); #pragma aux FINIT = \ "fstcw _savedControl" \ "mov ax, _savedControl" \ "and ax, 0xf3ff" \ "or ax, 0x0C00" \ "mov _fchopControl, ax" \ "and ax, 0xf3ff" \ "or ax, 0x0400" \ "mov _ffloorControl, ax" \ "and ax, 0xf3ff" \ "or ax, 0x0800" \ "mov _fceilControl, ax" \ parm nomemory caller [] \ modify nomemory exact [];

// ---------------------------------------------------------------------------- // This routine executes in approximately 16 cycles int ICHOP( float Val ); #pragma aux ICHOP = \ "fldcw _fchopControl" \ "fistp dword ptr writeValue" \ "mov eax,writeValue" \ value [eax] \ parm nomemory caller [8087] \ modify nomemory exact [eax 8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 21 cycles int ICHOP2( float Val ); #pragma aux ICHOP2 = \ "mov ebx,eax" \ "and eax,0x7fffff" \ "mov edx,ebx" \ "and ebx,0x7f800000" \ "shr ebx,23" \ "or eax,0x800000" \ "sar edx,31" \ "mov cl,chptab[ebx*2+1]" \ "sar eax,cl" \ "mov cl,chptab[ebx*2+0]" \ "sal eax,cl" \ "xor eax,edx" \ "sub eax,edx" \ value [eax] \ parm nomemory caller [eax] \ modify nomemory exact [eax ebx ecx edx];

// ---------------------------------------------------------------------------- // This routine executes in approximately 19 cycles float FCHOP( float Val ); #pragma aux FCHOP = \ "fldcw _fchopControl" \ "fistp dword ptr writeValue" \ "fild writeValue" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 30 cycles float FCHOP2( float Val ); #pragma aux FCHOP2 = \ "fldcw _fchopControl" \ "frndint" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 16 cycles int IFLOOR( float Val ); #pragma aux IFLOOR = \ "fldcw _ffloorControl" \ "fistp dword ptr writeValue" \ "mov eax,writeValue" \ value [eax] \ parm nomemory caller [8087] \ modify nomemory exact [eax 8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 16 cycles int IFLOOR2( float Val ); #pragma aux IFLOOR2 = \ "fldcw _ffloorControl" \ "fadd qword ptr _t_conv_int" \ "fstp qword ptr _t_fxfl" \ "mov eax,_t_fxfl" \ value [eax] \ parm nomemory caller [8087] \ modify nomemory exact [eax 8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 25 cycles int IFLOOR3( float Val ); #pragma aux IFLOOR3 = \ "mov ebx,eax" \ "and eax,0x7fffff" \ "mov edx,ebx" \ "and ebx,0x7f800000" \ "shr ebx,23" \ "or eax,0x800000" \ "sar edx,31" \ "mov esi,eax" \ "mov cl,chptab[ebx*2+1]" \ "sar eax,cl" \ "mov cl,chptab[ebx*2+0]" \ "sal eax,cl" \ "xor eax,edx" \ "sub eax,edx" \ "or edx,edx" \ "jz l1" \ "and esi,msktab[ebx * 4]" \ "jz l1" \ "dec eax" \ "l1:" \ value [eax] \ parm nomemory caller [eax] \ modify nomemory exact [eax ebx ecx edx esi];

// ---------------------------------------------------------------------------- // This routine executes in approximately 19 cycles float FFLOOR( float Val ); #pragma aux FFLOOR = \ "fldcw _ffloorControl" \ "fistp dword ptr writeValue" \ "fild writeValue" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 30 cycles float FFLOOR2( float Val ); #pragma aux FFLOOR2 = \ "fldcw _ffloorControl" \ "frndint" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 16 cycles int ICEIL( float Val ); #pragma aux ICEIL = \ "fldcw _fceilControl" \ "fistp dword ptr writeValue" \ "mov eax,writeValue" \ value [eax] \ parm nomemory caller [8087] \ modify nomemory exact [eax 8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 26 cycles int ICEIL2( float Val ); #pragma aux ICEIL2 = \ "or eax,eax" \ "jz l1" \ "mov ebx,eax" \ "and eax,0x7fffff" \ "mov edx,ebx" \ "and ebx,0x7f800000" \ "shr ebx,23" \ "sar edx,31" \ "or eax,0x800000" \ "mov esi,eax" \ "mov cl,chptab[ebx*2+1]" \ "sar eax,cl" \ "mov cl,chptab[ebx*2+0]" \ "sal eax,cl" \ "xor eax,edx" \ "sub eax,edx" \ "or edx,edx" \ "jnz l1" \ "and esi,msktab[ebx * 4]" \ "jz l1" \ "inc eax" \ "l1:" \ value [eax] \ parm nomemory caller [eax] \ modify nomemory exact [eax ebx ecx edx esi];

// ---------------------------------------------------------------------------- // This routine executes in approximately 19 cycles float FCEIL( float Val ); #pragma aux FCEIL = \ "fldcw _fceilControl" \ "fistp dword ptr writeValue" \ "fild writeValue" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 31 cycles float FCEIL2( float Val ); #pragma aux FCEIL2 = \ "fldcw _fceilControl" \ "frndint" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 22 cycles float FFRAC( float Val ); #pragma aux FFRAC = \ "fldcw _ffloorControl" \ "fist dword ptr writeValue" \ "fisub dword ptr writeValue" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 34 cycles float FFRAC2( float Val ); #pragma aux FFRAC2 = \ "fldcw _ffloorControl" \ "fld st(0)" \ "frndint" \ "fsubp st(1), st" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 22 cycles float SUB_PIX( float Val ); #pragma aux SUB_PIX = \ "fldcw _fceilControl" \ "fist dword ptr writeValue" \ "fisubr dword ptr writeValue" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 34 cycles float SUB_PIX2( float Val ); #pragma aux SUB_PIX2 = \ "fldcw _fceilControl" \ "fld st(0)" \ "frndint" \ "fsubrp st(1), st" \ value [8087] \ parm nomemory caller [8087] \ modify nomemory exact [8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 10 cycles int FTOX24( float Val ); #pragma aux FTOX24 = \ "fadd qword ptr _t_conv08_24" \ "fstp qword ptr _t_fxfl" \ "mov eax,_t_fxfl" \ value [eax] \ parm nomemory caller [8087] \ modify nomemory exact [eax 8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 21 cycles int FTOX242( float Val ); #pragma aux FTOX242 = \ "mov ebx,eax" \ "and eax,0x7fffff" \ "mov edx,ebx" \ "and ebx,0x7f800000" \ "shr ebx,23" \ "or eax,0x800000" \ "sar edx,31" \ "mov cl,f24tab[ebx*2+1]" \ "sar eax,cl" \ "mov cl,f24tab[ebx*2+0]" \ "sal eax,cl" \ "xor eax,edx" \ "sub eax,edx" \ value [eax] \ parm nomemory caller [eax] \ modify nomemory exact [eax ebx ecx edx];

// ---------------------------------------------------------------------------- // This routine executes in approximately 10 cycles int FTOX16( float Val ); #pragma aux FTOX16 = \ "fadd qword ptr _t_conv16_16" \ "fstp qword ptr _t_fxfl" \ "mov eax,_t_fxfl" \ value [eax] \ parm nomemory caller [8087] \ modify nomemory exact [eax 8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 21 cycles int FTOX162( float Val ); #pragma aux FTOX162 = \ "mov ebx,eax" \ "and eax,0x7fffff" \ "mov edx,ebx" \ "and ebx,0x7f800000" \ "shr ebx,23" \ "or eax,0x800000" \ "sar edx,31" \ "mov cl,f16tab[ebx*2+1]" \ "sar eax,cl" \ "mov cl,f16tab[ebx*2+0]" \ "sal eax,cl" \ "xor eax,edx" \ "sub eax,edx" \ value [eax] \ parm nomemory caller [eax] \ modify nomemory exact [eax ebx ecx edx];

// ---------------------------------------------------------------------------- // This routine executes in approximately 10 cycles int FTOX8( float Val ); #pragma aux FTOX8 = \ "fadd qword ptr _t_conv24_08" \ "fstp qword ptr _t_fxfl" \ "mov eax,_t_fxfl" \ value [eax] \ parm nomemory caller [8087] \ modify nomemory exact [eax 8087];

// ---------------------------------------------------------------------------- // This routine executes in approximately 21 cycles int FTOX82( float Val ); #pragma aux FTOX82 = \ "mov ebx,eax" \ "and eax,0x7fffff" \ "mov edx,ebx" \ "and ebx,0x7f800000" \ "shr ebx,23" \ "or eax,0x800000" \ "sar edx,31" \ "mov cl,fx8tab[ebx*2+1]" \ "sar eax,cl" \ "mov cl,fx8tab[ebx*2+0]" \ "sal eax,cl" \ "xor eax,edx" \ "sub eax,edx" \ value [eax] \ parm nomemory caller [eax] \ modify nomemory exact [eax ebx ecx edx];

// ---------------------------------------------------------------------------- bool IS_NEG( float Val ); #pragma aux IS_NEG = \ "shr eax,31" \ value [al] \ parm nomemory caller [eax] \ modify nomemory exact [eax];

// ---------------------------------------------------------------------------- bool IS_LESS( float Val1, float Val2 ); #pragma aux IS_LESS = \ "sub eax,ebx" \ "shr eax,31" \ value [al] \ parm nomemory caller [eax] [ebx]\ modify nomemory exact [eax];

// ---------------------------------------------------------------------------- bool IS_LEQUAL( float Val1, float Val2 ); #pragma aux IS_LEQUAL = \ "sub eax,ebx" \ "shr eax,31" \ value [al] \ parm nomemory caller [eax] [ebx]\ modify nomemory exact [eax];

// ---------------------------------------------------------------------------- bool IS_GREATER( float Val1, float Val2 ); #pragma aux IS_GREATER = \ "sub eax,ebx" \ "shr eax,31" \ value [al] \ parm nomemory caller [ebx] [eax]\ modify nomemory exact [eax];

// ---------------------------------------------------------------------------- bool IS_GEQUAL( float Val1, float Val2 ); #pragma aux IS_GEQUAL = \ "sub eax,ebx" \ "shr eax,31" \ value [al] \ parm nomemory caller [ebx] [eax]\ modify nomemory exact [eax];

// ---------------------------------------------------------------------------- void writeRead(); #pragma aux writeRead = \ "mov writeValue,eax" \ "mov ebx,writeValue" \ modify nomemory exact [eax ebx];

// ---------------------------------------------------------------------------- void readRead(); #pragma aux readRead = \ "mov eax,writeValue" \ "mov ebx,writeValue" \ modify nomemory exact [eax ebx];

// ---------------------------------------------------------------------------- void flushWriteBack(); #pragma aux flushWriteBack = \ "mov writeValue,eax" \ "mov writeValue,eax" \ "mov writeValue,eax" \ "mov writeValue,eax" \ "mov writeValue,eax" \ modify nomemory;

// ---------------------------------------------------------------------------- float makeTestValue() { // The formula for the test values uses three random values per // iteration in this way: (r1 - r2) * (r3 - r4) / r5 float r1 = rand(); float r2 = rand(); float r3 = rand(); float r4 = rand(); float r5 = rand();

// Make sure we don't get a divide by 0 while(!r5) r5 = rand();

// Make the test value return (r1 - r2) * (r3 - r4) / r5; }

// ---------------------------------------------------------------------------- void initFPU() { // Setup the tiny tables // // Yeah.. tables can suck for the cache, BUT, these tables only have // a used range of about 40 bytes someplace in the middle, and the most // commonly used portion of each table is within a single cache line, // so the cache thrashing is minimized. for (int e = 0; e < 256; e++) { int x = 150 - e; if (x > 31) x = 31; if (x < -31) x = -31; if (x < 0) chptab[e*2+0] = (unsigned char) -x; else chptab[e*2+1] = (unsigned char) x;

x = 150 - e - 24; if (x > 31) x = 31; if (x < -31) x = -31; if (x < 0) f24tab[e*2+0] = (unsigned char) -x; else f24tab[e*2+1] = (unsigned char) x;

x = 150 - e - 16; if (x > 31) x = 31; if (x < -31) x = -31; if (x < 0) f16tab[e*2+0] = (unsigned char) -x; else f16tab[e*2+1] = (unsigned char) x;

x = 150 - e - 8; if (x > 31) x = 31; if (x < -31) x = -31; if (x < 0) fx8tab[e*2+0] = (unsigned char) -x; else fx8tab[e*2+1] = (unsigned char) x;

x = 150 - e - 1; if (x > 31) x = 31; if (x < -31) x = -31; if (x < 0) msktab[e] = 0; else msktab[e] = (unsigned int) 0xffffffff >> (31 - x); }

// Finally, init the FPU routines FINIT(); }

// ---------------------------------------------------------------------------- void testICHOP(const int count) { printf( " Testing ICHOP...." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); int test = ICHOP(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) testValue; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testICHOP2(const int count) { printf( " Testing ICHOP2..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); int test = ICHOP2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) testValue; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFCHOP(const int count) { printf( " Testing FCHOP...." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FCHOP(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (int) ((float) testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFCHOP2(const int count) { printf( " Testing FCHOP2..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FCHOP2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (int) ((float) testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIFLOOR(const int count) { printf( " Testing IFLOOR..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); int test = IFLOOR(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) ((float) floor(testValue)); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIFLOOR2(const int count) { printf( " Testing IFLOOR2.." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); int test = IFLOOR2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) ((float) floor(testValue)); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIFLOOR3(const int count) { printf( " Testing IFLOOR3.." );

int expected = 0;

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); int test = IFLOOR3(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) ((float) floor(testValue)); slowTime += stopTimer() - timerAdjust;

// Expect -0.0f to return different results if ((*(unsigned int *) &testValue) == 0x80000000) expected++;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", expected == diffCount ? "OK":"ERROR!", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFFLOOR(const int count) { printf( " Testing FFLOOR..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FFLOOR(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (float) floor(testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFFLOOR2(const int count) { printf( " Testing FFLOOR2.." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FFLOOR2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (float) floor(testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testICEIL(const int count) { printf( " Testing ICEIL...." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); int test = ICEIL(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) ((float) ceil(testValue)); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testICEIL2(const int count) { printf( " Testing ICEIL2..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); int test = ICEIL2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) ((float) ceil(testValue)); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFCEIL(const int count) { printf( " Testing FCEIL...." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FCEIL(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (float) ceil(testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFCEIL2(const int count) { printf( " Testing FCEIL2..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FCEIL2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (float) ceil(testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFFRAC(const int count) { printf( " Testing FFRAC...." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FFRAC(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = testValue - (float) floor((double) testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFFRAC2(const int count) { printf( " Testing FFRAC2..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = FFRAC2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = testValue - (float) floor((double) testValue); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testSUB_PIX(const int count) { printf( " Testing SUB_PIX.." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = SUB_PIX(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (float) ceil((double) testValue) - testValue; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testSUB_PIX2(const int count) { printf( " Testing SUB_PIX2." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); float test = SUB_PIX2(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); float real = (float) ceil((double) testValue) - testValue; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIS_NEG(const int count) { printf( " Testing IS_NEG..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue = makeTestValue();

startTimer(); bool test = IS_NEG(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); bool real = testValue < 0.0f; slowTime += stopTimer() - timerAdjust;

if (test != real && *(int *) &testValue != 0x80000000) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIS_LESS(const int count) { printf( " Testing IS_LESS.." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue1 = makeTestValue(); float testValue2 = makeTestValue();

if (*(int *) &testValue1 == 0x80000000) testValue1 = 0.0f; if (*(int *) &testValue2 == 0x80000000) testValue2 = 0.0f;

if (testValue1 < 0.0f) testValue1 = -testValue1; if (testValue2 < 0.0f) testValue2 = -testValue2;

startTimer(); bool test = IS_LESS(testValue1, testValue2); fastTime += stopTimer() - timerAdjust;

startTimer(); bool real = testValue1 < testValue2; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIS_LEQUAL(const int count) { printf( " Testing IS_LEQ..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue1 = makeTestValue(); float testValue2 = makeTestValue();

if (*(int *) &testValue1 == 0x80000000) testValue1 = 0.0f; if (*(int *) &testValue2 == 0x80000000) testValue2 = 0.0f;

if (testValue1 < 0.0f) testValue1 = -testValue1; if (testValue2 < 0.0f) testValue2 = -testValue2;

startTimer(); bool test = IS_LEQUAL(testValue1, testValue2); fastTime += stopTimer() - timerAdjust;

startTimer(); bool real = testValue1 <= testValue2; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIS_GREATER(const int count) { printf( " Testing IS_GREAT." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue1 = makeTestValue(); float testValue2 = makeTestValue();

if (*(int *) &testValue1 == 0x80000000) testValue1 = 0.0f; if (*(int *) &testValue2 == 0x80000000) testValue2 = 0.0f;

if (testValue1 < 0.0f) testValue1 = -testValue1; if (testValue2 < 0.0f) testValue2 = -testValue2;

startTimer(); bool test = IS_GREATER(testValue1, testValue2); fastTime += stopTimer() - timerAdjust;

startTimer(); bool real = testValue1 > testValue2; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testIS_GEQUAL(const int count) { printf( " Testing IS_GEQ..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { float testValue1 = makeTestValue(); float testValue2 = makeTestValue();

if (*(int *) &testValue1 == 0x80000000) testValue1 = 0.0f; if (*(int *) &testValue2 == 0x80000000) testValue2 = 0.0f;

if (testValue1 < 0.0f) testValue1 = -testValue1; if (testValue2 < 0.0f) testValue2 = -testValue2;

startTimer(); bool test = IS_GEQUAL(testValue1, testValue2); fastTime += stopTimer() - timerAdjust;

startTimer(); bool real = testValue1 >= testValue2; slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFTOX24(const int count) { printf( " Testing FTOX24..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { enum {MAX_TESTVAL = RAND_MAX * RAND_MAX}; float testValue = (makeTestValue() / (float) MAX_TESTVAL) * 128.0f;

startTimer(); int test = FTOX24(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) (testValue * (float) 0x1000000); slowTime += stopTimer() - timerAdjust;

if (ABS(test - real) > 1) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFTOX242(const int count) { printf( " Testing FTOX242.." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { enum {MAX_TESTVAL = RAND_MAX * RAND_MAX}; float testValue = (makeTestValue() / (float) MAX_TESTVAL) * 128.0f;

startTimer(); int test = FTOX242(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) (testValue * (float) 0x1000000); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFTOX16(const int count) { printf( " Testing FTOX16..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { enum {MAX_TESTVAL = RAND_MAX * RAND_MAX}; float testValue = (makeTestValue() / (float) MAX_TESTVAL) * 32767.0f;

startTimer(); int test = FTOX16(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) (testValue * (float) 0x10000); slowTime += stopTimer() - timerAdjust;

if (ABS(test - real) > 1) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFTOX162(const int count) { printf( " Testing FTOX162.." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { enum {MAX_TESTVAL = RAND_MAX * RAND_MAX}; float testValue = (makeTestValue() / (float) MAX_TESTVAL) * 32767.0f;

startTimer(); int test = FTOX162(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) (testValue * (float) 0x10000); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFTOX8(const int count) { printf( " Testing FTOX8...." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { enum {MAX_TESTVAL = RAND_MAX * RAND_MAX}; float testValue = (makeTestValue() / (float) MAX_TESTVAL) * 8000000.0f;

startTimer(); int test = FTOX8(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) (testValue * (float) 0x100); slowTime += stopTimer() - timerAdjust;

if (ABS(test - real) > 1) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testFTOX82(const int count) { printf( " Testing FTOX82..." );

unsigned int fastTime = 0, slowTime = 0, diffCount = 0;

for (int i = 0; i < count; i++) { enum {MAX_TESTVAL = RAND_MAX * RAND_MAX}; float testValue = (makeTestValue() / (float) MAX_TESTVAL) * 8000000.0f;

startTimer(); int test = FTOX82(testValue); fastTime += stopTimer() - timerAdjust;

startTimer(); int real = (int) (testValue * (float) 0x100); slowTime += stopTimer() - timerAdjust;

if (test != real) diffCount++; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count);

printf( "Done. %s ticks: %d vs %d\n", diffCount ? "ERROR!":"OK", fastTime, slowTime); }

// ---------------------------------------------------------------------------- void testMemSpeed(const int count) { printf( " Testing mem spd.." );

unsigned int fastTime = 0, slowTime = 0, flushTime = 0;

for (int i = 0; i < count; i++) { startTimer(); readRead(); fastTime += stopTimer() - timerAdjust;

startTimer(); writeRead(); slowTime += stopTimer() - timerAdjust;

startTimer(); flushWriteBack(); flushTime += stopTimer() - timerAdjust; }

fastTime = (int) ((float) fastTime / (float) count); slowTime = (int) ((float) slowTime / (float) count); flushTime = (int) ((float) flushTime / (float) count);

printf( "Done. r/r ticks: %d w/r ticks: %d flush: %d\n", fastTime, slowTime, flushTime); }

// ---------------------------------------------------------------------------- void main(int argc, char *argv[]) { setbuf(stdout, 0);

// Warn the user about the /op option #ifndef __SW_OP printf( "---------------------------------------------------------\n" ); printf( "\aThis program was not compiled with /op. You can expect\n" ); printf( "problems since Watcom is less accurate without /op.\n " ); printf( "---------------------------------------------------------\n" ); printf( "\n" ); #endif

// Init the flaoting point routines initFPU();

// Calculate the timer routine overhead printf( "Syncronizing the timer..." );

int timerTestCount = 1000000;

for (int i = 0; i < timerTestCount; i++) { startTimer(); timerAdjust += stopTimer(); }

timerAdjust = (int) ((float) timerAdjust / (float) timerTestCount);

printf( "Done. Timer adjustment is %d cycles.\n", timerAdjust );

// Prime the random number generator srand(time(NULL));

// Get the run count int count = 1000000; if (argc > 1) count = atoi(argv[1]);

// Start testing printf( "Testing each routine with %d iterations.\n", count );

printf( "\nFastest routines:\n" );

testICHOP(count); testFCHOP(count); testIFLOOR(count); testFFLOOR(count); testICEIL(count); testFCEIL(count); testFFRAC(count); testSUB_PIX(count); testIS_NEG(count); testIS_LESS(count); testIS_LEQUAL(count); testIS_GREATER(count); testIS_GEQUAL(count); testFTOX24(count); testFTOX16(count); testFTOX8(count);

printf( "\nMedium-speed routines:\n" );

testICHOP2(count); testFCHOP2(count); testIFLOOR2(count); testFFLOOR2(count); testICEIL2(count); testFCEIL2(count); testFFRAC2(count); testSUB_PIX2(count); testFTOX242(count); testFTOX162(count); testFTOX82(count);

printf( "\nSlowest routines:\n" );

testIFLOOR3(count);

printf( "\nTesting memory:\n" );

testMemSpeed(count); }

// ----------------------------------------------------------------------------

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.