/*
 * test3400 - 3400 series of the regress.cal test suite
 *
 * Copyright (C) 1999  Ernest Bowen and Landon Curt Noll
 *
 * Primary author:  Ernest Bowen
 *
 * 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:	1995/12/02 05:20:11
 * File existed as early as:	1995
 *
 * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/
 */

/*
 * tests of performance of some trigonometric functions
 *
 * test3401 tests abs(acot(cot(x)) - x) <= eps for x = k * eps < pi
 * test3402 tests abs(tan(x/2) - csc(x) + cot(x)) <= eps
 * test3403 tests abs(tan(x) - cot(x) + 2 * cot(2 * x)) <= eps
 * test3404 tests abs(cot(x/2) - csc(x) - cot(x)) <= eps
 * test3405 tests atan(tan(x)) == x for x = k * eps, abs(x) <= pi/2
 * test3406 tests abs(sec(x) - sec(x + 2 * N * pi)) <= eps
 *
 * To run say, test1 n times give instruction test1(n, eps); eps
 * defaults to epsilon().
 *
 * Here pi1k is pi to 1000 decimal places; x is a random real number
 * except when x is described as k * eps, in which case k is a random
 * integer such that x is in the specified range.
 *
 * In the last test N is a large random integer, but it is assumed
 * that eps is large compared with N * 1e-1000.
 *
 * I am surprised that test3406 seems to give no errors - I had expected
 * that the two sides might differ by eps.  [[test changed to test eps error]]
 */


defaultverbose = 1;	/* default verbose value */

global pi1k = pi(1e-1000);

define test3401(str, n, eps, verbose)
{
	local i, m, x, y, N;

	if (isnull(verbose)) verbose = defaultverbose;
	if (verbose > 0) {
		print str:":",:;
	}
	if (isnull(n)) n = 250;
	if (isnull(eps)) eps = epsilon();

	m = 0;
	N = pi(eps)/eps;
	for (i = 0; i < n; i++) {
		x = rand(1, N) * eps;
		y = cot(x, eps);
		if (verbose > 1)
			printf("%r\n", x);
		if (abs(acot(y, eps) - x) > eps) {
			if (verbose > 1) {
				printf("*** Failure for x = %r\n", x);
			}
			m++;
		}
	}
	if (verbose > 0) {
		if (m) {
			printf("*** %d error(s)\n", m);
		} else {
			printf("no errors\n");
		}
	}
	return m;
}

define test3402(str, n, eps, verbose)
{
	local i, m, x, y, N;

	if (isnull(verbose)) verbose = defaultverbose;
	if (verbose > 0) {
		print str:":",:;
	}
	if (isnull(n)) n = 250;
	if (isnull(eps)) eps = epsilon();

	eps = abs(eps);
	m = 0;
	N = 1e10;
	for (i = 0; i < n; i++) {
		x = rand(-N, N)/rand(1, N);
		y = tan(x/2, eps) - csc(x,eps) + cot(x,eps);
		if (verbose > 1)
			printf("%r\n", x);
		if (abs(y) > eps) {
			if (verbose > 1) {
				printf("*** Failure for x = %r\n", x);
			}
			m++;
		}
	}
	if (verbose > 0) {
		if (m) {
			printf("*** %d error(s)\n", m);
		} else {
			printf("no errors\n");
		}
	}
	return m;
}

define test3403(str, n, eps, verbose)
{
	local i, m, x, y, N;

	if (isnull(verbose)) verbose = defaultverbose;
	if (verbose > 0) {
		print str:":",:;
	}
	if (isnull(n)) n = 250;
	if (isnull(eps)) eps = epsilon();

	eps = abs(eps);
	m = 0;
	N = 1e10;
	for (i = 0; i < n; i++) {
		x = rand(-N, N)/rand(1, N);
		y = tan(x, eps) - cot(x,eps) + 2 * cot(2 * x,eps);
		if (verbose > 1)
			printf("%r\n", x);
		if (abs(y) > eps) {
			m++;
			if (verbose > 1) {
				printf("*** Failure for x = %r\n", x);
			}
		}
	}
	if (verbose > 0) {
		if (m) {
			printf("*** %d error(s)\n", m);
		} else {
			printf("no errors\n");
		}
	}
	return m;
}

