/*
 * test9500.trigeq - test of trigonometric identities for test 95dd
 *
 * We test over a wide variety of real (NUMBER) and complex (COMPLEX)
 * values, that various trigonometric identities hold for all calc
 * builtin trigonometric functions.
 *
 * We assume that the value produced by sin() (trigonometric sine)
 * and cos() (trigonometric cosine) are correct.  We can reasonably
 * assume this because of the calc regression test suite:
 *
 *      (such as test 34dd and in particular cal/test3400.trig.cal and
 *       such as test 89dd and in particular cal/test8900.special.cal)
 *
 * will test such those function beforehand.
 *
 * We use various trigonometric identity to verify the non-inverse
 * trigonometric functions other than sin() and cos().
 *
 * we verify that it is true within the error tolerance of the eps
 * (epsilon) argument.
 *
 * Copyright (C) 2023  Landon Curt Noll
 *
 * Primary author:  Landon Curt Noll
 *
 * Calc is open software; you can redistribute it and/or modify it under
 * the terms of the version 2.1 of the GNU Lesser General Public License
 * as published by the Free Software Foundation.
 *
 * Calc 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 Lesser General
 * Public License for more details.
 *
 * A copy of version 2.1 of the GNU Lesser General Public License is
 * distributed with calc under the filename COPYING-LGPL.  You should have
 * received a copy with calc; if not, write to Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Under source code control:   2023/09/10 14:33:06
 * File existed as early as:    2023
 *
 * Share and enjoy!  :-)        http://www.isthe.com/chongo/tech/comp/calc/
 */


/*
 * base_tval - base set of test values
 *
 * Our 16 base test values must be > 0 and <= 1.
 * We use these fractions because, when multiplied
 * by pi() will give values that are commonly used.
 *
 * NOTE: There is no reason to sort these values other than ascetics. :-)
 */
static base_tval = list(
        1/12,   /* ~ 0.08333333333333333333 */
        1/8,    /*   0.12500000000000000000 */
        1/6,    /* ~ 0.16666666666666666667 */
        1/5,    /*   0.20000000000000000000 */
        1/4,    /*   0.25000000000000000000 */
        1/3,    /* ~ 0.33333333333333333333 */
        3/8,    /*   0.37500000000000000000 */
        5/12,   /* ~ 0.41666666666666666667 */
        1/2,    /*   0.50000000000000000000 */
        2/3,    /* ~ 0.66666666666666666667 */
        3/4,    /*   0.75000000000000000000 */
        4/5,    /*   0.80000000000000000000 */
        5/6,    /* ~ 0.83333333333333333333 */
        7/8,    /*   0.87500000000000000000 */
        11/12,  /* ~ 0.91666666666666666667 */
        1       /*   1.00000000000000000000 */
);


/*
 * tval - full test list
 *
 * This long list is formed via the form_tval() function from the base_tval list.
 *
 * When the form_tval() function forms the full test test values
 * we will have 1025 values of various real and complex
 * values that also include random values added or subtracted.
 *
 * See the form_tval() function for details.
 */
tval = list();


/*
 * Lists that hold precomputed trigonometric functions on the tval full test list
 *
 * The precompute_trig() function will fill out these lists.
 * They will be the same size as size as the full test list.
 */
sin_tval = list();      /* trigonometric sine of each test test value */
cos_tval = list();      /* trigonometric cosine of each test test value */


