mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
To make the meaning a bit more clear in cal/regress.cal, we have renamed the following test calc resource files that are related to the calc regression test suite: cal/test1700.cal -> cal/test8000.read.cal cal/test2300.cal -> cal/test2300.obj_incdec.cal cal/test2600.cal -> cal/test2600.numfunc.cal cal/test2700.cal -> cal/test2700.isqrt.cal cal/test3100.cal -> cal/test3100.matobj.cal cal/test3400.cal -> cal/test3400.trig.cal cal/test4000.cal -> cal/test4000.ptest.cal cal/test4100.cal -> cal/test4100.redc.cal cal/test4600.cal -> cal/test4600.fileop.cal cal/test5100.cal -> cal/test5100.newdecl.cal cal/test5200.cal -> cal/test5200.globstat.cal cal/test8400.cal -> cal/test8400.quit.cal cal/test8500.cal -> cal/test8500.divmod.cal cal/test8600.cal -> cal/test8600.maxargs.cal cal/set8700.cal -> cal/test8700.dotest.cal cal/test8900.cal -> cal/test8900.special.cal cal/test9300.cal -> cal/test9300.frem.cal Added to test 94dd, read of a number of new calc resource files that are not already read as a result of the calc regression test suite.
613 lines
13 KiB
Plaintext
613 lines
13 KiB
Plaintext
/*
|
|
* test2600.builtin0 - test numeric functions extensively for test 26dd
|
|
*
|
|
* Copyright (C) 1999,2021,2023 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/10/13 00:13:14
|
|
* File existed as early as: 1995
|
|
*
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
/*
|
|
* Stringent tests of some of calc's builtin functions.
|
|
* Most of the tests are concerned with the accuracy of the value
|
|
* returned for a function; usually it is expected that
|
|
* remainder (true value - calculated value) will be less in
|
|
* absolute value than "epsilon", where this is either a specified
|
|
* argument eps, or if this is omitted, the current value of epsilon().
|
|
* In some cases the remainder is to have a particular sign, or to
|
|
* have absolute value not exceeding eps/2, or in some cases 3 * eps/4.
|
|
*
|
|
* Typical of these tests is testpower("power", n, b, eps, verbose).
|
|
* Here n is the number of numbers a for which power(a, b, eps) is to
|
|
* be evaluated; the ratio c = (true value - calculated value)/eps
|
|
* is calculated and if this is not less in absolute value than
|
|
* 0.75, a "failure" is recorded and the value of a displayed.
|
|
* On completion of the tests, the minimum and maximum values of
|
|
* c are displayed.
|
|
*
|
|
* The numbers a are usually large "random" integers or sometimes
|
|
* ratios of such integers. In some cases the formulae used to
|
|
* calculate c assume eps is small compared with the value of the
|
|
* function. If eps is very small, say 1e-1000, or if the denominator
|
|
* of b in power(a, b, eps) is large, the computation required for
|
|
* a test may be very heavy.
|
|
*
|
|
* Test functions are called as:
|
|
*
|
|
* testabc(str, ..., verbose)
|
|
*
|
|
* where str is a string that names the test. This string is printed
|
|
* without a newline (if verbose > 0), near the beginning of the function.
|
|
* The verbose parameter controls how verbose the test will be:
|
|
*
|
|
* 0 - print nothing
|
|
* 1 - print str and the error count
|
|
* 2 - print min and max errors as well
|
|
* 3 - print everything including individual loop counts
|
|
*
|
|
* All functions return the number of errors that they detected.
|
|
*/
|
|
|
|
|
|
global defaultverbose = 1; /* default verbose value */
|
|
global err;
|
|
|
|
define testismult(str, n, verbose)
|
|
{
|
|
local a, b, c, i, m;
|
|
|
|
if (isnull(verbose)) verbose = defaultverbose;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
m = 0;
|
|
for (i = 0; i < n; i++) {
|
|
if (verbose > 2) print i,:;
|
|
a = scale(rand(1,1e1000), rand(100));
|
|
b = scale(rand(1,1e1000), rand(100));
|
|
c = a * b;
|
|
if (!ismult(c,a)) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** Failure with:\na = %d\nb = %d\n",
|
|
a,b);
|
|
}
|
|
}
|
|
}
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
define testsqrt(str, n, eps, verbose)
|
|
{
|
|
local a, c, i, x, m, min, max;
|
|
|
|
if (isnull(verbose)) verbose = 2;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
m = 0;
|
|
min = 1000;
|
|
max = -1000;
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
for (i = 1; i <= n; i++) {
|
|
if (verbose > 2) print i,:;
|
|
a = scale(rand(1,1000), rand(100));
|
|
x = sqrt(a, eps);
|
|
if (x)
|
|
c = (a/x - x)/2/eps;
|
|
else
|
|
c = a/eps; /* ??? */
|
|
if (c < min)
|
|
min = c;
|
|
if (c > max)
|
|
max = c;
|
|
if (abs(c) > 1) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** Failure with:\na = %d\neps = %d\n",
|
|
a,eps);
|
|
}
|
|
}
|
|
}
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
printf(" %s: rem/eps min=%d, max=%d\n",
|
|
str, min, max);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
if (verbose > 1) {
|
|
printf(" %s: rem/eps min=%0.4d, max=%0.4d\n", str, min, max);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
|
|
define testexp(str, n, eps, verbose)
|
|
{
|
|
local i, a, c, m, min, max;
|
|
|
|
if (isnull(verbose)) verbose = 2;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
min = 1000;
|
|
max = -1000;
|
|
for (i = 1; i <= n; i++) {
|
|
if (verbose > 2) print i,:;
|
|
a = rand(1,1e20)/rand(1,1e20) + rand(50);
|
|
if (rand(1))
|
|
a = -a;
|
|
c = cexp(a, eps);
|
|
if (c < min)
|
|
min = c;
|
|
if (c > max)
|
|
max = c;
|
|
if (abs(c) > 0.02) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** Failure with:\na = %d\neps = %d\n",
|
|
a,eps);
|
|
}
|
|
}
|
|
}
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
printf(" %s: rem/eps min=%d, max=%d\n",
|
|
str, min, max);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
if (verbose > 1) {
|
|
printf(" %s: rem/eps min=%0.4d, max=%0.4d\n", str, min, max);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
|
|
define cexp(x,eps) /* Find relative rem/eps for exp(x, eps) */
|
|
{
|
|
local eps1, v, v1, c;
|
|
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
eps1 = eps * 1e-6;
|
|
v = exp(x, eps);
|
|
v1 = exp(x, eps1);
|
|
c = round((v1 - v)/v1/eps, 6, 24);
|
|
return c;
|
|
}
|
|
|
|
|
|
define testln(str, n, eps, verbose)
|
|
{
|
|
local i, a, c, m, min, max;
|
|
|
|
if (isnull(verbose)) verbose = 2;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
min = 1000;
|
|
max = -1000;
|
|
for (i = 1; i <= n; i++) {
|
|
if (verbose > 2) print i,:;
|
|
a = rand(1,1e20)/rand(1,1e20) + rand(50);
|
|
c = cln(a, eps);
|
|
if (c < min)
|
|
min = c;
|
|
if (c > max)
|
|
max = c;
|
|
if (abs(c) > 0.5) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** Failure with:\na = %d\neps = %d\n",
|
|
a,eps);
|
|
}
|
|
}
|
|
}
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
printf(" %s: rem/eps min=%d, max=%d\n",
|
|
str, min, max);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
if (verbose > 1) {
|
|
printf(" %s: rem/eps min=%0.4d, max=%0.4d\n", str, min, max);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
define cln(a, eps)
|
|
{
|
|
local eps1, v, v1, c;
|
|
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
eps1 = eps/1e6;
|
|
v = ln(a, eps);
|
|
v1 = ln(a, eps1);
|
|
c = round((v1 - v)/eps, 6, 24);
|
|
return c;
|
|
}
|
|
|
|
|
|
define testpower(str, n, b, eps, verbose)
|
|
{
|
|
local i, a, c, m, min, max;
|
|
|
|
if (isnull(verbose)) verbose = 2;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
if (!isnum(b))
|
|
quit "Second argument (exponent) to be a number";
|
|
min = 1000;
|
|
max = -1000;
|
|
for (i = 1; i <= n; i++) {
|
|
if (verbose > 2) print i,:;
|
|
a = rand(1,1e20)/rand(1,1e20);
|
|
c = cpow(a, b, eps);
|
|
if (abs(c) > .75) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** Failure for a = %d\n", a);
|
|
}
|
|
}
|
|
if (c < min)
|
|
min = c;
|
|
if (c > max)
|
|
max = c;
|
|
}
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
printf(" %s: rem/eps min=%d, max=%d\n",
|
|
str, min, max);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
if (verbose > 1) {
|
|
printf(" %s: rem/eps min=%0.4d, max=%0.4d\n", str, min, max);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
|
|
define testpower2(str, n, eps, verbose)
|
|
{
|
|
local i, a, c, m, min, max;
|
|
local b;
|
|
local num;
|
|
local c2;
|
|
local oldeps;
|
|
|
|
if (isnull(verbose)) verbose = 2;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
oldeps = epsilon(eps);
|
|
epsilon(eps),;
|
|
if (!isnum(b))
|
|
quit "Second argument (exponent) to be a number";
|
|
min = 1000;
|
|
max = -1000;
|
|
for (i = 1; i <= n; i++) {
|
|
if (verbose > 2) print i,:;
|
|
|
|
/* real ^ real */
|
|
a = rand(1,1e20);
|
|
a = a / (int(a/2)+rand(1,1e20));
|
|
b = rand(1,1e20);
|
|
b = b / (int(b/2)+rand(1,1e20));
|
|
c = a ^ b;
|
|
c2 = power(a, b);
|
|
if (c != c2) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** real^real failure for a = %d\n", a);
|
|
}
|
|
}
|
|
|
|
/* complex ^ real */
|
|
a = rand(1,1e20);
|
|
a = a / (int(a/2)+rand(1,1e20));
|
|
b = rand(1,1e20);
|
|
b = b / (int(b/2)+rand(1,1e20));
|
|
c = (a*1i) ^ b;
|
|
c2 = power(a*1i, b);
|
|
if (c != c2) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** comp^real failure for a = %d\n", a);
|
|
}
|
|
}
|
|
|
|
/* real ^ complex */
|
|
a = rand(1,1e20);
|
|
a = a / (int(a/2)+rand(1,1e20));
|
|
b = rand(1,1e20);
|
|
b = b / (int(b/2)+rand(1,1e20));
|
|
c = a ^ (b*1i);
|
|
c2 = power(a, b*1i);
|
|
if (c != c2) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** real^comp failure for a = %d\n", a);
|
|
}
|
|
}
|
|
|
|
/* complex ^ complex */
|
|
a = rand(1,1e20);
|
|
a = a / (int(a/2)+rand(1,1e20));
|
|
b = rand(1,1e20);
|
|
b = b / (int(b/2)+rand(1,1e20));
|
|
c = (a*1i) ^ (b*1i);
|
|
c2 = power(a*1i, b*1i);
|
|
if (c != c2) {
|
|
m++;
|
|
if (verbose > 1) {
|
|
printf("*** comp^comp failure for a = %d\n", a);
|
|
}
|
|
}
|
|
}
|
|
epsilon(oldeps),;
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
printf(" %s: rem/eps min=%d, max=%d\n",
|
|
str, min, max);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
if (verbose > 1) {
|
|
printf(" %s: rem/eps min=%0.4d, max=%0.4d\n", str, min, max);
|
|
}
|
|
return m;
|
|
}
|
|
|
|
|
|
define cpow(a, b, eps) /* Find rem/eps for power(a,b,eps) */
|
|
{
|
|
local v, v1, c, n, d, h;
|
|
|
|
if (isnull(eps))
|
|
eps = epsilon();
|
|
n = num(b);
|
|
d = den(b);
|
|
|
|
v = power(a, b, eps);
|
|
h = (a^n/v^d - 1) * v/d;
|
|
c = round(h/eps, 6, 24);
|
|
return c;
|
|
}
|
|
|
|
define testgcd(str, n, verbose)
|
|
{
|
|
local i, a, b, g, m;
|
|
|
|
if (isnull(verbose)) verbose = 2;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
m = 0;
|
|
for (i = 1; i <= n; i++) {
|
|
if (verbose > 2) print i,:;
|
|
a = rand(1,1e1000);
|
|
b = rand(1,1e1000);
|
|
g = gcd(a,b);
|
|
if (!ismult(a,g) || !ismult(b,g) || !g || !isrel(a/g, b/g)) {
|
|
m++;
|
|
printf("*** Failure for a = %d, b = %d\n", a, b);
|
|
}
|
|
}
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
define mkreal() = scale(rand(-1000,1001)/rand(1,1000), rand(-100, 101));
|
|
|
|
define mkcomplex() = mkreal() + 1i * mkreal();
|
|
|
|
define mkbigreal()
|
|
{
|
|
local x;
|
|
|
|
x = rand(100, 1000)/rand(1,10);
|
|
if (rand(2))
|
|
x = -x;
|
|
return x;
|
|
}
|
|
|
|
define mksmallreal() = rand(-10, 11)/rand(100,1000);
|
|
|
|
define testappr(str, n, verbose)
|
|
{
|
|
local x, y, z, m, i, p;
|
|
|
|
if (isnull(verbose))
|
|
verbose = defaultverbose;
|
|
if (verbose > 0) {
|
|
print str:":",:;
|
|
}
|
|
m = 0;
|
|
for (i = 1; i <= n; i++) {
|
|
x = rand(3) ? mkreal(): mkcomplex();
|
|
y = mkreal();
|
|
if (verbose > 2)
|
|
printf(" %d: x = %d, y = %d\n", i, x, y);
|
|
|
|
for (z = 0; z < 32; z++) {
|
|
p = checkappr(x,y,z,verbose);
|
|
if (p) {
|
|
printf("*** Failure for x=%d, y=%d, z=%d\n",
|
|
x, y, z);
|
|
m++;
|
|
}
|
|
}
|
|
}
|
|
if (verbose > 0) {
|
|
if (m) {
|
|
printf("*** %d error(s)\n", m);
|
|
} else {
|
|
printf("no errors\n");
|
|
}
|
|
}
|
|
return m;
|
|
}
|
|
|
|
|
|
define checkappr(x,y,z,verbose) /* Returns 1 if an error is detected */
|
|
{
|
|
local a;
|
|
|
|
a = appr(x,y,z);
|
|
if (verbose > 1)
|
|
printf("\ta = %d\n", a);
|
|
if (isreal(x))
|
|
return checkresult(x,y,z,a);
|
|
if (isnum(x))
|
|
return checkresult(re(x), y, z, re(a))
|
|
| checkresult(im(x), y, z, im(a));
|
|
|
|
quit "Bad first argument for checkappr()";
|
|
}
|
|
|
|
define checkresult(x,y,z,a) /* tests correctness of a = appr(x,y,z) */
|
|
{
|
|
local r, n, s, v;
|
|
|
|
if (y == 0)
|
|
return (a != x);
|
|
r = x - a;
|
|
n = a/y;
|
|
|
|
if (!isint(n))
|
|
return 1;
|
|
if (abs(r) >= abs(y))
|
|
return 1;
|
|
if (r == 0)
|
|
return 0;
|
|
if (z & 16) {
|
|
if (abs(r) > abs(y)/2)
|
|
return 1;
|
|
if (abs(r) < abs(y)/2)
|
|
return 0;
|
|
z &= 15;
|
|
}
|
|
s = sgn(r);
|
|
switch (z) {
|
|
case 0: v = (s == sgn(y)); break;
|
|
case 1: v = (s == -sgn(y)); break;
|
|
case 2: v = (s == sgn(x)); break;
|
|
case 3: v = (s == -sgn(x)); break;
|
|
case 4: v = (s > 0); break;
|
|
case 5: v = (s < 0); break;
|
|
case 6: v = (s == sgn(x/y)); break;
|
|
case 7: v = (s == -sgn(x/y)); break;
|
|
case 8: v = iseven(n); break;
|
|
case 9: v = isodd(n); break;
|
|
case 10: v = (x/y > 0) ? iseven(n) : isodd(n); break;
|
|
case 11: v = (x/y > 0) ? isodd(n) : iseven(n); break;
|
|
case 12: v = (y > 0) ? iseven(n) : isodd(n); break;
|
|
case 13: v = (y > 0) ? isodd(n) : iseven(n); break;
|
|
case 14: v = (x > 0) ? iseven(n) : isodd(n); break;
|
|
case 15: v = (x > 0) ? isodd(n) : iseven(n); break;
|
|
}
|
|
return !v;
|
|
}
|
|
|
|
/*
|
|
* test2600 - perform all of the above tests a bunch of times
|
|
*/
|
|
define test2600(verbose, tnum)
|
|
{
|
|
local n; /* test parameter */
|
|
local ep; /* test parameter */
|
|
local i;
|
|
|
|
/* set test parameters */
|
|
n = 5; /* internal test loop count */
|
|
if (isnull(verbose)) {
|
|
verbose = defaultverbose;
|
|
}
|
|
if (isnull(tnum)) {
|
|
tnum = 1; /* initial test number */
|
|
}
|
|
|
|
/*
|
|
* test a lot of stuff
|
|
*/
|
|
srand(2600e2600);
|
|
ep = 1e-250;
|
|
err += testismult(strcat(str(tnum++), ": mult"), n*20, verbose);
|
|
err += testappr(strcat(str(tnum++), ": appr"), n*40, verbose);
|
|
err += testexp(strcat(str(tnum++),": exp"), n, ep, verbose);
|
|
err += testln(strcat(str(tnum++),": ln"), n, ep, verbose);
|
|
err += testpower(strcat(str(tnum++),": power"), n,
|
|
rand(2,10), ep, verbose);
|
|
err += testgcd(strcat(str(tnum++),": gcd"), n, ep, verbose);
|
|
for (i=0; i < 32; ++i) {
|
|
config("sqrt", i);
|
|
err += testsqrt(strcat(str(tnum++),": sqrt",str(i)), n*10,
|
|
ep, verbose);
|
|
}
|
|
err += testpower2(strcat(str(tnum++),": power"), n*4, ep, verbose);
|
|
if (verbose > 1) {
|
|
if (err) {
|
|
print "***", err, "error(s) found in test2600";
|
|
} else {
|
|
print "no errors in test2600";
|
|
}
|
|
}
|
|
return tnum;
|
|
}
|