/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- main
- pick_com
- do_com
- do_add
- do_sub
- do_mul
- do_div
- do_eq
- do_lt
- do_gt
- do_le
- do_ge
- report_math
- report_comp
- get_num
- app_out
/* fxpstres - A program to stress test the fixed point math ('fxp') API.
Rick Smereka, Copyright (C) 2002-2004.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, get a copy via the Internet at
http://gnu.org/copyleft/gpl.html or write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston,
MA 02111-1307 USA
You can contact the author via email at rsmereka@future-lab.com
This program contains an infinite loop and will have to be
forced to terminate. The program works by picking a random
math operation/comparison, generating random floating point
numbers (in string form) and using the fixed point API ('fxp')
to carry out the operation/comparison.
Program syntax:
fxpstres
Output will be sent to 'stdout'. The personal logger may also
be used as the 'fxp' API is coded to write log messages if the
personal logger is enabled.
Original Linux version. Apr/2002, Rick Smereka
Ported to 32-bit Windows. May/2002, Rick Smereka
Ported to DOS and QNX 4.x. Jul/2002, Rick Smereka
Ported to Debian Linux. Jan/2003, Rick Smereka
Changed all logging calls to use the 'logman' API.
Changed all requests for a random number to use the
'rnd' function (in 'misc.c'). Dec/2004, Rick Smereka */
#include "stdhead.h"
/* global data */
long trans_no;
/* operation codes */
#define FXPS_ADD 1
#define FXPS_SUB 2
#define FXPS_MUL 3
#define FXPS_DIV 4
#define FXPS_EQ 5
#define FXPS_LT 6
#define FXPS_GT 7
#define FXPS_LE 8
#define FXPS_GE 9
#define FXPS_MAXCOM 9
#define VERSION "1.01.01-2004.12.21"
#define APNAME "fxpstres"
/* function prototypes */
int main(void);
int pick_com(void);
void do_com(int);
void do_add(struct fxp *, struct fxp *);
void do_sub(struct fxp *, struct fxp *);
void do_mul(struct fxp *, struct fxp *);
void do_div(struct fxp *, struct fxp *);
void do_eq(struct fxp *, struct fxp *);
void do_lt(struct fxp *, struct fxp *);
void do_gt(struct fxp *, struct fxp *);
void do_le(struct fxp *, struct fxp *);
void do_ge(struct fxp *, struct fxp *);
void report_math(struct fxp *, struct fxp *, struct fxp *, char);
void report_comp(struct fxp *, struct fxp *, int, char *);
int get_num(char *);
void app_out(char *,...);
int main(void)
{
int fxpcom;
/* if (logman_start("/work/logs/fxpstres.log", APNAME))
{
printf("error starting log\n");
return(0);
} */
srand((unsigned)time(NULL)); /* seed rnd gen */
trans_no = 1L;
/* build logo string based on platform */
#ifndef OS_UNIX
app_out("%s for %s Version %s", APNAME, PLATFORM_STRING, VERSION);
#else
app_out("%s for %s Version %s", APNAME, SUB_PLATFORM_STRING, VERSION);
#endif
app_out("By Rick Smereka, Copyright (c) 2002-2004");
app_out("%s comes with ABSOLUTELY NO WARRANTY", APNAME);
app_out("This is free software, and you are welcome to redistribute it");
app_out("under certain conditions; see 'gpl.txt' for information.");
/* main loop, infinite */
while(1)
{
fxpcom = pick_com();
trans_no++;
do_com(fxpcom);
}
if (logman_is_active())
logman_end();
return(0);
}
int pick_com(void)
{
/* Pick a random operation/comparison. */
int rnd_num;
rnd_num = rnd(1, FXPS_MAXCOM);
return(rnd_num);
}
void do_com(int com_num)
{
/* Dispatch command. */
struct fxp *fxp1, *fxp2;
char mname[] = "do_com", n1[10], n2[10];
logman("%s:enter", mname);
if (!get_num(n1))
{
logman("%s:exit:bad rc from get_num[n1]", mname);
return;
}
if (!get_num(n2))
{
logman("%s:exit:bad rc from get_num[n2]", mname);
return;
}
if ((fxp1 = fxp_iconv(n1)) == FXP_OT_NULL)
{
logman("%s:bad rc from fxp_iconv[fxp1]", mname);
return;
}
if ((fxp2 = fxp_iconv(n2)) == FXP_OT_NULL)
{
logman("%s:bad rc from fxp_iconv[fxp2]", mname);
fxp_free(fxp1);
return;
}
switch(com_num)
{
case FXPS_ADD:
do_add(fxp1, fxp2);
break;
case FXPS_SUB:
do_sub(fxp1, fxp2);
break;
case FXPS_MUL:
do_mul(fxp1, fxp2);
break;
case FXPS_DIV:
do_div(fxp1, fxp2);
break;
case FXPS_EQ:
do_eq(fxp1, fxp2);
break;
case FXPS_LT:
do_lt(fxp1, fxp2);
break;
case FXPS_GT:
do_gt(fxp1, fxp2);
break;
case FXPS_LE:
do_le(fxp1, fxp2);
break;
case FXPS_GE:
do_ge(fxp1, fxp2);
break;
default:
app_out("%s:unknown command[%d],ignoring", mname, com_num);
};
fxp_free(fxp1);
fxp_free(fxp2);
logman("%s:normal exit", mname);
}
void do_add(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point addition on two numbers. */
struct fxp *result;
char mname[] = "do_add";
logman("%s:enter", mname);
if ((result = fxp_add(fxp1, fxp2)) == FXP_OT_NULL)
{
app_out("%s:exit:bad rc from fxp_add[fxp1,fxp2]", mname);
return;
}
report_math(fxp1, fxp2, result, '+');
fxp_free(result);
logman("%s:normal exit", mname);
}
void do_sub(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point subtraction on two numbers. */
struct fxp *result;
char mname[] = "do_sub";
logman("%s:enter", mname);
if ((result = fxp_sub(fxp1, fxp2)) == FXP_OT_NULL)
{
app_out("%s:exit:bad rc from fxp_sub[fxp1,fxp2]", mname);
return;
}
report_math(fxp1, fxp2, result, '-');
fxp_free(result);
logman("%s:normal exit", mname);
}
void do_mul(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point multiplication on two numbers. */
struct fxp *result;
char mname[] = "do_mul";
logman("%s:enter", mname);
if ((result = fxp_mul(fxp1, fxp2)) == FXP_OT_NULL)
{
app_out("%s:exit:bad rc from fxp_mul[fxp1,fxp2]", mname);
return;
}
report_math(fxp1, fxp2, result, '*');
fxp_free(result);
logman("%s:normal exit", mname);
}
void do_div(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point division on two numbers. */
struct fxp *result;
char mname[] = "do_div";
logman("%s:enter", mname);
if ((result = fxp_div(fxp1, fxp2)) == FXP_OT_NULL)
{
app_out("%s:exit:bad rc from fxp_div[fxp1,fxp2]", mname);
return;
}
report_math(fxp1, fxp2, result, '/');
fxp_free(result);
logman("%s:normal exit", mname);
}
void do_eq(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point equality test. */
char mname[] = "do_eq";
int result;
logman("%s:enter", mname);
result = fxp_eq(fxp1, fxp2);
report_comp(fxp1, fxp2, result, "=");
logman("%s:normal exit", mname);
}
void do_lt(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point less than comparison. */
char mname[] = "do_lt";
int result;
logman("%s:enter", mname);
result = fxp_lt(fxp1, fxp2);
report_comp(fxp1, fxp2, result, "<");
logman("%s:normal exit", mname);
}
void do_gt(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point greater than comparison. */
char mname[] = "do_gt";
int result;
logman("%s:enter", mname);
result = fxp_gt(fxp1, fxp2);
report_comp(fxp1, fxp2, result, ">");
logman("%s:normal exit", mname);
}
void do_le(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point less than or equal comparison. */
char mname[] = "do_le";
int result;
logman("%s:enter", mname);
result = fxp_le(fxp1, fxp2);
report_comp(fxp1, fxp2, result, "<=");
logman("%s:normal exit", mname);
}
void do_ge(struct fxp *fxp1, struct fxp *fxp2)
{
/* Perform a fixed point greater than or equal comparison. */
char mname[] = "do_ge";
int result;
logman("%s:enter", mname);
result = fxp_ge(fxp1, fxp2);
report_comp(fxp1, fxp2, result, ">=");
logman("%s:normal exit", mname);
}
void report_math(struct fxp *f1, struct fxp *f2, struct fxp *result, char op)
{
/* Report the result of an math operation. */
char mname[] = "report_math", cf1[10], cf2[10], cr[10];
int out_scale;
logman("%s:enter", mname);
if (f1 == FXP_OT_NULL)
{
logman("%s:exit:null[f1]", mname);
return;
}
if (f2 == FXP_OT_NULL)
{
logman("%s:exit:null[f2]", mname);
return;
}
if (result == FXP_OT_NULL)
{
logman("%s:exit:null[result]", mname);
return;
}
if (!fxp_oconv(f1, FXP_DEFAULT, cf1))
{
logman("%s:exit:bad rc from fxp_oconv[f1]", mname);
return;
}
if (!fxp_oconv(f2, FXP_DEFAULT, cf2))
{
logman("%s:exit:bad rc from fxp_oconv[f2]", mname);
return;
}
/* set result scale to largest of the two numbers except
for divide where we set the scale to the smallest */
if (op == '/')
out_scale = (f2->scale < f1->scale) ? f2->scale : f1->scale;
else
out_scale = (f1->scale > f2->scale) ? f1->scale : f2->scale;
if (!fxp_oconv(result, out_scale, cr))
{
logman("%s:exit:bad rc from fxp_oconv[result]", mname);
return;
}
app_out("%ld:%s%c%s=%s", trans_no, cf1, op, cf2, cr);
}
void report_comp(struct fxp *f1, struct fxp *f2, int result, char *op)
{
/* Report the result of a comparison. */
char mname[] = "report_comp", cf1[10], cf2[10];
logman("%s:enter", mname);
if (f1 == FXP_OT_NULL)
{
logman("%s:exit:null[f1]", mname);
return;
}
if (f2 == FXP_OT_NULL)
{
logman("%s:exit:null[f2]", mname);
return;
}
if (result != TRUE && result != FALSE)
{
logman("%s:exit:out of range[result]", mname);
return;
}
if (!fxp_oconv(f1, FXP_DEFAULT, cf1))
{
logman("%s:exit:bad rc from fxp_oconv[f1]", mname);
return;
}
if (!fxp_oconv(f2, FXP_DEFAULT, cf2))
{
logman("%s:exit:bad rc from fxp_oconv[f2]", mname);
return;
}
app_out("%ld:%s%s%s=%d", trans_no, cf1, op, cf2, result);
}
int get_num(char *numout)
{
/* Generate a random floating point number in string form.
Function returns 'TRUE' upon success, 'FALSE' otherwise. */
char mname[] = "get_num";
int ival, is_frac, fval;
logman("%s:enter", mname);
if (numout == (char *)NULL)
{
logman("%s:null[numout]", mname);
return(FALSE);
}
numout[0] = EOS;
/* first, generate integer portion */
ival = rnd(0, 99);
/* decide whether number should have fractional portion */
is_frac = rnd(0, 1);
if (is_frac)
fval = rnd(0, 99);
else
fval = 0;
if (is_frac)
sprintf(numout, "%d.%d", ival, fval);
else
sprintf(numout, "%d", ival);
return(TRUE);
}
void app_out(char *fmt,...)
{
/* Display a message and if the logger is active, log
the message also. */
va_list argptr;
char *mes, mname[] = "app_out";
int ret;
va_start(argptr, fmt);
if ((mes = (char *)malloc(2048)) == (char *)NULL)
{
logman("%s:alloc fail[mes]", mname);
return;
}
// format message
memset(mes, 0, 2048);
vsprintf(mes, fmt, argptr);
printf("%s\n", mes);
if (logman_is_active())
logman_nf(mes);
free(mes);
}