home *** CD-ROM | disk | FTP | other *** search
/ Die Ultimative Software-P…i Collection 1996 & 1997 / Die Ultimative Software-Pakete CD-ROM fur Atari Collection 1996 & 1997.iso / g / gnu_c / pmlsrc23.zoo / pmltests / d2d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-19  |  11.1 KB  |  450 lines

  1. /************************************************************************
  2.  *                                    *
  3.  *                N O T I C E                *
  4.  *                                    *
  5.  *            Copyright Abandoned, 1987, Fred Fish        *
  6.  *                                    *
  7.  *    This previously copyrighted work has been placed into the    *
  8.  *    public domain by the author (Fred Fish) and may be freely used    *
  9.  *    for any purpose, private or commercial.  I would appreciate    *
  10.  *    it, as a courtesy, if this notice is left in all copies and    *
  11.  *    derivative works.  Thank you, and enjoy...            *
  12.  *                                    *
  13.  *    The author makes no warranty of any kind with respect to this    *
  14.  *    product and explicitly disclaims any implied warranties of    *
  15.  *    merchantability or fitness for any particular purpose.        *
  16.  *                                    *
  17.  ************************************************************************
  18.  */
  19.  
  20.  
  21. /*
  22.  *  FILE
  23.  *
  24.  *    d2d.c   test double to double math functions
  25.  *
  26.  *  KEY WORDS
  27.  *
  28.  *    portable math library
  29.  *    test functions
  30.  *
  31.  *  DESCRIPTION
  32.  *
  33.  *    Tests double precision functions for the Portable Math
  34.  *    Library.  Tests those functions which expect a single
  35.  *    double precision argument and return a double.
  36.  *
  37.  *    Most of the test data in the current data file (d2d.dat)
  38.  *    was generated using double precision FORTRAN arithmetic
  39.  *    on a Decsystem-20.
  40.  *
  41.  *    Note that the ordering of functions is important for
  42.  *    optimum error information.  Since some functions call
  43.  *    others in the library, the functions being called should
  44.  *    be tested first.  Naturally, an error in a lower level
  45.  *    function will cause propagation of errors up to higher
  46.  *    level functions.
  47.  *
  48.  *  USAGE
  49.  *
  50.  *    d2d [-esv] [-l limit]
  51.  *
  52.  *        -e    =>    force error for each test
  53.  *                to verify error handling
  54.  *
  55.  *        -l    =>    report errors greater than
  56.  *                specified limit (default 10**-6)
  57.  *
  58.  *        -s    =>    print summary after tests
  59.  *
  60.  *        -v    =>    print each function, argument,
  61.  *                and result
  62.  *
  63.  *    Test directives are read from the standard input, which
  64.  *    may be redirected to the provided test file (d2d.dat),
  65.  *    and any relative errors are automatically written to standard
  66.  *    output if they exceed a maximum allowable limit.
  67.  *    Each test directive has the form:
  68.  *
  69.  *        <name> <argument> <expected result>
  70.  *
  71.  *    Each field is separated by a one or more space character(s).
  72.  *    The first field, "name", is the name of the function
  73.  *    to test (sqrt, ln, exp, etc).  The second field
  74.  *    is the argument to use in calling the specified function.
  75.  *    The third field is the expected result.
  76.  *        
  77.  *  PROGRAMMER
  78.  *
  79.  *    Fred Fish
  80.  *
  81.  */
  82.  
  83.  
  84. #include <stdio.h>
  85. #include <math.h>
  86. #include "pml.h"
  87.  
  88. #ifdef atarist
  89. #define STDERR    stdout
  90. #else
  91. #define STDERR stderr
  92. #endif
  93.  
  94. #define MAX_ABS_ERR 1.0e-6    /* Set to catch only gross errors */
  95.  
  96. static int vflag;        /* Flag for verbose option */
  97. static int eflag;        /* Simulate an error to error printout */
  98. static int sflag;        /* Flag to show final statistics */
  99.  
  100. static double max_abs_err = MAX_ABS_ERR;
  101.  
  102. extern double dabs ();
  103. extern double acos ();
  104. extern double acosh ();
  105. extern double asin ();
  106. extern double asinh ();
  107. extern double atan ();
  108. extern double atanh ();
  109. extern double cos ();
  110. extern double cosh ();
  111. extern double exp ();
  112. extern double log ();
  113. extern double log10 ();
  114. extern double sin ();
  115. extern double sinh ();
  116. extern double sqrt ();
  117. extern double tan ();
  118. extern double tanh ();
  119.  
  120.  
  121.  
  122. /*
  123.  *    Define all recognized test functions.  Each function
  124.  *    must have an entry in this table, where each
  125.  *    entry contains the information specified in the 
  126.  *    structure "test".
  127.  *
  128.  */
  129.  
  130. struct test {            /* Structure of each function to be tested */
  131.     char *name;            /* Name of the function to test */
  132.     double (*func)();        /* Pointer to the function's entry point */
  133.     double max_err;        /* Error accumulator for this function */
  134. };
  135.  
  136. static struct test tests[] = {    /* Table of all recognized functions */
  137.     "dabs", dabs, 0.0,        /* Absolute value */
  138.     "acos", acos, 0.0,        /* Arc cosine (in radians) */
  139.     "acosh", acosh, 0.0,    /* Hyperbolic arc cosine (in radians) */
  140.     "asin", asin, 0.0,        /* Arc sine (in radians) */
  141.     "asinh", asinh, 0.0,    /* Hyperbolic arc sine (in radians) */
  142.     "atan", atan, 0.0,        /* Arc tangent (in radians) */
  143.     "atanh", atanh, 0.0,    /* Hyperbolic arc tangent (in radians) */
  144.     "cos", cos, 0.0,        /* Cosine (argument in radians) */
  145.     "cosh", cosh, 0.0,        /* Hyperbolic cosine (argument in radians) */
  146.     "exp", exp, 0.0,        /* Exponential */
  147.     "log", log, 0.0,        /* Natural logarithm */
  148.     "log10", log10, 0.0,    /* Log to base 10 */
  149.     "sin", sin, 0.0,        /* Sine (argument in radians) */
  150.     "sinh", sinh, 0.0,        /* Hyperbolic sine (argument in radians) */
  151.     "sqrt", sqrt, 0.0,        /* Garden variety square root */
  152.     "tan", tan, 0.0,        /* Tangent (argument in radians) */
  153.     "tanh", tanh, 0.0,        /* Hyperbolic tangent (argument in radians) */
  154.     NULL, NULL, 0.0        /* Function list end marker */
  155. };
  156.  
  157.  
  158. /*
  159.  *  FUNCTION
  160.  *
  161.  *    main   entry point for d2d test utility
  162.  *
  163.  *  PSEUDO CODE
  164.  *
  165.  *    Begin main
  166.  *        Process any options in command line.
  167.  *        Do all tests requested by stdin directives.
  168.  *        Report final statistics (if enabled).
  169.  *    End main
  170.  *
  171.  */
  172.  
  173. main (argc, argv)
  174. int argc;
  175. char *argv[];
  176. {
  177.     VOID dotests ();
  178.     
  179.     DBUG_ENTER ("main");
  180.     DBUG_PROCESS (argv[0]);
  181.     options (argc, argv);
  182.     dotests (argv);
  183.     statistics ();
  184.     DBUG_RETURN (0);
  185. }
  186.  
  187.  
  188. /*
  189.  *  FUNCTION
  190.  *
  191.  *    dotests   process each test from stdin directives
  192.  *
  193.  *  ERROR REPORTING
  194.  *
  195.  *    Note that in most cases, the error criterion is based
  196.  *    on relative error, defined as:
  197.  *
  198.  *        error = (result - expected) / expected
  199.  *
  200.  *    Naturally, if the expected result is zero, some
  201.  *    other criterion must be used.  In this case, the
  202.  *    absolute error is used.  That is:
  203.  *
  204.  *        error = result
  205.  *
  206.  *  PSEUDO CODE
  207.  *
  208.  *    Begin dotests
  209.  *        While a test directive is successfully read from stdin
  210.  *        Default function name to "{null}"
  211.  *        Default argument to 0.0
  212.  *        Default expected result to 0.0
  213.  *        Extract function name, argument and expected result
  214.  *        Lookup test in available test list
  215.  *        If no test was found then
  216.  *            Tell user that unknown function was specified
  217.  *        Else
  218.  *            Call function with argument and save result
  219.  *            If the verify flag is set then
  220.  *            Print function name, argument, and result
  221.  *            End if
  222.  *            If the expected result is not zero then
  223.  *            Compute the relative error
  224.  *            Else
  225.  *            Use the absolute error
  226.  *            End if
  227.  *            Get absolute value of error
  228.  *            If error exceeds limit or error force flag set
  229.  *            Print error notification on stderr
  230.  *            End if
  231.  *            If this error is max for given function then
  232.  *            Remember this error for summary
  233.  *            End if
  234.  *        End if
  235.  *        End while
  236.  *    End dotests
  237.  *
  238.  */
  239.  
  240.  
  241. VOID dotests (argv)
  242. char *argv[];
  243. {
  244.     char buffer[256];        /* Directive buffer */
  245.     char function[64];        /* Specified function name */
  246.     double argument;        /* Specified function argument */
  247.     double expected;        /* Specified expected result */
  248.     double result;        /* Actual result */
  249.     double error;        /* Relative or absolute error */
  250.     double abs_err;        /* Absolute value of error */
  251.     struct test *testp;        /* Pointer to function test */
  252.     struct test *lookup ();    /* Returns function test pointer */
  253.     register char *strp;    /* Pointer to next token in string */
  254.     extern char *strtok ();
  255.     extern double atof ();
  256.  
  257. #ifdef MJR
  258.     FILE * save_stdin, * re_stdin;
  259.     save_stdin = stdin;
  260.     re_stdin = freopen("d2d.dat","r",stdin);
  261.     if( re_stdin == (FILE *)NULL ) {
  262.     exit(-33);
  263.     }
  264. #endif
  265.     DBUG_ENTER ("dotests");
  266.     while (fgets (buffer, sizeof(buffer), stdin) != NULL) {
  267.     strcpy (function, "{null}");
  268.     argument = 0.0;
  269.     expected = 0.0;
  270.     sscanf (buffer, "%s %le %le", function, &argument, &expected);
  271.         testp = lookup (function);
  272.         if (testp == NULL) {
  273.             fprintf (STDERR, "%s: unknown function \"%s\".\n",
  274.             argv[0], function);
  275.         } else {
  276.         result = (*testp -> func)(argument);
  277.         if (vflag) {
  278.             printf ("%s(%le) = %30.23le.\n", function, argument, result);
  279.         }
  280.         if (expected != 0.0) {
  281.             error = (result - expected) / expected;
  282.         } else {
  283.             error = result;
  284.         }
  285.         if (error < 0.0) {
  286.         abs_err = -error;
  287.         } else {
  288.         abs_err = error;
  289.         }
  290.             if ((abs_err > max_abs_err) || eflag) {
  291.         fprintf (STDERR, "%s: error in \"%s\"\n", argv[0], function);
  292.         fprintf (STDERR, "\targument\t%25.20le\n", argument);
  293.         fprintf (STDERR, "\tresult\t\t%25.20le\n", result);
  294.         fprintf (STDERR, "\texpected\t%25.20le\n", expected);
  295.             }
  296.         if (abs_err > testp -> max_err) {
  297.             testp -> max_err = abs_err;
  298.         }
  299.         }
  300.     }
  301. #ifdef MJR
  302.     fclose( re_stdin );
  303. #endif
  304.     DBUG_VOID_RETURN;
  305. }
  306.  
  307.  
  308. /*
  309.  *  FUNCTION
  310.  *
  311.  *    options   process command line options
  312.  *
  313.  *  PSEUDO CODE
  314.  *
  315.  *    Begin options
  316.  *        Reset all flags to FALSE by default
  317.  *        Initialize flag argument scan pointer
  318.  *        If there is a second command line argument then
  319.  *        If the argument specifies flags then
  320.  *            While there is an unprocessed flag
  321.  *            Switch on flag
  322.  *            Case "force error flag":
  323.  *                Set the "force error" flag
  324.  *                Break switch
  325.  *            Case "print summary":
  326.  *                Set "print summary" flag
  327.  *                Break switch
  328.  *            Case "verbose":
  329.  *                Set "verbose" flag
  330.  *                Break switch
  331.  *            Default:
  332.  *                Tell user unknown flag
  333.  *                Break switch
  334.  *            End switch
  335.  *            End while
  336.  *        End if
  337.  *        End if
  338.  *    End options
  339.  *
  340.  */
  341.  
  342.  
  343. options (argc, argv)
  344. int argc;
  345. char *argv[];
  346. {
  347.     register int flag;
  348.     extern int getopt ();
  349.     extern char *optarg;
  350.  
  351.     DBUG_ENTER ("options");
  352.     eflag = sflag = vflag = FALSE;
  353.     while ((flag = getopt (argc, argv, "#:el:sv")) != EOF) {
  354.     switch (flag) {
  355.         case '#':
  356.             DBUG_PUSH (optarg);
  357.         break;
  358.         case 'e':
  359.         eflag = TRUE;
  360.         break;
  361.         case 'l':
  362.             sscanf (optarg, "%le", &max_abs_err);
  363.         DBUG_3 ("args", "max_abs_err = %le", max_abs_err);
  364.         break;
  365.         case 's':
  366.         sflag = TRUE;
  367.         break;
  368.         case 'v':
  369.         vflag = TRUE;
  370.         break;
  371.     }
  372.     }
  373.     DBUG_VOID_RETURN;
  374. }
  375.  
  376.  
  377. /*
  378.  *  FUNCTION
  379.  *
  380.  *    loopup   lookup test in known test list
  381.  *
  382.  *  DESCRIPTION
  383.  *
  384.  *    Given the name of a desired test, looks up the test
  385.  *    in the known test list and returns a pointer to the
  386.  *    test structure.
  387.  *
  388.  *    Since the table is so small we simply use a linear
  389.  *    search.
  390.  *
  391.  *  PSEUDO CODE
  392.  *
  393.  *    Begin lookup
  394.  *        For each known test
  395.  *        If the test's name matches the desired test name
  396.  *            Return pointer to the test structure
  397.  *        End if
  398.  *        End for
  399.  *    End lookup
  400.  *
  401.  */
  402.  
  403. struct test *lookup (funcname)
  404. char *funcname;
  405. {
  406.     struct test *testp;
  407.     struct test *rtnval;
  408.  
  409.     DBUG_ENTER ("lookup");
  410.     rtnval = (struct test *) NULL;
  411.     for (testp = tests; testp -> name != NULL && rtnval == NULL; testp++) {
  412.     if (!strcmp (testp -> name, funcname)) {
  413.         rtnval = testp;
  414.      }
  415.     }
  416.     DBUG_RETURN (rtnval);
  417. }
  418.  
  419.  
  420. /*
  421.  *  FUNCTION
  422.  *
  423.  *    statistics   print final statistics if desired
  424.  *
  425.  *  PSEUDO CODE
  426.  *
  427.  *    Begin statistics
  428.  *        If a final statistics (summary) is desired then
  429.  *        For each test in the known test list
  430.  *            Print the maximum error encountered
  431.  *        End for
  432.  *        End if
  433.  *    End statistics
  434.  *
  435.  */
  436.  
  437. statistics ()
  438. {
  439.     struct test *tp;
  440.  
  441.     DBUG_ENTER ("statistics");
  442.     if (sflag) {
  443.         for (tp = tests; tp -> name != NULL; tp++) {
  444.         printf ("%s:\tmaximum relative error %le\n", 
  445.             tp -> name, tp -> max_err);
  446.     }
  447.     }
  448.     DBUG_VOID_RETURN;
  449. }
  450.