/*
 * seed_rand - seed the subtractive 100 shuffle pseudo-random number generator
 *
 * We want to seed the subtractive 100 shuffle pseudo-random number generator
 * with a constant so that the result of this test set will be deterministic.
 *
 * We seed the subtractive 100 shuffle pseudo-random number generator with
 * a 128-bit seed value.  The 128-bit seed value was produced when a
 * Blum-Blum-Shub pseudo-random number generator was seeded with the
 * following 160-bit SHA1 hash of 3 calls to seed():
 *
 *      sha1(sha1(seed(), seed()<<64, seed()<<128)) == 0x732fda50b1bf6e34b604b7c75b993e5c37a4ad97
 *
 * This produced the following 160-bit value that was used to seed
 * the Blum-Blum-Shub pseudo-random number:
 *
 *      srandom(0x732fda50b1bf6e34b604b7c75b993e5c37a4ad97)
 *
 * The seeded Blum-Blum-Shub pseudo-random number generator was then
 * used to generate a 128-bit value:
 *
 *      randombit(128) == 0x37301cf47204f7fababc2f32e39ab338
 *
 * We seed the subtractive 100 shuffle pseudo-random number generator
 * with the above mentioned 128-bit value:
 *
 *      srand(0x37301cf47204f7fababc2f32e39ab338)
 */
define seed_rand()
{
        return srand(0x37301cf47204f7fababc2f32e39ab338);
}


/*
 * epsilon_bits - number of bits in epsilon()
 */
static epsilon_bits = highbit(1/epsilon()) + 1;


/*
 * epsilon_norm - norm of a epsilon()
 */
static epsilon_norm = norm(epsilon());


/*
 * random_rational_value - compute a random rational value > 0 and < 1
 *
 * We compute a pseudo-random value in the range (0,1) with a prevision of epsilon().
 *
 * We compute two distinct non-zero pseudo-random integers (i.e., > 0), a and b,
 * that are epsilon_bits (see above) long and produced by the seeded
 * subtractive 100 shuffle pseudo-random number generator (see seed_rand()).
 *
 * Return the smaller of a,b divided by the larger of a,b.
 */
define random_rational_value()
{
        local a;        /* epsilon_bits pseudo-random integer > 0 */
        local b;        /* epsilon_bits pseudo-random integer > 0 */

        /*
         * compute 1st non-zero pseudo-random epsilon_bits integer
         */
        do {
                a = randbit(epsilon_bits);
        } while (a == 0);

        /*
         * compute 2nd non-zero pseudo-random epsilon_bits integer also != a
         */
        do {
                b = randbit(epsilon_bits);
        } while (b == 0 || a == b);

        /*
         * return the min(a,b) / max(a,b): a value > 0 and < 1
         */
        return min(a,b) / max(a,b);
}


/*
 * form_tval - form a full list of test values
 *
 * Given an initial list of 16 values, we form 1025 test values.
 *
 * From the test set starts with 16 values from the base_tval[] list:
 *
 *      tval = base_tval;
 *
 * We form a list of 32 values by appending all of the above with:
 *
 *      tval[i] + 1
 *
 * We form a list of 64 values by appending all of the above with:
 *
 *      -tval[i]
 *
 * We form a list of 128 values by appending all of the above with:
 *
 *      For values >= 0:        tval[i] + random_rational_value
 *      For values < 0:         tval[i] - random_rational_value
 *
 * We form a list of 256 values by appending all of the above with:
 *
 *      tval[i] * pi()
 *
 * We form a list of 512 values by appending all of the above with:
 *
 *      tval[i] * 1i
 *
 * We for a list of 1024 values by appending new complex values where the
 * real part is a randomly selected real value (from the first 256 list values), and the
 * imaginary part is a randomly selected complex value (from the last 256 list values).
 *
 * Finally we append 0 to the list to form the full 1025 value list.
 */
