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

📄 qfunc.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * qfunc - extended precision rational arithmetic non-primitive functions * * 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.9 $ * @(#) $Id: qfunc.c,v 29.9 2006/05/20 08:43:55 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/qfunc.c,v $ * * Under source code control:	1990/02/15 01:48:20 * File existed as early as:	before 1990 * * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/ */#include "qmath.h"#include "config.h"#include "prime.h"static NUMBER **B_table;static long B_num;static long B_allocnum;static NUMBER **E_table;static long E_num;#define QALLOCNUM 64/* * Set the default epsilon for approximate calculations. * This must be greater than zero. * * given: *	q		number to be set as the new epsilon */voidsetepsilon(NUMBER *q){	NUMBER *old;	if (qisneg(q) || qiszero(q)) {		math_error("Epsilon value must be greater than zero");		/*NOTREACHED*/	}	old = conf->epsilon;	conf->epsilonprec = qprecision(q);	conf->epsilon = qlink(q);	if (old)		qfree(old);}/* * Return the inverse of one number modulo another. * That is, find x such that: *	Ax = 1 (mod B) * Returns zero if the numbers are not relatively prime (temporary hack). */NUMBER *qminv(NUMBER *q1, NUMBER *q2){	NUMBER *r;	ZVALUE z1, z2, tmp;	int s, t;	long rnd;	if (qisfrac(q1) || qisfrac(q2)) {		math_error("Non-integers for minv");		/*NOTREACHED*/	}	if (qiszero(q2)) {		if (qisunit(q1))			return qlink(q1);		return qlink(&_qzero_);	}	if (qisunit(q2))		return qlink(&_qzero_);	rnd = conf->mod;	s = (rnd & 4) ? 0 : q2->num.sign;	if (rnd & 1)		s^= 1;	tmp = q2->num;	tmp.sign = 0;	if (zmodinv(q1->num, tmp, &z1))		return qlink(&_qzero_);	zsub(tmp, z1, &z2);	if (rnd & 16) {		t = zrel(z1, z2);		if (t < 0)			s = 0;		else if (t > 0)			s = 1;	}	r = qalloc();	if (s) {		zfree(z1);		z2.sign = TRUE;		r->num = z2;		return r;	}	zfree(z2);	r->num = z1;	return r;}/* * Return the residue modulo an integer (q3) of an integer (q1) * raised to a positive integer (q2) power. */NUMBER *qpowermod(NUMBER *q1, NUMBER *q2, NUMBER *q3){	NUMBER *r;	ZVALUE z1, z2, tmp;	int s, t;	long rnd;	if (qisfrac(q1) || qisfrac(q2) || qisfrac(q3)) {		math_error("Non-integers for pmod");		/*NOTREACHED*/	}	if (qisneg(q2)) {		math_error("Negative power for pmod");		/*NOTREACHED*/	}	if (qiszero(q3))		return qpowi(q1, q2);	if (qisunit(q3))		return qlink(&_qzero_);	rnd = conf->mod;	s = (rnd & 4) ? 0 : q3->num.sign;	if (rnd & 1)		s^= 1;	tmp = q3->num;	tmp.sign = 0;	zpowermod(q1->num, q2->num, tmp, &z1);	if (ziszero(z1)) {		zfree(z1);		return qlink(&_qzero_);	}	zsub(tmp, z1, &z2);	if (rnd & 16) {		t = zrel(z1, z2);		if (t < 0)			s = 0;		else if (t > 0)			s = 1;	}	r = qalloc();	if (s) {		zfree(z1);		z2.sign = TRUE;		r->num = z2;		return r;	}	zfree(z2);	r->num = z1;	return r;}/* * Return the power function of one number with another. * The power must be integral. *	q3 = qpowi(q1, q2); */NUMBER *qpowi(NUMBER *q1, NUMBER *q2){	register NUMBER *r;	BOOL invert, sign;	ZVALUE num, zden, z2;	if (qisfrac(q2)) {		math_error("Raising number to fractional power");		/*NOTREACHED*/	}	num = q1->num;	zden = q1->den;	z2 = q2->num;	sign = (num.sign && zisodd(z2));	invert = z2.sign;	num.sign = 0;	z2.sign = 0;	/*	* Check for trivial cases first.	*/	if (ziszero(num) && !ziszero(z2)) {	/* zero raised to a power */		if (invert) {			math_error("Zero raised to negative power");			/*NOTREACHED*/		}		return qlink(&_qzero_);	}	if (zisunit(num) && zisunit(zden)) {	/* 1 or -1 raised to a power */		r = (sign ? q1 : &_qone_);		r->links++;		return r;	}	if (ziszero(z2))	/* raising to zeroth power */		return qlink(&_qone_);	if (zisunit(z2)) {	/* raising to power 1 or -1 */		if (invert)			return qinv(q1);		return qlink(q1);	}	/*	 * Not a trivial case.	Do the real work.	 */	r = qalloc();	if (!zisunit(num))		zpowi(num, z2, &r->num);	if (!zisunit(zden))		zpowi(zden, z2, &r->den);	if (invert) {		z2 = r->num;		r->num = r->den;		r->den = z2;	}	r->num.sign = sign;	return r;}/* * Given the legs of a right triangle, compute its hypotenuse within * the specified error.	 This is sqrt(a^2 + b^2). */NUMBER *qhypot(NUMBER *q1, NUMBER *q2, NUMBER *epsilon){	NUMBER *tmp1, *tmp2, *tmp3;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for hypot");		/*NOTREACHED*/	}	if (qiszero(q1))		return qqabs(q2);	if (qiszero(q2))		return qqabs(q1);	tmp1 = qsquare(q1);	tmp2 = qsquare(q2);	tmp3 = qqadd(tmp1, tmp2);	qfree(tmp1);	qfree(tmp2);	tmp1 = qsqrt(tmp3, epsilon, 24L);	qfree(tmp3);	return tmp1;}/* * Given one leg of a right triangle with unit hypotenuse, calculate * the other leg within the specified error.  This is sqrt(1 - a^2). * If the wantneg flag is nonzero, then negative square root is returned. */NUMBER *qlegtoleg(NUMBER *q, NUMBER *epsilon, BOOL wantneg){	NUMBER *res, *qtmp1, *qtmp2;	ZVALUE num;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for legtoleg");		/*NOTREACHED*/	}	if (qisunit(q))		return qlink(&_qzero_);	if (qiszero(q)) {		if (wantneg)			return qlink(&_qnegone_);		return qlink(&_qone_);	}	num = q->num;	num.sign = 0;	if (zrel(num, q->den) >= 0) {		math_error("Leg too large in legtoleg");		/*NOTREACHED*/	}	qtmp1 = qsquare(q);	qtmp2 = qsub(&_qone_, qtmp1);	qfree(qtmp1);	res = qsqrt(qtmp2, epsilon, 24L);	qfree(qtmp2);	if (wantneg) {		qtmp1 = qneg(res);		qfree(res);		res = qtmp1;	}	return res;}/* * Compute the square root of a real number. * Type of rounding if any depends on rnd. * If rnd & 32 is nonzero, result is exact for square numbers; * If rnd & 64 is nonzero, the negative square root is returned; * If rnd < 32, result is rounded to a multiple of epsilon *	up, down, etc. depending on bits 0, 2, 4 of v. */NUMBER *qsqrt(NUMBER *q1, NUMBER *epsilon, long rnd){	NUMBER *r, etemp;	ZVALUE tmp1, tmp2, quo, mul, divisor;	long  s1, s2, up, RR, RS;	int sign;	if (qisneg(q1)) {		math_error("Square root of negative number");		/*NOTREACHED*/	}	if (qiszero(q1))		return qlink(&_qzero_);	sign = (rnd & 64) != 0;	if (qiszero(epsilon)) {		math_error("Zero epsilon for qsqrt");		/*NOTREACHED*/	}	etemp = *epsilon;	etemp.num.sign = 0;	RS = rnd & 25;	if (!(RS & 8))		RS ^= epsilon->num.sign;	if (rnd & 2)		RS ^= sign ^ epsilon->num.sign;	if (rnd & 4)		RS ^= epsilon->num.sign;	RR = zisunit(q1->den) && qisunit(epsilon);	if (rnd & 32 || RR) {		s1 = zsqrt(q1->num, &tmp1, RS);		if (RR) {			if (ziszero(tmp1)) {				zfree(tmp1);				return qlink(&_qzero_);			}			r = qalloc();			tmp1.sign = sign;			r->num = tmp1;			return r;		}		if (!s1) {			s2 = zsqrt(q1->den, &tmp2, 0);			if (!s2) {				r = qalloc();				tmp1.sign = sign;				r->num = tmp1;				r->den = tmp2;				return r;			}			zfree(tmp2);		}		zfree(tmp1);	}	up = 0;	zsquare(epsilon->den, &tmp1);	zmul(tmp1, q1->num, &tmp2);	zfree(tmp1);	zsquare(epsilon->num, &tmp1);	zmul(tmp1, q1->den, &divisor);	zfree(tmp1);	if (rnd & 16) {		zshift(tmp2, 2, &tmp1);		zfree(tmp2);		s1 = zquo(tmp1, divisor, &quo, 16);		zfree(tmp1);		s2 = zsqrt(quo, &tmp1, s1 ? s1 < 0 : 16);		zshift(tmp1, -1, &mul);		up = (*tmp1.v & 1) ? s1 + s2 : -1;		zfree(tmp1);	} else {		s1 = zquo(tmp2, divisor, &quo, 0);		zfree(tmp2);		s2 = zsqrt(quo, &mul, 0);		up = (s1 + s2) ? 0 : -1;	}	if (up == 0) {		if (rnd & 8)			up = (long)((RS ^ *mul.v) & 1);		else			up = RS ^ sign;	}	if (up > 0) {		zadd(mul, _one_, &tmp2);		zfree(mul);		mul = tmp2;	}	zfree(divisor);	zfree(quo);	if (ziszero(mul)) {		zfree(mul);		return qlink(&_qzero_);	}	r = qalloc();	zreduce(mul, etemp.den, &tmp1, &r->den);	zfree(mul);	tmp1.sign = sign;	zmul(tmp1, etemp.num, &r->num);	zfree(tmp1);	return r;}/* * Calculate the integral part of the square root of a number. * Example:  qisqrt(13) = 3. */NUMBER *qisqrt(NUMBER *q){	NUMBER *r;	ZVALUE tmp;	if (qisneg(q)) {		math_error("Square root of negative number");		/*NOTREACHED*/	}	if (qiszero(q))		return qlink(&_qzero_);	r = qalloc();	if (qisint(q)) {		(void) zsqrt(q->num, &r->num,0);		return r;	}	zquo(q->num, q->den, &tmp, 0);	(void) zsqrt(tmp, &r->num,0);	freeh(tmp.v);	return r;}/* * Return whether or not a number is an exact square. */BOOLqissquare(NUMBER *q){	BOOL flag;	flag = zissquare(q->num);	if (qisint(q) || !flag)		return flag;	return zissquare(q->den);}/* * Compute the greatest integer of the Kth root of a number. * Example:  qiroot(85, 3) = 4. */NUMBER *qiroot(NUMBER *q1, NUMBER *q2){	NUMBER *r;	ZVALUE tmp;	if (qisneg(q2) || qiszero(q2) || qisfrac(q2)) {		math_error("Taking number to bad root value");		/*NOTREACHED*/	}	if (qiszero(q1))		return qlink(&_qzero_);	if (qisone(q1) || qisone(q2))		return qlink(q1);	if (qistwo(q2))		return qisqrt(q1);	r = qalloc();	if (qisint(q1)) {		zroot(q1->num, q2->num, &r->num);		return r;	}	zquo(q1->num, q1->den, &tmp, 0);	zroot(tmp, q2->num, &r->num);	zfree(tmp);	return r;}/* * Return the greatest integer of the base 2 log of a number. * This is the number such that	 1 <= x / log2(x) < 2. * Examples:  qilog2(8) = 3, qilog2(1.3) = 1, qilog2(1/7) = -3. * * given: *	q		number to take log of */longqilog2(NUMBER *q){	long n;			/* power of two */	int c;			/* result of comparison */	ZVALUE tmp1, tmp2;	/* temporary values */	if (qiszero(q)) {		math_error("Zero argument for ilog2");		/*NOTREACHED*/	}	if (qisint(q))		return zhighbit(q->num);	tmp1 = q->num;	tmp1.sign = 0;	n = zhighbit(tmp1) - zhighbit(q->den);	if (n == 0)		c = zrel(tmp1, q->den);	else if (n > 0) {		zshift(q->den, n, &tmp2);		c = zrel(tmp1, tmp2);		zfree(tmp2);	} else {		zshift(tmp1, -n, &tmp2);		c = zrel(tmp2, q->den);		zfree(tmp2);	}	if (c < 0)		n--;	return n;}/* * Return the greatest integer of the base 10 log of a number. * This is the number such that	 1 <= x / log10(x) < 10. * Examples:  qilog10(100) = 2, qilog10(12.3) = 1, qilog10(.023) = -2. * * given: *	q		number to take log of */longqilog10(NUMBER *q){	long n;			/* log value */	ZVALUE tmp1, tmp2;	/* temporary values */	if (qiszero(q)) {		math_error("Zero argument for ilog10");		/*NOTREACHED*/	}	tmp1 = q->num;	tmp1.sign = 0;	if (qisint(q))		return zlog10(tmp1, NULL);	/*	 * The number is not an integer.	 * Compute the result if the number is greater than one.	 */	if (zrel(tmp1, q->den) > 0) {		zquo(tmp1, q->den, &tmp2, 0);		n = zlog10(tmp2, NULL);		zfree(tmp2);		return n;	}	/*	 * Here if the number is less than one.	 * If the number is the inverse of a power of ten, then the	 * obvious answer will be off by one.  Subtracting one if the	 * number is the inverse of an integer will fix it.	 */	if (zisunit(tmp1))		zsub(q->den, _one_, &tmp2);	else		zquo(q->den, tmp1, &tmp2, 0);	n = -zlog10(tmp2, NULL) - 1;	zfree(tmp2);	return n;}/* * Return the integer floor of the logarithm of a number relative to * a specified integral base. */NUMBER *qilog(NUMBER *q, ZVALUE base){	long n;	ZVALUE tmp1, tmp2;	if (qiszero(q))		return NULL;	if (qisunit(q))		return qlink(&_qzero_);	if (qisint(q))		return itoq(zlog(q->num, base));	tmp1 = q->num;	tmp1.sign = 0;	if (zrel(tmp1, q->den) > 0) {		zquo(tmp1, q->den, &tmp2, 0);		n = zlog(tmp2, base);		zfree(tmp2);		return itoq(n);	}	if (zisunit(tmp1))		zsub(q->den, _one_, &tmp2);	else		zquo(q->den, tmp1, &tmp2, 0);	n = -zlog(tmp2, base) - 1;

⌨️ 快捷键说明

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