* Copyright (c) 1994 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
* Extended precision rational arithmetic primitive routines
NUMBER _qzero_
= { { _zeroval_
, 1, 0 }, { _oneval_
, 1, 0 }, 1 };
NUMBER _qone_
= { { _oneval_
, 1, 0 }, { _oneval_
, 1, 0 }, 1 };
static NUMBER _qtwo_
= { { _twoval_
, 1, 0 }, { _oneval_
, 1, 0 }, 1 };
static NUMBER _qten_
= { { _tenval_
, 1, 0 }, { _oneval_
, 1, 0 }, 1 };
NUMBER _qnegone_
= { { _oneval_
, 1, 1 }, { _oneval_
, 1, 0 }, 1 };
NUMBER _qonehalf_
= { { _oneval_
, 1, 0 }, { _twoval_
, 1, 0 }, 1 };
* Create another copy of a number.
r
->num
.sign
= q
->num
.sign
;
r
->num
.v
= alloc(r
->num
.len
);
zcopyval(q
->num
, r
->num
);
r
->den
.v
= alloc(r
->den
.len
);
zcopyval(q
->den
, r
->den
);
* Convert a number to a normal integer.
zquo(q
->num
, q
->den
, &res
);
* Convert a normal integer into a number.
if ((i
>= -1) && (i
<= 10)) {
case 0: q
= &_qzero_
; break;
case 1: q
= &_qone_
; break;
case 2: q
= &_qtwo_
; break;
case 10: q
= &_qten_
; break;
case -1: q
= &_qnegone_
; break;
* Create a number from the given integral numerator and denominator.
math_error("Division by zero");
return itoq(sign
? -inum
: inum
);
* Add two numbers to each other.
register NUMBER
*q1
, *q2
;
ZVALUE t1
, t2
, temp
, d1
, d2
, vpd1
, upd1
;
* If either number is an integer, then the result is easy.
if (qisint(q1
) && qisint(q2
)) {
zadd(q1
->num
, q2
->num
, &r
->num
);
zmul(q1
->den
, q2
->num
, &temp
);
zadd(q1
->num
, temp
, &r
->num
);
zmul(q2
->den
, q1
->num
, &temp
);
zadd(q2
->num
, temp
, &r
->num
);
* Both arguments are true fractions, so we need more work.
* If the denominators are relatively prime, then the answer is the
* straightforward cross product result with no need for reduction.
zgcd(q1
->den
, q2
->den
, &d1
);
zmul(q1
->num
, q2
->den
, &t1
);
zmul(q1
->den
, q2
->num
, &t2
);
zmul(q1
->den
, q2
->den
, &r
->den
);
* The calculation is now more complicated.
* See Knuth Vol 2 for details.
zquo(q2
->den
, d1
, &vpd1
);
zquo(q1
->den
, d1
, &upd1
);
zmul(q1
->num
, vpd1
, &t1
);
zmul(q2
->num
, upd1
, &t2
);
zmul(upd1
, q2
->den
, &r
->den
);
zquo(q2
->den
, d2
, &temp
);
zmul(temp
, upd1
, &r
->den
);
* Subtract one number from another.
register NUMBER
*q1
, *q2
;
if (qisint(q1
) && qisint(q2
)) {
zsub(q1
->num
, q2
->num
, &r
->num
);
* Increment a number by one.
zadd(q
->num
, _one_
, &r
->num
);
zadd(q
->num
, q
->den
, &r
->num
);
* Decrement a number by one.
zsub(q
->num
, _one_
, &r
->num
);
zsub(q
->num
, q
->den
, &r
->num
);
* Add a normal small integer value to an arbitrary number.
NUMBER addnum
; /* temporary number */
HALF addval
[2]; /* value of small number */
BOOL neg
; /* TRUE if number is neg */
n
= (((FULL
) n
) >> BASEB
);
return qsub(q1
, &addnum
);
return qadd(q1
, &addnum
);
register NUMBER
*q1
, *q2
;
NUMBER
*r
; /* returned value */
ZVALUE n1
, n2
, d1
, d2
; /* numerators and denominators */
if (qiszero(q1
) || qiszero(q2
))
if (qisint(q1
) && qisint(q2
)) { /* easy results if integers */
zmul(q1
->num
, q2
->num
, &r
->num
);
if (ziszero(d1
) || ziszero(d2
))
math_error("Division by zero");
if (ziszero(n1
) || ziszero(n2
))
if (!zisunit(n1
) && !zisunit(d2
)) { /* possibly reduce */
if (!zisunit(n2
) && !zisunit(d1
)) { /* again possibly reduce */
* Multiply a number by a small integer.
long d
; /* gcd of multiplier and denominator */
if ((n
== 0) || qiszero(q
))
zmuli(q
->num
, n
, &r
->num
);
zmuli(q
->num
, (n
* sign
) / d
, &r
->num
);
(void) zdivi(q
->den
, d
, &r
->den
);
* Divide two numbers (as fractions).
register NUMBER
*q1
, *q2
;
math_error("Division by zero");
if ((q1
== q2
) || !qcmp(q1
, q2
))
temp
.num
.sign
= temp
.den
.sign
;
* Divide a number by a small integer.
long d
; /* gcd of divisor and numerator */
math_error("Division by zero");
if ((n
== 1) || qiszero(q
))
(void) zdivi(q
->num
, d
* sign
, &r
->num
);
zmuli(q
->den
, n
/ d
, &r
->den
);
* Return the quotient when one number is divided by another.
* This works for fractional values also, and in all cases:
* qquo(q1, q2) = int(q1 / q2).
register NUMBER
*q1
, *q2
;
else if (zisunit(q2
->den
))
zmul(q1
->num
, q2
->den
, &num
);
else if (zisunit(q2
->num
))
zmul(q1
->den
, q2
->num
, &den
);
if ((num
.v
!= q2
->den
.v
) && (num
.v
!= q1
->num
.v
))
if ((den
.v
!= q2
->num
.v
) && (den
.v
!= q1
->den
.v
))
res
.sign
= (q1
->num
.sign
!= q2
->num
.sign
);
q
= (res
.sign
? &_qnegone_
: &_qone_
);
* Return the absolute value of a number.
r
->num
.sign
= !q
->num
.sign
;
* Return the sign of a number (-1, 0 or 1)
return qlink(&_qnegone_
);
r
= (qisneg(q
) ? &_qnegone_
: &_qone_
);
math_error("Division by zero");
r
->num
.sign
= q
->num
.sign
;
* Return just the numerator of a number.
r
= (qisneg(q
) ? &_qnegone_
: &_qone_
);
* Return just the denominator of a number.
* Return the fractional part of a number.
if ((q
->num
.len
< q
->den
.len
) || ((q
->num
.len
== q
->den
.len
) &&
(q
->num
.v
[q
->num
.len
- 1] < q
->den
.v
[q
->num
.len
- 1])))
zmod(q
->num
, q
->den
, &z
);
zsub(q
->den
, z
, &r
->num
);
zmod(q
->num
, q
->den
, &r
->num
);
r
->num
.sign
= q
->num
.sign
;
* Return the integral part of a number.
if ((q
->num
.len
< q
->den
.len
) || ((q
->num
.len
== q
->den
.len
) &&
(q
->num
.v
[q
->num
.len
- 1] < q
->den
.v
[q
->num
.len
- 1])))
zquo(q
->num
, q
->den
, &r
->num
);
* Compute the square of a number.
* Shift an integer by a given number of bits. This multiplies the number
* by the appropriate power of two. Positive numbers shift left, negative
* ones shift right. Low bits are truncated when shifting right.
math_error("Shift of non-integer");
if (qiszero(q
) || (n
== 0))
if (n
<= -(q
->num
.len
* BASEB
))
zshift(q
->num
, n
, &r
->num
);
* Scale a number by a power of two, as in:
* This is similar to shifting, except that fractions work.
long numshift
, denshift
, tmp
;
if (qiszero(q
) || (pow
== 0))
if ((pow
> 1000000L) || (pow
< -1000000L))
math_error("Very large scale value");
numshift
= zisodd(q
->num
) ? 0 : zlowbit(q
->num
);
denshift
= zisodd(q
->den
) ? 0 : zlowbit(q
->den
);
zshift(q
->num
, numshift
, &r
->num
);
zshift(q
->den
, denshift
, &r
->den
);
* Return the minimum of two numbers.
* Return the maximum of two numbers.
* Perform the logical OR of two integers.
if (qisfrac(q1
) || qisfrac(q2
))
math_error("Non-integers for logical or");
if ((q1
== q2
) || qiszero(q2
))
zor(q1
->num
, q2
->num
, &r
->num
);
* Perform the logical AND of two integers.
if (qisfrac(q1
) || qisfrac(q2
))
math_error("Non-integers for logical and");
if (qiszero(q1
) || qiszero(q2
))
zand(q1
->num
, q2
->num
, &res
);
* Perform the logical XOR of two integers.
if (qisfrac(q1
) || qisfrac(q2
))
math_error("Non-integers for logical xor");
zxor(q1
->num
, q2
->num
, &res
);
* Return the number whose binary representation only has the specified
* bit set (counting from zero). This thus produces a given power of two.
* Test to see if the specified bit of a number is on (counted from zero).
* Returns TRUE if the bit is set, or FALSE if it is not.
if ((n
< 0) || (n
>= (q
->num
.len
* BASEB
)))
* Return the precision of a number (usually for examining an epsilon value).
* This is the largest power of two whose reciprocal is not smaller in absolute
* value than the specified number. For example, qbitprec(1/100) = 6.
* Numbers larger than one have a precision of zero.
r
= zhighbit(q
->den
) - zhighbit(q
->num
) - 1;
* Return an integer indicating the sign of a number (-1, 0, or 1).
* Determine whether or not one number exactly divides another one.
* Returns TRUE if the first number is an integer multiple of the second one.
if (qisint(q1
) && qisint(q2
)) {
return zdivides(q1
->num
, q2
->num
);
return zdivides(q1
->num
, q2
->num
) && zdivides(q2
->den
, q1
->den
);
* Compare two numbers and return an integer indicating their relative size.
register NUMBER
*q1
, *q2
;
sign
= q2
->num
.sign
- q1
->num
.sign
;
* Make a quick comparison by calculating the number of words resulting as
* if we multiplied through by the denominators, and then comparing the
wc1
= q1
->num
.len
+ q2
->den
.len
;
wc2
= q2
->num
.len
+ q1
->den
.len
;
* Quick check failed, must actually do the full comparison.
else if (zisone(q1
->num
))
zmul(q1
->num
, q2
->den
, &z1
);
else if (zisone(q2
->num
))
zmul(q2
->num
, q1
->den
, &z2
);
* Compare two numbers to see if they are equal.
* This differs from qrel in that the numbers are not ordered.
* Returns TRUE if they differ.
register NUMBER
*q1
, *q2
;
if ((q1
->num
.sign
!= q2
->num
.sign
) || (q1
->num
.len
!= q2
->num
.len
) ||
(q2
->den
.len
!= q2
->den
.len
) || (*q1
->num
.v
!= *q2
->num
.v
) ||
(*q1
->den
.v
!= *q2
->den
.v
))
if (zcmp(q1
->num
, q2
->num
))
return zcmp(q1
->den
, q2
->den
);
* Compare a number against a normal small integer.
* Returns 1, 0, or -1, according to whether the first number is greater,
* equal, or less than the second number.
sign
= ztest(q
->num
); /* do trivial sign checks */
if ((sign
< 0) && (n
>= 0))
if ((sign
> 0) && (n
<= 0))
if (n
== 1) { /* quick check against 1 or -1 */
return (sign
* zrel(num
, q
->den
));
num
.len
= 1 + (n
>= BASE
);
if (zisunit(q
->den
)) /* integer compare if no denominator */
return zrel(q
->num
, num
);
return qrel(q
, &q2
); /* full fractional compare */
* Compare a number against a small integer to see if they are equal.
* Returns TRUE if they differ.
if ((len
> 2) || qisfrac(q
) || (q
->num
.sign
!= (n
< 0)))
if (((HALF
)(n
)) != q
->num
.v
[0])
return (((n
!= 0) != (len
== 2)) || (n
!= q
->num
.v
[1]));
* Number node allocation routines
static union allocNode
*freeNum
;
register union allocNode
*temp
;
freeNum
= (union allocNode
*)
malloc(sizeof (NUMBER
) * NNALLOC
);
math_error("Not enough memory");
freeNum
[NNALLOC
-1].link
= NULL
;
for (temp
=freeNum
+NNALLOC
-2; temp
>= freeNum
; --temp
) {
a
= (union allocNode
*) q
;