define form_tval()
{
        local tval_len;         /* current length of the tval[] array */
        local real_cnt;         /* number of real values in tval[] array */
        local imag_cnt;         /* number of imaginary values in tval[] array */
        local i;

        /*
         * seed the subtractive 100 shuffle pseudo-random number generator
         */
        seed_rand();

        /*
         * load base_tval[] array into tval[] array
         */
        tval = base_tval;

        /*
         * expand all tval with tval+1
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {
                append(tval, tval[i] + 1);
        }

        /*
         * expand all tval with -tval
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {
                append(tval, -tval[i]);
        }

        /*
         * expand all tval with tval +/- random_rational_value
         *
         * For values we add random_rational_value if > 0
         *   or we subtract crandom_rational_value if < 0.
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* use the sign to determine if we add or subtract */
                if (tval[i] >= 0) {
                        append(tval, tval[i] + random_rational_value());
                } else {
                        append(tval, tval[i] - random_rational_value());
                }
        }

        /*
         * expand all tval with tval * pi()
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {
                append(tval, tval[i] * pi());
        }

        /*
         * expand all tval with tval * 1i
         */
        tval_len = size(tval);
        /* tval[0] thru tval[real_cnt-1] are real values */
        real_cnt = tval_len;
        for (i=0; i < tval_len; ++i) {
                append(tval, tval[i] * 1i);
        }

        /*
         * expand tval with randomly selected real value
         * plus randomly selected complex value.
         */
        tval_len = size(tval);
        /* tval[real_cnt] thru tval[real_cnt+imag_cnt-1] are complex values */
        imag_cnt = tval_len - real_cnt;
        for (i=0; i < tval_len; ++i) {
                append(tval, tval[rand(0,real_cnt)] + tval[real_cnt + rand(0,imag_cnt)]);
        }

        /*
         * last, append our final 0 value
         */
        append(tval, 0);
}


/*
 * compute - form precomputed trigonometric value lists
 */
define precompute_trig()
{
        local tval_len;         /* current length of the tval[] array */
        local i;

        /*
         * firewall - be sure tval list is setup
         */
        if (size(tval) <= 0) {
                form_tval();
        }
        tval_len = size(tval);
        if (tval_len <= 0) {
                quit "FATAL: tval_len is empty";
        }

        /*
         * compute trigonometric sine of the tval full test list
         */
        for (i=0; i < tval_len; ++i) {
                append(sin_tval, sin(tval[i]));
        }
        if (size(tval) != size(sin_tval)) {
                print "****: size(tval):", size(tval), "!= size(sin_tval)", size(sin_tval);
                quit "FATAL: sin_tval not same size as tval_len";
        }

        /*
         * compute trigonometric cosine of the tval full test list
         */
        for (i=0; i < tval_len; ++i) {
                append(cos_tval, cos(tval[i]));
        }
        if (size(tval) != size(cos_tval)) {
                print "****: size(tval):", size(tval), "!= size(cos_tval)", size(cos_tval);
                quit "FATAL: cos_tval not same size as tval_len";
        }
}


/*
 * compare - compare the trigonometric identity and the trigonometric function value
 *
 * given:
 *      ident_val       computed trig value trigonometric identity
 *      trig_val        computed value from the trigonometric function
 *      name            trig function name
 *      index           test index value
 *      testnum         regression test number being performed
 *
 * returns:
 *      0 ==> trigonometric identity and the trigonometric function value match
 *      1 ==> trigonometric identity and the trigonometric function value do NOT match
 */
define compare(ident_val, trig_val, name, index, testnum)
{
        local abs_diff;         /* absolute difference between ident_val and trig_val */

        /*
         * firewall
         */
        if (!isnum(trig_val)) {
                printf("**** trig test %d-%d failed: %s(tval[%d]): ",
                       testnum, index, name, index);
                printf("%d returned a non-numeric value\n", trig_val);
                return 1;
        }

        /*
         * compute absolute difference
         */
        abs_diff = abs(ident_val - trig_val);

        /*
         * determine if ident_val within epsilon of trig_val
         */
        if (near(norm(abs_diff), epsilon_norm) > 0) {
                printf("**** trig test %d-%d failed: %s(tval[%d]): ",
                       testnum, index, name, index);
                printf("%d is not near trig identity value: %d\n",
                       trig_val, ident_val);
                return 1;
        }
        return 0;
}


/*
 * not_near_zero - determine if a value is within epsilon() of 0
 *
 * given:
 *      value   real or complex value
 *
 * returns:
 *      1 ==> value is farther from 0 than epsilon (not near zero)
 *      0 ==> value is within epsilon of 0 (near zero)
 */
define not_near_zero(value)
{
        if (near(norm(value), epsilon_norm) > 0) {
                /* value is farther from 0 than epsilon */
                return 1;
        }

        /* value is within epsilon of 0 */
        return 0;
}


