⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qmath.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * qmath - extended precision rational arithmetic primitive routines * * Copyright (C) 1999-2004  David I. Bell and Ernest Bowen * * Primary author:  David I. Bell * * 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. * 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA. * * @(#) $Revision: 29.7 $ * @(#) $Id: qmath.c,v 29.7 2006/12/15 16:18:10 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/qmath.c,v $ * * Under source code control:	1990/02/15 01:48:21 * File existed as early as:	before 1990 * * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/ */#include <stdio.h>#include "qmath.h"#include "config.h"NUMBER _qzero_ =	{ { _zeroval_, 1, 0 }, { _oneval_, 1, 0 }, 1, NULL };NUMBER _qone_ =		{ { _oneval_, 1, 0  }, { _oneval_, 1, 0 }, 1, NULL };NUMBER _qtwo_ =		{ { _twoval_, 1, 0 }, { _oneval_, 1, 0 }, 1, NULL };NUMBER _qthree_ =	{ { _threeval_, 1, 0 }, { _oneval_, 1, 0 }, 1, NULL };NUMBER _qfour_ =	{ { _fourval_, 1, 0 }, { _oneval_, 1, 0 }, 1, NULL };NUMBER _qten_ =		{ { _tenval_, 1, 0 }, { _oneval_, 1, 0 }, 1, NULL };NUMBER _qnegone_ =	{ { _oneval_, 1, 1 }, { _oneval_, 1, 0 }, 1, NULL };NUMBER _qonehalf_ =	{ { _oneval_, 1, 0 }, { _twoval_, 1, 0 }, 1, NULL };NUMBER _qneghalf_ = 	{ { _oneval_, 1, 1 }, { _twoval_, 1, 0 }, 1, NULL };NUMBER _qonesqbase_ =	{ { _oneval_, 1, 0 }, { _sqbaseval_, 2, 0 }, 1, NULL };NUMBER * initnumbs[INITCONSTCOUNT] = {&_qzero_, &_qone_, &_qtwo_, &_qthree_,	&_qfour_, &_qten_, &_qnegone_, &_qonehalf_, &_qneghalf_};/* * Create another copy of a number. *	q2 = qcopy(q1); */NUMBER *qcopy(NUMBER *q){	register NUMBER *r;	r = qalloc();	r->num.sign = q->num.sign;	if (!zisunit(q->num)) {		r->num.len = q->num.len;		r->num.v = alloc(r->num.len);		zcopyval(q->num, r->num);	}	if (!zisunit(q->den)) {		r->den.len = q->den.len;		r->den.v = alloc(r->den.len);		zcopyval(q->den, r->den);	}	return r;}/* * Convert a number to a normal integer. *	i = qtoi(q); */longqtoi(NUMBER *q){	long i;	ZVALUE res;	if (qisint(q))		return ztoi(q->num);	zquo(q->num, q->den, &res, 0);	i = ztoi(res);	zfree(res);	return i;}/* * Convert a normal integer into a number. *	q = itoq(i); */NUMBER *itoq(long i){	register NUMBER *q;	if ((i >= -1) && (i <= 10)) {		switch ((int) i) {		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;		default: q = NULL;		}		if (q)			return qlink(q);	}	q = qalloc();	itoz(i, &q->num);	return q;}/* * Convert a number to a normal unsigned integer. *	u = qtou(q); */FULLqtou(NUMBER *q){	FULL i;	ZVALUE res;	if (qisint(q))		return ztou(q->num);	zquo(q->num, q->den, &res, 0);	i = ztou(res);	zfree(res);	return i;}/* * Convert a number to a normal signed integer. *	s = qtos(q); */SFULLqtos(NUMBER *q){	SFULL i;	ZVALUE res;	if (qisint(q))		return ztos(q->num);	zquo(q->num, q->den, &res, 0);	i = ztos(res);	zfree(res);	return i;}/* * Convert a normal unsigned integer into a number. *	q = utoq(i); */NUMBER *utoq(FULL i){	register NUMBER *q;	if (i <= 10) {		switch ((int) i) {		case 0: q = &_qzero_; break;		case 1: q = &_qone_; break;		case 2: q = &_qtwo_; break;		case 10: q = &_qten_; break;		default: q = NULL;		}		if (q)			return qlink(q);	}	q = qalloc();	utoz(i, &q->num);	return q;}/* * Convert a normal signed integer into a number. *	q = stoq(s); */NUMBER *stoq(SFULL i){	register NUMBER *q;	if (i <= 10) {		switch ((int) i) {		case 0: q = &_qzero_; break;		case 1: q = &_qone_; break;		case 2: q = &_qtwo_; break;		case 10: q = &_qten_; break;		default: q = NULL;		}		if (q)			return qlink(q);	}	q = qalloc();	stoz(i, &q->num);	return q;}/* * Create a number from the given FULL numerator and denominator. *	q = uutoq(inum, iden); */NUMBER *uutoq(FULL inum, FULL iden){	register NUMBER *q;	FULL d;	BOOL sign;	if (iden == 0) {		math_error("Division by zero");		/*NOTREACHED*/	}	if (inum == 0)		return qlink(&_qzero_);	sign = 0;	d = uugcd(inum, iden);	inum /= d;	iden /= d;	if (iden == 1)		return utoq(inum);	q = qalloc();	if (inum != 1)		utoz(inum, &q->num);	utoz(iden, &q->den);	q->num.sign = sign;	return q;}/* * Create a number from the given integral numerator and denominator. *	q = iitoq(inum, iden); */NUMBER *iitoq(long inum, long iden){	register NUMBER *q;	long d;	BOOL sign;	if (iden == 0) {		math_error("Division by zero");		/*NOTREACHED*/	}	if (inum == 0)		return qlink(&_qzero_);	sign = 0;	if (inum < 0) {		sign = 1;		inum = -inum;	}	if (iden < 0) {		sign = 1 - sign;		iden = -iden;	}	d = iigcd(inum, iden);	inum /= d;	iden /= d;	if (iden == 1)		return itoq(sign ? -inum : inum);	q = qalloc();	if (inum != 1)		itoz(inum, &q->num);	itoz(iden, &q->den);	q->num.sign = sign;	return q;}/* * Add two numbers to each other. *	q3 = qqadd(q1, q2); */NUMBER *qqadd(NUMBER *q1, NUMBER *q2){	NUMBER *r;	ZVALUE t1, t2, temp, d1, d2, vpd1, upd1;	if (qiszero(q1))		return qlink(q2);	if (qiszero(q2))		return qlink(q1);	r = qalloc();	/*	 * If either number is an integer, then the result is easy.	 */	if (qisint(q1) && qisint(q2)) {		zadd(q1->num, q2->num, &r->num);		return r;	}	if (qisint(q2)) {		zmul(q1->den, q2->num, &temp);		zadd(q1->num, temp, &r->num);		zfree(temp);		zcopy(q1->den, &r->den);		return r;	}	if (qisint(q1)) {		zmul(q2->den, q1->num, &temp);		zadd(q2->num, temp, &r->num);		zfree(temp);		zcopy(q2->den, &r->den);		return r;	}	/*	 * 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);	if (zisunit(d1)) {		zfree(d1);		zmul(q1->num, q2->den, &t1);		zmul(q1->den, q2->num, &t2);		zadd(t1, t2, &r->num);		zfree(t1);		zfree(t2);		zmul(q1->den, q2->den, &r->den);		return r;	}	/*	 * The calculation is now more complicated.	 * See Knuth Vol 2 for details.	 */	zquo(q2->den, d1, &vpd1, 0);	zquo(q1->den, d1, &upd1, 0);	zmul(q1->num, vpd1, &t1);	zmul(q2->num, upd1, &t2);	zadd(t1, t2, &temp);	zfree(t1);	zfree(t2);	zfree(vpd1);	zgcd(temp, d1, &d2);	zfree(d1);	if (zisunit(d2)) {		zfree(d2);		r->num = temp;		zmul(upd1, q2->den, &r->den);		zfree(upd1);		return r;	}	zquo(temp, d2, &r->num, 0);	zfree(temp);	zquo(q2->den, d2, &temp, 0);	zfree(d2);	zmul(temp, upd1, &r->den);	zfree(temp);	zfree(upd1);	return r;}/* * Subtract one number from another. *	q3 = qsub(q1, q2); */NUMBER *qsub(NUMBER *q1, NUMBER *q2){	NUMBER *r;	if (q1 == q2)		return qlink(&_qzero_);	if (qiszero(q2))		return qlink(q1);	if (qisint(q1) && qisint(q2)) {		r = qalloc();		zsub(q1->num, q2->num, &r->num);		return r;	}	q2 = qneg(q2);	if (qiszero(q1))		return q2;	r = qqadd(q1, q2);	qfree(q2);	return r;}/* * Increment a number by one. */NUMBER *qinc(NUMBER *q){	NUMBER *r;	r = qalloc();	if (qisint(q)) {		zadd(q->num, _one_, &r->num);		return r;	}	zadd(q->num, q->den, &r->num);	zcopy(q->den, &r->den);	return r;}/* * Decrement a number by one. */NUMBER *qdec(NUMBER *q){	NUMBER *r;	r = qalloc();	if (qisint(q)) {		zsub(q->num, _one_, &r->num);		return r;	}	zsub(q->num, q->den, &r->num);	zcopy(q->den, &r->den);	return r;}/* * Add a normal small integer value to an arbitrary number. */NUMBER *qaddi(NUMBER *q1, long n){	NUMBER addnum;		/* temporary number */	HALF addval[2];		/* value of small number */	BOOL neg;		/* TRUE if number is neg */#if LONG_BITS > BASEB	FULL nf;#endif	if (n == 0)		return qlink(q1);	if (n == 1)		return qinc(q1);	if (n == -1)		return qdec(q1);	if (qiszero(q1))		return itoq(n);	addnum.num.sign = 0;	addnum.num.v = addval;	addnum.den = _one_;	neg = (n < 0);	if (neg)		n = -n;	addval[0] = (HALF) n;#if LONG_BITS > BASEB	nf = (((FULL) n) >> BASEB);	if (nf) {		addval[1] = (HALF) nf;		addnum.num.len = 2;	}#else	addnum.num.len = 1;#endif	if (neg)		return qsub(q1, &addnum);	else		return qqadd(q1, &addnum);}/* * Multiply two numbers. *	q3 = qmul(q1, q2); */NUMBER *qmul(NUMBER *q1, NUMBER *q2){	NUMBER *r;			/* returned value */	ZVALUE n1, n2, d1, d2;		/* numerators and denominators */	ZVALUE tmp;	if (qiszero(q1) || qiszero(q2))		return qlink(&_qzero_);	if (qisone(q1))		return qlink(q2);	if (qisone(q2))		return qlink(q1);	if (qisint(q1) && qisint(q2)) { /* easy results if integers */		r = qalloc();		zmul(q1->num, q2->num, &r->num);		return r;	}	n1 = q1->num;	n2 = q2->num;	d1 = q1->den;	d2 = q2->den;	if (ziszero(d1) || ziszero(d2)) {		math_error("Division by zero");		/*NOTREACHED*/	}	if (ziszero(n1) || ziszero(n2))		return qlink(&_qzero_);	if (!zisunit(n1) && !zisunit(d2)) {	/* possibly reduce */		zgcd(n1, d2, &tmp);		if (!zisunit(tmp)) {			zequo(q1->num, tmp, &n1);			zequo(q2->den, tmp, &d2);		}		zfree(tmp);	}	if (!zisunit(n2) && !zisunit(d1)) {	/* again possibly reduce */		zgcd(n2, d1, &tmp);		if (!zisunit(tmp)) {			zequo(q2->num, tmp, &n2);			zequo(q1->den, tmp, &d1);		}		zfree(tmp);	}	r = qalloc();	zmul(n1, n2, &r->num);	zmul(d1, d2, &r->den);	if (q1->num.v != n1.v)		zfree(n1);	if (q1->den.v != d1.v)		zfree(d1);	if (q2->num.v != n2.v)		zfree(n2);	if (q2->den.v != d2.v)		zfree(d2);	return r;}/* * Multiply a number by a small integer. *	q2 = qmuli(q1, n); */NUMBER *qmuli(NUMBER *q, long n){	NUMBER *r;	long d;			/* gcd of multiplier and denominator */	int sign;	if ((n == 0) || qiszero(q))		return qlink(&_qzero_);	if (n == 1)		return qlink(q);	r = qalloc();	if (qisint(q)) {		zmuli(q->num, n, &r->num);		return r;	}	sign = 1;	if (n < 0) {		n = -n;		sign = -1;	}	d = zmodi(q->den, n);	d = iigcd(d, n);	zmuli(q->num, (n * sign) / d, &r->num);	(void) zdivi(q->den, d, &r->den);	return r;}/* * Divide two numbers (as fractions). *	q3 = qqdiv(q1, q2); */NUMBER *qqdiv(NUMBER *q1, NUMBER *q2){	NUMBER temp;	if (qiszero(q2)) {		math_error("Division by zero");		/*NOTREACHED*/	}	if ((q1 == q2) || !qcmp(q1, q2))		return qlink(&_qone_);	if (qisone(q1))		return qinv(q2);	temp.num = q2->den;	temp.den = q2->num;	temp.num.sign = temp.den.sign;	temp.den.sign = 0;	temp.links = 1;	return qmul(q1, &temp);}/* * Divide a number by a small integer. *	q2 = qdivi(q1, n); */NUMBER *qdivi(NUMBER *q, long n){	NUMBER *r;	long d;			/* gcd of divisor and numerator */	int sign;	if (n == 0) {		math_error("Division by zero");		/*NOTREACHED*/	}	if ((n == 1) || qiszero(q))		return qlink(q);	sign = 1;	if (n < 0) {		n = -n;		sign = -1;	}	r = qalloc();	d = zmodi(q->num, n);	d = iigcd(d, n);	(void) zdivi(q->num, d * sign, &r->num);	zmuli(q->den, n / d, &r->den);	return r;}/* * Return the integer quotient of a pair of numbers * If q1/q2 is an integer qquo(q1, q2) returns this integer * If q2 is zero, zero is returned * In other cases whether rounding is down, up, towards zero, etc. * is determined by rnd. */NUMBER *qquo(NUMBER *q1, NUMBER *q2, long rnd){	ZVALUE tmp, tmp1, tmp2;	NUMBER *q;	if (qiszero(q1) || qiszero(q2))		return qlink(&_qzero_);	if (qisint(q1) && qisint(q2)) {		zquo(q1->num, q2->num, &tmp, rnd);	} else {		zmul(q1->num, q2->den, &tmp1);		zmul(q2->num, q1->den, &tmp2);		zquo(tmp1, tmp2, &tmp, rnd);		zfree(tmp1);		zfree(tmp2);	}	if (ziszero(tmp)) {		zfree(tmp);		return qlink(&_qzero_);	}	q = qalloc();	q->num = tmp;	return q;}/* * Return the absolute value of a number. *	q2 = qqabs(q1); */NUMBER *qqabs(NUMBER *q){	register NUMBER *r;	if (q->num.sign == 0)		return qlink(q);	r = qalloc();	if (!zisunit(q->num))		zcopy(q->num, &r->num);	if (!zisunit(q->den))		zcopy(q->den, &r->den);	r->num.sign = 0;	return r;}/* * Negate a number. *	q2 = qneg(q1); */NUMBER *qneg(NUMBER *q){	register NUMBER *r;	if (qiszero(q))		return qlink(&_qzero_);	r = qalloc();	if (!zisunit(q->num))		zcopy(q->num, &r->num);	if (!zisunit(q->den))		zcopy(q->den, &r->den);	r->num.sign = !q->num.sign;	return r;}/* * Return the sign of a number (-1, 0 or 1) */NUMBER *qsign(NUMBER *q){	if (qiszero(q))		return qlink(&_qzero_);	if (qisneg(q))		return qlink(&_qnegone_);	return qlink(&_qone_);}/* * Invert a number. *	q2 = qinv(q1); */NUMBER *qinv(NUMBER *q){	register NUMBER *r;	if (qisunit(q)) {		r = (qisneg(q) ? &_qnegone_ : &_qone_);		return qlink(r);	}	if (qiszero(q)) {		math_error("Division by zero");		/*NOTREACHED*/	}	r = qalloc();	if (!zisunit(q->num))		zcopy(q->num, &r->den);	if (!zisunit(q->den))		zcopy(q->den, &r->num);	r->num.sign = q->num.sign;	r->den.sign = 0;	return r;}/* * Return just the numerator of a number. *	q2 = qnum(q1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -