## root/source/fxpstres.c

/* [<][>][^][v][top][bottom][index][help] */

## DEFINITIONS

This source file includes following definitions.

1. main
2. pick_com
3. do_com
4. do_add
5. do_sub
6. do_mul
7. do_div
8. do_eq
9. do_lt
10. do_gt
11. do_le
12. do_ge
13. report_math
14. report_comp
15. get_num
16. 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);
    }

/* [<][>][^][v][top][bottom][index][help] */