/*
 * verify_tan - verify trigonometric tangent
 *
 * We use the following trigonometric identity:
 *
 *      tan(x) = sin(x) / cos(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_tan(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0 || size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        error_count = 0;
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(cos_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = sin_tval[i] / cos_tval[i];

                        /* compute trigonometric function */
                        trig_val = tan(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "tan", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': tan test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_cot - verify trigonometric cotangent
 *
 * We use the following trigonometric identity:
 *
 *      cot(x) = cos(x) / sin(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_cot(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0 || size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when sin(x) within epsilon of 0 */
                if (not_near_zero(sin_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = cos_tval[i] / sin_tval[i];

                        /* compute trigonometric function */
                        trig_val = cot(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "cot", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': cot test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_sec - verify trigonometric secant
 *
 * We use the following trigonometric identity:
 *
 *      sec(x) = 1 / cos(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_sec(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(cos_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = 1 / cos_tval[i];

                        /* compute trigonometric function */
                        trig_val = sec(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "sec", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': sec test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_csc - verify trigonometric cosecant
 *
 * We use the following trigonometric identity:
 *
 *      csc(x) = 1 / sin(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_csc(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when sin(x) within epsilon of 0 */
                if (not_near_zero(sin_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = 1 / sin_tval[i];

                        /* compute trigonometric function */
                        trig_val = csc(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "csc", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': csc test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_versin - verify versed trigonometric sine
 *
 * We use the following trigonometric identity:
 *
 *      versin(x) = 1 - cos(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_versin(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(cos_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = 1 - cos_tval[i];

                        /* compute trigonometric function */
                        trig_val = versin(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "versin", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': versin test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_coversin - verify coversed trigonometric sine
 *
 * We use the following trigonometric identity:
 *
 *      coversin(x) = 1 - sin(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_coversin(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when sin(x) within epsilon of 0 */
                if (not_near_zero(sin_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = 1 - sin_tval[i];

                        /* compute trigonometric function */
                        trig_val = coversin(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "coversin", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': coversin test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_vercos - verify versed trigonometric cosine
 *
 * We use the following trigonometric identity:
 *
 *      vercos(x) = 1 + cos(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_vercos(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(cos_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = 1 + cos_tval[i];

                        /* compute trigonometric function */
                        trig_val = vercos(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "vercos", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': vercos test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_covercos - verify coversed trigonometric cosine
 *
 * We use the following trigonometric identity:
 *
 *      covercos(x) = 1 + sin(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_covercos(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when sin(x) within epsilon of 0 */
                if (not_near_zero(sin_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = 1 + sin_tval[i];

                        /* compute trigonometric function */
                        trig_val = covercos(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "covercos", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': covercos test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_haversin - verify half versed trigonometric sine
 *
 * We use the following trigonometric identity:
 *
 *      haversin(x) = versin(x) / 2 = (1 - cos(x)) / 2
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_haversin(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(cos_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = (1 - cos_tval[i]) / 2;

                        /* compute trigonometric function */
                        trig_val = haversin(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "haversin", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': haversin test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_hacoversin - verify half versed trigonometric cosine
 *
 * We use the following trigonometric identity:
 *
 *      hacoversin(x) = coversin(x) / 2 = (1 - sin(x)) / 2
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_hacoversin(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(sin_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = (1 - sin_tval[i]) / 2;

                        /* compute trigonometric function */
                        trig_val = hacoversin(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "hacoversin", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': hacoversin test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_havercos - verify half versed trigonometric cosine
 *
 * We use the following trigonometric identity:
 *
 *      havercos(x) = vercos(x) / 2 = (1 + cos(x)) / 2
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_havercos(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(cos_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = (1 + cos_tval[i]) / 2;

                        /* compute trigonometric function */
                        trig_val = havercos(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "havercos", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': havercos test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_hacovercos - verify half coversed trigonometric cosine
 *
 * We use the following trigonometric identity:
 *
 *      hacovercos(x) = covercos(x) / 2 = (1 + sin(x)) / 2
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_hacovercos(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when sin(x) within epsilon of 0 */
                if (not_near_zero(sin_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = (1 + sin_tval[i]) / 2;

                        /* compute trigonometric function */
                        trig_val = hacovercos(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "hacovercos", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': hacovercos test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_exsec - exterior trigonometric secant
 *
 * We use the following trigonometric identity:
 *
 *      exsec(x) = sec(x) - 1 = (1 / cos(x)) - 1
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_exsec(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when cos(x) within epsilon of 0 */
                if (not_near_zero(cos_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = (1 / cos_tval[i]) - 1;

                        /* compute trigonometric function */
                        trig_val = exsec(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "exsec", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': exsec test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_excsc - verify trigonometric cosecant
 *
 * We use the following trigonometric identity:
 *
 *      excsc(x) = csc(x) - 1 = (1 / sin(x)) - 1
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_excsc(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* skip test when sin(x) within epsilon of 0 */
                if (not_near_zero(sin_tval[i])) {

                        /* compute trigonometric identity */
                        ident_val = (1 / sin_tval[i]) - 1;

                        /* compute trigonometric function */
                        trig_val = excsc(tval[i]);

                        /* compare trigonometric identity with trigonometric function value */
                        if (compare(ident_val, trig_val, "excsc", i, testnum)) {
                                ++error_count;
                        }
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': excsc test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_crd - verify trigonometric chord of a unit circle
 *
 * We use the following trigonometric identity:
 *
 *      crd(x) = 2 * sin(x / 2)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_crd(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* NOTE: We actually check the identity: crd(x*2) = 2 * sin(x) */

                /* compute trigonometric identity */
                ident_val = 2 * sin_tval[i];

                /* compute trigonometric function */
                trig_val = crd(tval[i] * 2);

                /* compare trigonometric identity with trigonometric function value */
                if (compare(ident_val, trig_val, "crd", i, testnum)) {
                        ++error_count;
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': crd test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_cas - verify cosine plus sine
 *
 * We use the following trigonometric identity:
 *
 *      cas(x) = cos(x) + sin(x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_cas(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* compute trigonometric identity */
                ident_val = cos_tval[i] + sin_tval[i];

                /* compute trigonometric function */
                trig_val = cas(tval[i]);

                /* compare trigonometric identity with trigonometric function value */
                if (compare(ident_val, trig_val, "cas", i, testnum)) {
                        ++error_count;
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': cas test failure count:', error_count;
        }
        return error_count;
}


/*
 * verify_cis - verify Euler's formula
 *
 * We use the following trigonometric identity:
 *
 *      cis(x) = cos(x) + i*sin(x)
 *      cis(x) = exp(1i * x)
 *
 * given:
 *      testnum         regression test number being performed
 *
 * returns:
 *      number of tests that failed
 */
define verify_cis(testnum)
{
        local tval_len;         /* current length of the tval[] array */
        local ident_val;        /* computed trig value trigonometric identity */
        local trig_val;         /* computed value from the trigonometric function */
        local error_count;      /* number of compare errors detected */
        local i;

        /*
         * firewall
         */
        if (size(sin_tval) <= 0) {
                precompute_trig();
        }
        if (size(cos_tval) <= 0) {
                precompute_trig();
        }

        /*
         * for each test value, verify the trigonometric identity within epsilon
         */
        tval_len = size(tval);
        for (i=0; i < tval_len; ++i) {

                /* compute trigonometric identity */
                ident_val = cos_tval[i] + 1i*sin_tval[i];

                /* compute trigonometric function */
                trig_val = cis(tval[i]);

                /* compare trigonometric identity with trigonometric function value */
                if (compare(ident_val, trig_val, "cis", i, testnum)) {
                        ++error_count;
                }
        }

        /*
         * report test results
         */
        if (error_count != 0) {
                print '**** test', testnum : ': cis test failure count:', error_count;
        }
        return error_count;
}
