Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watnot!watmath!clyde!rutgers!husc6!seismo!nbires!hao!noao!mcdsun!fnf From: fnf@mcdsun.UUCP Newsgroups: net.sources Subject: Portable Math Library in C (Part 6 of 6) Message-ID: <294@mcdsun.UUCP> Date: Fri, 10-Apr-87 18:47:55 EST Article-I.D.: mcdsun.294 Posted: Fri Apr 10 18:47:55 1987 Date-Received: Sun, 12-Apr-87 19:55:32 EST Organization: Motorola Microcomputer Division, Tempe, Az. Lines: 964 Keywords: math library This is a portable math library written entirely in C. Since it has been several years since I had any interest in doing any more work on it, and people may find it useful, I have decided to post it. There should be a lead-in posting (part 0 of 6?) containing a README file and commands to make the directories for the regular parts 1-6. Be sure to read the README file in 'part 0'. -Fred Fish =============== Cut here and feed to the shell ======================== #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh tests/c2c.c <<'END_OF_tests/c2c.c' X/************************************************************************ X * * X * N O T I C E * X * * X * Copyright Abandoned, 1987, Fred Fish * X * * X * This previously copyrighted work has been placed into the * X * public domain by the author (Fred Fish) and may be freely used * X * for any purpose, private or commercial. I would appreciate * X * it, as a courtesy, if this notice is left in all copies and * X * derivative works. Thank you, and enjoy... * X * * X * The author makes no warranty of any kind with respect to this * X * product and explicitly disclaims any implied warranties of * X * merchantability or fitness for any particular purpose. * X * * X ************************************************************************ X */ X X/* X * FILE X * X * c2c.c test complex to complex math functions X * X * KEY WORDS X * X * portable math library X * test functions X * X * DESCRIPTION X * X * Tests double precision functions for the Portable Math X * Library. Tests those functions which expect a single X * double precision complex argument and return a double X * precision complex result. X * X * Most of the test data in the current data file (c2c.dat) X * was generated using double precision FORTRAN arithmetic X * on a Decsystem-20. X * X * Note that the ordering of functions is important for X * optimum error information. Since some functions call X * others in the library, the functions being called should X * be tested first. Naturally, an error in a lower level X * function will cause propagation of errors up to higher X * level functions. X * X * USAGE X * X * c2c [-esv] [-l limit] X * X * -e => force error for each test X * to verify error handling X * X * -l => report errors greater than X * specified limit (default 10**-6) X * X * -s => print summary after tests X * X * -v => print each function, argument, X * and result X * X * Test directives are read from the standard input, which X * may be redirected to the provided test file (c2c.dat), X * and any relative errors are automatically written to standard X * output if they exceed a maximum allowable limit. X * Each test directive has the form: X * X * X * X * Each field is separated by a one or more space character(s). X * Both the argument and the expected result are given X * in the form: X * X * X * X * where is the real part and is the X * imaginary part, separated by one or more spaces. X * X * X * NOTE X * X * This program uses both the csubt and the cdiv routines, X * which are pml functions!. Thus if either of these screw X * up, the results will be unpredictable. BEWARE! X * X * PROGRAMMER X * X * Fred Fish X * Tempe, Az 85281 X * X */ X X X#include X#include X X#ifndef NODBG X#include X#else X#include "dbg.h" X#endif X X#define TRUE 1 /* This really should be in stdio.h */ X#define FALSE 0 /* This too */ X#define MAX_ABS_ERR 1.0e-6 /* Set to catch only gross errors */ X Xstatic int vflag; /* Flag for verbose option */ Xstatic int eflag; /* Simulate an error to error printout */ Xstatic int sflag; /* Flag to show final statistics */ X Xstatic double max_abs_err = MAX_ABS_ERR; X X/* X * External functions which are used internally. X */ X Xextern char *strtok (); Xextern double atof (); Xextern double cabs (); Xextern COMPLEX csubt (); Xextern COMPLEX cdiv (); X X/* X * External functions to be tested. X */ X Xextern COMPLEX cacos(); Xextern COMPLEX casin(); Xextern COMPLEX catan(); Xextern COMPLEX ccos(); Xextern COMPLEX ccosh(); Xextern COMPLEX cexp(); Xextern COMPLEX clog(); Xextern COMPLEX crcp(); Xextern COMPLEX csin(); Xextern COMPLEX csinh(); Xextern COMPLEX csqrt(); Xextern COMPLEX ctan(); Xextern COMPLEX ctanh(); X X X/* X * Define all recognized test functions. Each function X * must have an entry in this table, where each X * entry contains the information specified in the X * structure "test". X * X */ X Xstruct test { /* Structure of each function to be tested */ X char *name; /* Name of the function to test */ X COMPLEX (*func)(); /* Pointer to the function's entry point */ X double max_err; /* Error accumulator for this function */ X}; X Xstatic struct test tests[] = { /* Table of all recognized functions */ X "cacos", cacos, 0.0, /* Complex arc cosine */ X "casin", casin, 0.0, /* Complex arc sine */ X "catan", catan, 0.0, /* Complex arc tangent */ X "ccos", ccos, 0.0, /* Complex cosine */ X "ccosh", ccosh, 0.0, /* Complex hyperbolic cosine */ X "cexp", cexp, 0.0, /* Complex exponential */ X "clog", clog, 0.0, /* Complex natural logarithm */ X "crcp", crcp, 0.0, /* Complex reciprocal */ X "csin", csin, 0.0, /* Complex sine */ X "csinh", csinh, 0.0, /* Complex hyperbolic sine */ X "csqrt", csqrt, 0.0, /* Complex square root */ X "ctan", ctan, 0.0, /* Complex tangent */ X "ctanh", ctanh, 0.0, /* Complex hyperbolic tangent */ X NULL, NULL, 0.0 /* Function list end marker */ X}; X X X/* X * FUNCTION X * X * main entry point for c2c test utility X * X * PSEUDO CODE X * X * Begin main X * Process any options in command line. X * Do all tests requested by stdin directives. X * Report final statistics (if enabled). X * End main X * X */ X Xmain (argc, argv) Xint argc; Xchar *argv[]; X{ X ENTER ("main"); X DEBUGWHO (argv[0]); X options (argc, argv); X dotests (argv); X statistics (); X LEAVE (); X} X X X/* X * FUNCTION X * X * dotests process each test from stdin directives X * X * ERROR REPORTING X * X * Note that in most cases, the error criterion is based X * on relative error, defined as: X * X * error = (result - expected) / expected X * X * Naturally, if the expected result is zero, some X * other criterion must be used. In this case, the X * absolute error is used. That is: X * X * error = result X * X * PSEUDO CODE X * X * Begin dotests X * While a test directive is successfully read from stdin X * Default function name to "{null}" X * Default real part of argument to 0.0 X * Default imaginary part of argument to 0.0 X * Default expected result to 0.0 X * Extract function name, argument and expected result X * Lookup test in available test list X * If no test was found then X * Tell user that unknown function was specified X * Else X * Call function with argument and save result X * If the verify flag is set then X * Print function name, argument, and result X * End if X * If the expected result is not zero then X * Compute the relative error X * Else X * Use the absolute error X * End if X * Get absolute value of error X * If error exceeds limit or error force flag set X * Print error notification on stderr X * End if X * If this error is max for given function then X * Remember this error for summary X * End if X * End if X * End while X * End dotests X * X */ X X Xdotests (argv) Xchar *argv[]; X{ X char buffer[256]; /* Directive buffer */ X char function[64]; /* Specified function name */ X COMPLEX argument; /* Specified function argument */ X COMPLEX expected; /* Specified expected result */ X COMPLEX result; /* Actual result */ X COMPLEX error; /* Relative or absolute error */ X double abs_err; /* Absolute value of error */ X struct test *testp; /* Pointer to function test */ X struct test *lookup (); /* Returns function test pointer */ X register char *strp; /* Pointer to next token in string */ X X ENTER ("dotests"); X while (fgets (buffer, sizeof(buffer), stdin) != NULL) { X strcpy (function, "{null}"); X argument.real = argument.imag = 0.0; X expected.real = expected.imag = 0.0; X sscanf (buffer, "%s %le %le %le %le", function, X &argument.real, &argument.imag, &expected.real, &expected.imag); X testp = lookup (function); X if (testp == NULL) { X fprintf (stderr, "%s: unknown function \"%s\".\n", X argv[0], function); X } else { X result = (*testp -> func)(argument); X if (vflag) { X printf ("%s(%le + j %le) \n = %30.23le + j %30.23le.\n", X function, argument.real, argument.imag, result.real, X result.imag); X } X if (expected.real != 0.0 || expected.imag != 0.0) { X error = csubt (result, expected); X error = cdiv (error, expected); X } else { X error = result; X } X abs_err = cabs (error); X if ((abs_err > max_abs_err) || eflag) { X fprintf (stderr, "%s: error in \"%s\"\n", argv[0], function); X fprintf (stderr, "\treal (arg)\t\t%25.20le\n", argument.real); X fprintf (stderr, "\timag (arg)\t\t%25.20le\n", argument.imag); X fprintf (stderr, "\treal (result)\t\t%25.20le\n",result.real); X fprintf (stderr, "\timag (result)\t\t%25.20le\n",result.imag); X fprintf (stderr, "\treal (expected)\t\t%25.20le\n",expected.real); X fprintf (stderr, "\timag (expected)\t\t%25.20le\n",expected.imag); X } X if (abs_err > testp -> max_err) { X testp -> max_err = abs_err; X } X } X } X LEAVE (); X} X X X/* X * FUNCTION X * X * options process command line options X * X * PSEUDO CODE X * X * Begin options X * Reset all flags to FALSE by default X * Initialize flag argument scan pointer X * If there is a second command line argument then X * If the argument specifies flags then X * While there is an unprocessed flag X * Switch on flag X * Case "force error flag": X * Set the "force error" flag X * Break switch X * Case "print summary": X * Set "print summary" flag X * Break switch X * Case "verbose": X * Set "verbose" flag X * Break switch X * Default: X * Tell user unknown flag X * Break switch X * End switch X * End while X * End if X * End if X * End options X * X */ X X Xoptions (argc, argv) Xint argc; Xchar *argv[]; X{ X register int flag; X extern int getopt (); X extern char *optarg; X X ENTER ("options"); X eflag = sflag = vflag = FALSE; X while ((flag = getopt (argc, argv, "#:el:sv")) != EOF) { X switch (flag) { X case '#': X DEBUGPUSH (optarg); X break; X case 'e': X eflag = TRUE; X break; X case 'l': X sscanf (optarg, "%le", &max_abs_err); X DEBUG3 ("args", "max_abs_err = %le", max_abs_err); X break; X case 's': X sflag = TRUE; X break; X case 'v': X vflag = TRUE; X break; X } X } X LEAVE (); X} X X X/* X * FUNCTION X * X * loopup lookup test in known test list X * X * DESCRIPTION X * X * Given the name of a desired test, looks up the test X * in the known test list and returns a pointer to the X * test structure. X * X * Since the table is so small we simply use a linear X * search. X * X * PSEUDO CODE X * X * Begin lookup X * For each known test X * If the test's name matches the desired test name X * Return pointer to the test structure X * End if X * End for X * End lookup X * X */ X Xstruct test *lookup (funcname) Xchar *funcname; X{ X struct test *testp; X struct test *rtnval; X X ENTER ("lookup"); X rtnval = (struct test *) NULL; X for (testp = tests; testp -> name != NULL && rtnval == NULL; testp++) { X if (!strcmp (testp -> name, funcname)) { X rtnval = testp; X } X } X LEAVE (); X return (rtnval); X} X X X/* X * FUNCTION X * X * statistics print final statistics if desired X * X * PSEUDO CODE X * X * Begin statistics X * If a final statistics (summary) is desired then X * For each test in the known test list X * Print the maximum error encountered X * End for X * End if X * End statistics X * X */ X Xstatistics () X{ X struct test *tp; X X ENTER ("statistics"); X if (sflag) { X for (tp = tests; tp -> name != NULL; tp++) { X printf ("%s:\tmaximum relative error %le\n", X tp -> name, tp -> max_err); X } X } X LEAVE (); X} END_OF_tests/c2c.c if test 11638 -ne `wc -c tests/cc2c.c <<'END_OF_tests/cc2c.c' X/************************************************************************ X * * X * N O T I C E * X * * X * Copyright Abandoned, 1987, Fred Fish * X * * X * This previously copyrighted work has been placed into the * X * public domain by the author (Fred Fish) and may be freely used * X * for any purpose, private or commercial. I would appreciate * X * it, as a courtesy, if this notice is left in all copies and * X * derivative works. Thank you, and enjoy... * X * * X * The author makes no warranty of any kind with respect to this * X * product and explicitly disclaims any implied warranties of * X * merchantability or fitness for any particular purpose. * X * * X ************************************************************************ X */ X X/* X * FILE X * X * cc2c.c test complex to complex math functions X * X * KEY WORDS X * X * portable math library X * test functions X * X * DESCRIPTION X * X * Tests double precision functions for the Portable Math X * Library. Tests those functions which expect two X * double precision complex arguments and return a double X * precision complex result. X * X * Most of the test data in the current data file (cc2c.dat) X * was generated using double precision FORTRAN arithmetic X * on a Decsystem-20. X * X * Note that the ordering of functions is important for X * optimum error information. Since some functions call X * others in the library, the functions being called should X * be tested first. Naturally, an error in a lower level X * function will cause propagation of errors up to higher X * level functions. X * X * USAGE X * X * cc2c [-esv] [-l limit] X * X * -e => force error for each test X * to verify error handling X * X * -l => report errors greater than X * specified limit (default 10**-6) X * X * -s => print summary after tests X * X * -v => print each function, argument, X * and result X * X * Test directives are read from the standard input, which X * may be redirected to the provided test file (cc2c.dat), X * and any relative errors are automatically written to standard X * output if they exceed a maximum allowable limit. X * Each test directive has the form: X * X * X * X * Each field is separated by a one or more space character(s). X * Both the argument and the expected result are given X * in the form: X * X * X * X * where is the real part and is the X * imaginary part, separated by one or more spaces. X * X * X * NOTE X * X * This program uses both the csubt and the cdiv routines, X * which are pml functions!. Thus if either of these screw X * up, the results will be unpredictable. BEWARE! X * X * PROGRAMMER X * X * Fred Fish X * Tempe, Az 85281 X * X */ X X X#include X#include X X#ifndef NODBG X#include X#else X#include "dbg.h" X#endif X X#define TRUE 1 /* This really should be in stdio.h */ X#define FALSE 0 /* This too */ X#define MAX_ABS_ERR 1.0e-6 /* Set to catch only gross errors */ X Xstatic int vflag; /* Flag for verbose option */ Xstatic int eflag; /* Simulate an error to error printout */ Xstatic int sflag; /* Flag to show final statistics */ X Xstatic double max_abs_err = MAX_ABS_ERR; X X/* X * External functions which are used internally. X */ X Xextern char *strtok (); Xextern double atof (); Xextern double cabs (); Xextern COMPLEX csubt (); Xextern COMPLEX cdiv (); X X/* X * External functions to be tested. X */ X Xextern COMPLEX cadd(); Xextern COMPLEX csubt(); Xextern COMPLEX cdiv(); Xextern COMPLEX cmult(); X X X/* X * Define all recognized test functions. Each function X * must have an entry in this table, where each X * entry contains the information specified in the X * structure "test". X * X */ X Xstruct test { /* Structure of each function to be tested */ X char *name; /* Name of the function to test */ X COMPLEX (*func)(); /* Pointer to the function's entry point */ X double max_err; /* Error accumulator for this function */ X}; X Xstatic struct test tests[] = { /* Table of all recognized functions */ X "cadd", cadd, 0.0, /* Complex addition */ X "csubt", csubt, 0.0, /* Complex subtraction */ X "cdiv", cdiv, 0.0, /* Complex division */ X "cmult", cmult, 0.0, /* Complex multiplication */ X NULL, NULL, 0.0 /* Function list end marker */ X}; X X X/* X * FUNCTION X * X * main entry point for cc2c test utility X * X * PSEUDO CODE X * X * Begin main X * Process any options in command line. X * Do all tests requested by stdin directives. X * Report final statistics (if enabled). X * End main X * X */ X Xmain (argc, argv) Xint argc; Xchar *argv[]; X{ X ENTER ("main"); X DEBUGWHO (argv[0]); X options (argc, argv); X dotests (argv); X statistics (); X LEAVE (); X} X X X/* X * FUNCTION X * X * dotests process each test from stdin directives X * X * ERROR REPORTING X * X * Note that in most cases, the error criterion is based X * on relative error, defined as: X * X * error = (result - expected) / expected X * X * Naturally, if the expected result is zero, some X * other criterion must be used. In this case, the X * absolute error is used. That is: X * X * error = result X * X * PSEUDO CODE X * X * Begin dotests X * While a test directive is successfully read from stdin X * Default function name to "{null}" X * Default real part of argument to 0.0 X * Default imaginary part of argument to 0.0 X * Default expected result to 0.0 X * Extract function name, argument and expected result X * Lookup test in available test list X * If no test was found then X * Tell user that unknown function was specified X * Else X * Call function with argument and save result X * If the verify flag is set then X * Print function name, argument, and result X * End if X * If the expected result is not zero then X * Compute the relative error X * Else X * Use the absolute error X * End if X * Get absolute value of error X * If error exceeds limit or error force flag set X * Print error notification on stderr X * End if X * If this error is max for given function then X * Remember this error for summary X * End if X * End if X * End while X * End dotests X * X */ X X Xdotests (argv) Xchar *argv[]; X{ X char buffer[256]; /* Directive buffer */ X char function[64]; /* Specified function name */ X COMPLEX arg1; /* Specified function argument 1 */ X COMPLEX arg2; /* Specified function argument 2 */ X COMPLEX expected; /* Specified expected result */ X COMPLEX result; /* Actual result */ X COMPLEX error; /* Relative or absolute error */ X double abs_err; /* Absolute value of error */ X struct test *testp; /* Pointer to function test */ X struct test *lookup (); /* Returns function test pointer */ X register char *strp; /* Pointer to next token in string */ X X ENTER ("dotests"); X while (fgets (buffer, sizeof(buffer), stdin) != NULL) { X strcpy (function, "{null}"); X arg1.real = arg1.imag = 0.0; X arg2.real = arg2.imag = 0.0; X expected.real = expected.imag = 0.0; X sscanf (buffer, "%s %le %le %le %le %le %le", function, X &arg1.real, &arg1.imag, &arg2.real, &arg2.imag, X &expected.real, &expected.imag); X testp = lookup (function); X if (testp == NULL) { X fprintf (stderr, "%s: unknown function \"%s\".\n", X argv[0], function); X } else { X result = (*testp -> func)(arg1, arg2); X if (vflag) { X printf ("%s(%le + j %le, %le + j %le)\n", X function, arg1.real, arg1.imag, arg2.real, arg2.imag); X printf (" = %30.23le + j %30.23le.\n", result.real, X result.imag); X } X if (expected.real != 0.0 || expected.imag != 0.0) { X error = csubt (result, expected); X error = cdiv (error, expected); X } else { X error = result; X } X abs_err = cabs (error); X if ((abs_err > max_abs_err) || eflag) { X fprintf (stderr, "%s: error in \"%s\"\n", argv[0], function); X fprintf (stderr, "\treal (arg1)\t\t%25.20le\n", arg1.real); X fprintf (stderr, "\timag (arg1)\t\t%25.20le\n", arg1.imag); X fprintf (stderr, "\treal (arg2)\t\t%25.20le\n", arg2.real); X fprintf (stderr, "\timag (arg2)\t\t%25.20le\n", arg2.imag); X fprintf (stderr, "\treal (result)\t\t%25.20le\n",result.real); X fprintf (stderr, "\timag (result)\t\t%25.20le\n",result.imag); X fprintf (stderr, "\treal (expected)\t\t%25.20le\n",expected.real); X fprintf (stderr, "\timag (expected)\t\t%25.20le\n",expected.imag); X } X if (abs_err > testp -> max_err) { X testp -> max_err = abs_err; X } X } X } X LEAVE (); X} X X X/* X * FUNCTION X * X * options process command line options X * X * PSEUDO CODE X * X * Begin options X * Reset all flags to FALSE by default X * Initialize flag argument scan pointer X * If there is a second command line argument then X * If the argument specifies flags then X * While there is an unprocessed flag X * Switch on flag X * Case "force error flag": X * Set the "force error" flag X * Break switch X * Case "print summary": X * Set "print summary" flag X * Break switch X * Case "verbose": X * Set "verbose" flag X * Break switch X * Default: X * Tell user unknown flag X * Break switch X * End switch X * End while X * End if X * End if X * End options X * X */ X X Xoptions (argc, argv) Xint argc; Xchar *argv[]; X{ X register int flag; X extern int getopt (); X extern char *optarg; X X ENTER ("options"); X eflag = sflag = vflag = FALSE; X while ((flag = getopt (argc, argv, "#:el:sv")) != EOF) { X switch (flag) { X case '#': X DEBUGPUSH (optarg); X break; X case 'e': X eflag = TRUE; X break; X case 'l': X sscanf (optarg, "%le", &max_abs_err); X DEBUG3 ("args", "max_abs_err = %le", max_abs_err); X break; X case 's': X sflag = TRUE; X break; X case 'v': X vflag = TRUE; X break; X } X } X LEAVE (); X} X X X/* X * FUNCTION X * X * loopup lookup test in known test list X * X * DESCRIPTION X * X * Given the name of a desired test, looks up the test X * in the known test list and returns a pointer to the X * test structure. X * X * Since the table is so small we simply use a linear X * search. X * X * PSEUDO CODE X * X * Begin lookup X * For each known test X * If the test's name matches the desired test name X * Return pointer to the test structure X * End if X * End for X * End lookup X * X */ X Xstruct test *lookup (funcname) Xchar *funcname; X{ X struct test *testp; X struct test *rtnval; X X ENTER ("lookup"); X rtnval = (struct test *) NULL; X for (testp = tests; testp -> name != NULL && rtnval == NULL; testp++) { X if (!strcmp (testp -> name, funcname)) { X rtnval = testp; X } X } X LEAVE (); X return (rtnval); X} X X X/* X * FUNCTION X * X * statistics print final statistics if desired X * X * PSEUDO CODE X * X * Begin statistics X * If a final statistics (summary) is desired then X * For each test in the known test list X * Print the maximum error encountered X * End for X * End if X * End statistics X * X */ X Xstatistics () X{ X struct test *tp; X X ENTER ("statistics"); X if (sflag) { X for (tp = tests; tp -> name != NULL; tp++) { X printf ("%s:\tmaximum relative error %le\n", X tp -> name, tp -> max_err); X } X } X LEAVE (); X} END_OF_tests/cc2c.c if test 11225 -ne `wc -c