define test3404(str, n, eps, verbose)
{
	local i, m, x, y, N;

	if (isnull(verbose)) verbose = defaultverbose;
	if (verbose > 0) {
		print str:":",:;
	}
	if (isnull(n)) n = 250;
	if (isnull(eps)) eps = epsilon();

	eps = abs(eps);
	m = 0;
	N = 1e10;
	for (i = 0; i < n; i++) {
		x = rand(-N, N)/rand(1, N);
		y = cot(x/2, eps) - csc(x,eps) - cot(x,eps);
		if (verbose > 1)
			printf("%r\n", x);
		if (abs(y) > eps) {
			m++;
			if (verbose > 1) {
				printf("*** Failure for x = %r\n", x);
			}
		}
	}
	if (verbose > 0) {
		if (m) {
			printf("*** %d error(s)\n", m);
		} else {
			printf("no errors\n");
		}
	}
	return m;
}

define test3405(str, n, eps, verbose)
{
	local i, m, x, y, N;

	if (isnull(verbose)) verbose = defaultverbose;
	if (verbose > 0) {
		print str:":",:;
	}
	if (isnull(n)) n = 250;
	if (isnull(eps)) eps = epsilon();

	m = 0;
	N = pi(eps)/eps;
	N = quo(N, 2, 0);
	for (i = 0; i < n; i++) {
		x = rand(-N, N) * eps;
		y = tan(x, eps);
		if (verbose > 1)
			printf("%r\n", x);
		if (atan(y, eps) != x) {
			m++;
			if (verbose > 1) {
				printf("*** Failure for x = %r\n", x);
			}
		}
	}
	if (verbose > 0) {
		if (m) {
			printf("*** %d error(s)\n", m);
		} else {
			printf("no errors\n");
		}
	}
	return m;
}

define test3406(str, n, eps, verbose)
{
	local i, m, x, y, z, N;

	if (isnull(verbose)) verbose = defaultverbose;
	if (verbose > 0) {
		print str:":",:;
	}
	if (isnull(n)) n = 250;
	if (isnull(eps)) eps = epsilon();

	m = 0;
	for (i = 0; i < n; i++) {
		x = rand(-1e10, 1e10)/rand(1, 1e10);
		N = rand(-1e10, 1e10);
		y = sec(x, eps);
		z = sec(x + 2 * N * pi1k, eps);
		if (verbose > 1)
			printf("%r, %d\n", x, N);
		if (abs(y-z) > eps) {
			m++;
			if (verbose > 1) {
				printf("*** Failure for x = %r\n", x);
			}
		}
	}
	if (verbose > 0) {
		if (m) {
			printf("*** %d error(s)\n", m);
		} else {
			printf("no errors\n");
		}
	}
	return m;
}

/*
 * test3400 - perform all of the above tests
 */
define test3400(verbose, tnum)
{
	local n;	/* test parameter */
	local eps;	/* test parameter */
	local i;

	/*
	 * set test parameters
	 */
	if (isnull(verbose)) {
		verbose = defaultverbose;
	}
	n = 250;
	eps = epsilon();
	srand(3400e3400);

	/*
	 * test a lot of stuff
	 */
	err += test3401(strcat(str(tnum++), \
		     ": acot(cot(x))"), n, eps, verbose);
	err += test3402(strcat(str(tnum++), \
		     ": tan(x/2)-csc(x)+cot(x)"), n, eps, verbose);
	err += test3403(strcat(str(tnum++), \
		     ": tan(x)-cot(x)+2*cot(2*x)"), n, eps, verbose);
	err += test3404(strcat(str(tnum++), \
		     ": cot(x/2)-csc(x)-cot(x)"), n, eps, verbose);
	err += test3405(strcat(str(tnum++), \
		     ": atan(tan(x))"), n, eps, verbose);
	err += test3406(strcat(str(tnum++), \
		     ": sec(x)-sec(x+2*N*pi)"), n, eps, verbose);

	/*
	 * test results
	 */
	if (verbose > 1) {
		if (err) {
			print "***", err, "error(s) found in test3400";
		} else {
			print "no errors in test3400";
		}
	}
	return tnum;
}
