Release calc version 2.11.3t0

This commit is contained in:
Landon Curt Noll
2000-07-14 00:55:58 -07:00
parent 61dd47526f
commit ae2a752314
33 changed files with 2784 additions and 1556 deletions

339
zfunc.c
View File

@@ -20,7 +20,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* @(#) $Revision: 29.2 $
* @(#) $Id: zfunc.c,v 29.2 2000/06/07 14:02:13 chongo Exp $
* @(#) $Id: zfunc.c,v 29.2 2000/06/07 14:02:13 chongo Exp chongo $
* @(#) $Source: /usr/local/src/cmd/calc/RCS/zfunc.c,v $
*
* Under source code control: 1990/02/15 01:48:27
@@ -51,7 +51,7 @@ zfact(ZVALUE z, ZVALUE *dest)
math_error("Negative argument for factorial");
/*NOTREACHED*/
}
if (zge24b(z)) {
if (zge31b(z)) {
math_error("Very large factorial");
/*NOTREACHED*/
}
@@ -108,7 +108,7 @@ zperm(ZVALUE z1, ZVALUE z2, ZVALUE *res)
math_error("Second arg larger than first in permutation");
/*NOTREACHED*/
}
if (zge24b(z2)) {
if (zge31b(z2)) {
math_error("Very large permutation");
/*NOTREACHED*/
}
@@ -127,58 +127,104 @@ zperm(ZVALUE z1, ZVALUE z2, ZVALUE *res)
*res = ans;
}
/*
* Compute the combinatorial function M! / ( N! * (M - N)! ).
* docomb evaluates binomial coefficient when z1 >= 0, z2 >= 0
*/
void
zcomb(ZVALUE z1, ZVALUE z2, ZVALUE *res)
static int
docomb(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
ZVALUE ans;
ZVALUE mul, div, temp;
FULL count, i;
#if BASEB == 16
HALF dh[2];
#else
HALF dh[1];
#endif
if (zisneg(z1) || zisneg(z2)) {
math_error("Negative argument for combinatorial");
/*NOTREACHED*/
}
if (zrel(z2, z1) > 0)
return 0;
zsub(z1, z2, &temp);
if (zisneg(temp)) {
if (zge31b(z2) && zge31b(temp)) {
zfree(temp);
math_error("Second arg larger than first for combinatorial");
/*NOTREACHED*/
return -2;
}
if (zge24b(z2) && zge24b(temp)) {
zfree(temp);
math_error("Very large combinatorial");
/*NOTREACHED*/
}
count = ztofull(z2);
i = ztofull(temp);
if (zge24b(z2) || (!zge24b(temp) && (i < count)))
count = i;
if (zrel(temp, z2) < 0)
count = ztofull(temp);
else
count = ztofull(z2);
zfree(temp);
mul = z1;
if (count == 0)
return 1;
if (count == 1)
return 2;
div.sign = 0;
div.v = dh;
ans = _one_;
for (i = 1; i <= count; i++) {
div.len = 1;
zcopy(z1, &mul);
zcopy(z1, &ans);
for (i = 2; i <= count; i++) {
#if BASEB == 16
dh[0] = (HALF)(i & BASE1);
dh[1] = (HALF)(i >> BASEB);
div.len = 1 + (dh[1] != 0);
#else
dh[0] = (HALF) i;
#endif
zsub(mul, _one_, &temp);
zfree(mul);
mul = temp;
zmul(ans, mul, &temp);
zfree(ans);
zquo(temp, div, &ans, 0);
zfree(temp);
zsub(mul, _one_, &temp);
if (mul.v != z1.v)
zfree(mul);
mul = temp;
}
if (mul.v != z1.v)
zfree(mul);
zfree(mul);
*res = ans;
return 3;
}
/*
* Compute the combinatorial function M! / ( N! * (M - N)! ).
* Returns 0 if result is 0
* 1 1
* 2 z1
* -1 -1
* -2 if too complicated
* 3 result stored at res
*/
int
zcomb(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
ZVALUE z3, z4;
int r;
if (z2.sign || (!z1.sign && zrel(z2, z1) > 0))
return 0;
if (zisone(z2))
return 2;
if (z1.sign) {
z1.sign = 0;
zsub(z1, _one_, &z3);
zadd(z3, z2, &z4);
zfree(z3);
r = docomb(z4, z2, res);
if (r == 2) {
*res = z4;
r = 3;
}
else
zfree(z4);
if (z2.v[0] & 1) {
if (r == 1)
r = -1;
if (r == 3)
res->sign = 1;
}
return r;
}
return docomb(z1, z2, res);
}
@@ -474,7 +520,7 @@ ztenpow(long power, ZVALUE *res)
/*
* Calculate modular inverse suppressing unnecessary divisions.
* This is based on the Euclidian algorithm for large numbers.
* This is based on the Euclidean algorithm for large numbers.
* (Algorithm X from Knuth Vol 2, section 4.5.2. and exercise 17)
* Returns TRUE if there is no solution because the numbers
* are not relatively prime.
@@ -1021,108 +1067,76 @@ zrelprime(ZVALUE z1, ZVALUE z2)
/*
* Compute the log of one number base another, to the closest integer.
* This is the largest integer which when the second number is raised to it,
* the resulting value is less than or equal to the first number.
* Compute the integer floor of the log of an integer to a specified base.
* The signs of the integers and base are ignored.
* Example: zlog(123456, 10) = 5.
*/
long
zlog(ZVALUE z1, ZVALUE z2)
zlog(ZVALUE z, ZVALUE base)
{
register ZVALUE *zp; /* current square */
ZVALUE *zp; /* current square */
long power; /* current power */
long worth; /* worth of current square */
ZVALUE val; /* current value of power */
ZVALUE temp; /* temporary */
ZVALUE squares[32]; /* table of squares of base */
/* ignore signs */
z.sign = 0;
base.sign = 0;
/*
* Make sure that the numbers are > 0 and the base is > 1
* Make sure that the numbers are nonzero and the base is > 1
*/
if (zislezero(z1) || zisleone(z2)) {
math_error("Bad arguments for log");
if (ziszero(z) || ziszero(base) || zisone(base)) {
math_error("Zero or too small argument argument for zlog!!!");
/*NOTREACHED*/
}
/*
* Reject trivial cases.
* Some trivial cases.
*/
if (z1.len < z2.len)
return 0;
if ((z1.len == z2.len) && (z1.v[z1.len-1] < z2.v[z2.len-1]))
return 0;
power = zrel(z1, z2);
power = zrel(z, base);
if (power <= 0)
return (power + 1);
/*
* Handle any power of two special.
*/
if (zisonebit(z2))
return (zhighbit(z1) / zlowbit(z2));
/*
* Handle base 10 special
*/
if ((z2.len == 1) && (*z2.v == 10))
return zlog10(z1);
/* base - power of two */
if (zisonebit(base))
return (zhighbit(z) / zlowbit(base));
/* base = 10 */
if (base.len == 1 && base.v[0] == 10)
return zlog10(z);
/*
* Now loop by squaring the base each time, and see whether or
* not each successive square is still smaller than the number.
*/
worth = 1;
zp = &squares[0];
*zp = z2;
while (((zp->len * 2) - 1) <= z1.len) { /* while square not too large */
*zp = base;
while (zp->len * 2 - 1 <= z.len && zrel(z, *zp) > 0) {
/* while square not too large */
zsquare(*zp, zp + 1);
zp++;
worth *= 2;
}
/*
* Now back down the squares, and multiply them together to see
* exactly how many times the base can be raised by.
* Now back down the squares,
*/
val = _one_;
power = 0;
/*
* We prevent the zp pointer from walking behind squares
* by stopping one short of the end and running the loop one
* more time.
*
* We could stop the loop with just zp >= squares, but stopping
* short and running the loop one last time manually helps make
* code checkers such as insure happy.
*/
for (; zp > squares; zp--, worth /= 2) {
if ((val.len + zp->len - 1) <= z1.len) {
zmul(val, *zp, &temp);
if (zrel(z1, temp) >= 0) {
zfree(val);
val = temp;
power += worth;
} else {
zfree(temp);
}
for (; zp > squares; zp--) {
if (zrel(z, *zp) >= 0) {
zquo(z, *zp, &temp, 0);
if (power)
zfree(z);
z = temp;
power++;
}
if (zp != squares)
zfree(*zp);
zfree(*zp);
power <<= 1;
}
/* run the loop manually one last time */
if (zp == squares) {
if ((val.len + zp->len - 1) <= z1.len) {
zmul(val, *zp, &temp);
if (zrel(z1, temp) >= 0) {
zfree(val);
val = temp;
power += worth;
} else {
zfree(temp);
}
}
if (zp != squares)
zfree(*zp);
}
zfree(val);
if (zrel(z, *zp) >= 0)
power++;
if (power > 1)
zfree(z);
return power;
}
@@ -1135,70 +1149,50 @@ zlog10(ZVALUE z)
{
register ZVALUE *zp; /* current square */
long power; /* current power */
long worth; /* worth of current square */
ZVALUE val; /* current value of power */
ZVALUE temp; /* temporary */
if (!zispos(z)) {
math_error("Non-positive number for log10");
if (ziszero(z)) {
math_error("Zero argument argument for zlog10");
/*NOTREACHED*/
}
/* Ignore sign of z */
z.sign = 0;
/*
* Loop by squaring the base each time, and see whether or
* not each successive square is still smaller than the number.
*/
worth = 1;
zp = &_tenpowers_[0];
*zp = _ten_;
while (((zp->len * 2) - 1) <= z.len) { /* while square not too large */
if (zp >= &_tenpowers_[TEN_MAX]) {
math_error("Maximum storable power of 10 reached!");
/*NOTREACHED*/
}
if (zp[1].len == 0)
zsquare(*zp, zp + 1);
zp++;
worth *= 2;
}
/*
* Now back down the squares, and multiply them together to see
* exactly how many times the base can be raised by.
*/
val = _one_;
power = 0;
/*
* We prevent the zp pointer from walking behind _tenpowers_
* by stopping one short of the end and running the loop one
* more time.
*
* We could stop the loop with just zp >= _tenpowers_, but stopping
* short and running the loop one last time manually helps make
* code checkers such as insure happy.
*/
for (; zp > _tenpowers_; zp--, worth /= 2) {
if ((val.len + zp->len - 1) <= z.len) {
zmul(val, *zp, &temp);
if (zrel(z, temp) >= 0) {
zfree(val);
val = temp;
power += worth;
} else {
zfree(temp);
}
for (; zp > _tenpowers_; zp--) {
if (zrel(z, *zp) >= 0) {
zquo(z, *zp, &temp, 0);
if (power)
zfree(z);
z = temp;
power++;
}
power <<= 1;
}
/* run the loop manually one last time */
if (zp == _tenpowers_) {
if ((val.len + zp->len - 1) <= z.len) {
zmul(val, *zp, &temp);
if (zrel(z, temp) >= 0) {
zfree(val);
val = temp;
power += worth;
} else {
zfree(temp);
}
}
}
zfree(val);
if (zrel(z, *zp) >= 0)
power++;
if (power > 1)
zfree(z);
return power;
}
@@ -1223,7 +1217,7 @@ zdivcount(ZVALUE z1, ZVALUE z2)
/*
* Remove all occurences of the specified factor from a number.
* Remove all occurrences of the specified factor from a number.
* Also returns the number of factors removed as a function return value.
* Example: zfacrem(540, 3, &x) returns 3 and sets x to 20.
*/
@@ -1357,29 +1351,47 @@ zfacrem(ZVALUE z1, ZVALUE z2, ZVALUE *rem)
/*
* Keep dividing a number by the gcd of it with another number until the
* result is relatively prime to the second number.
* result is relatively prime to the second number. Returns the number
* of divisions made, and if this is positive, stores result at res.
*/
void
long
zgcdrem(ZVALUE z1, ZVALUE z2, ZVALUE *res)
{
ZVALUE tmp1, tmp2;
long count, onecount;
long sh;
if (ziszero(z1) || ziszero(z2)) {
math_error("Zero argument in call to zgcdrem!!!");
/*NOTREACHED*/
}
/*
* Begin by taking the gcd for the first time.
* If the number is already relatively prime, then we are done.
*/
z1.sign = 0;
z2.sign = 0;
zgcd(z1, z2, &tmp1);
if (zisunit(tmp1) || ziszero(tmp1)) {
res->len = z1.len;
res->v = alloc(z1.len);
res->sign = 0;
zcopyval(z1, *res);
zfree(tmp1);
return;
if (zisone(z2))
return 0;
if (zisonebit(z2)) {
sh = zlowbit(z1);
if (sh == 0)
return 0;
zshift(z1, -sh, res);
return 1 + (sh - 1)/zlowbit(z2);
}
if (zisonebit(z1)) {
if (zisodd(z2))
return 0;
*res = _one_;
return zlowbit(z1);
}
zgcd(z1, z2, &tmp1);
if (zisunit(tmp1) || ziszero(tmp1))
return 0;
zequo(z1, tmp1, &tmp2);
count = 1;
z1 = tmp2;
z2 = tmp1;
/*
@@ -1387,15 +1399,18 @@ zgcdrem(ZVALUE z1, ZVALUE z2, ZVALUE *res)
* the gcd becomes one.
*/
while (!zisunit(z2)) {
(void) zfacrem(z1, z2, &tmp1);
zfree(z1);
z1 = tmp1;
onecount = zfacrem(z1, z2, &tmp1);
if (onecount) {
count += onecount;
zfree(z1);
z1 = tmp1;
}
zgcd(z1, z2, &tmp1);
zfree(z2);
z2 = tmp1;
}
zfree(z2);
*res = z1;
return count;
}
@@ -1820,7 +1835,7 @@ zroot(ZVALUE z1, ZVALUE z2, ZVALUE *dest)
old.len = ztry.len;
zcopyval(ztry, old);
}
/* average current try and quotent for the new try */
/* average current try and quotient for the new try */
zmul(ztry, k1, &temp);
zfree(ztry);
zadd(quo, temp, &temp2);