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

📄 qtrans.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * qtrans - transcendental functions for real numbers * * 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: qtrans.c,v 29.7 2006/05/07 13:04:18 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/qtrans.c,v $ * * Under source code control:	1990/02/15 01:48:22 * File existed as early as:	before 1990 * * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/ *//* * Transcendental functions for real numbers. * These are sin, cos, exp, ln, power, cosh, sinh. */#include "qmath.h"HALF _qlgenum_[] = { 36744 };HALF _qlgeden_[] = { 25469 };NUMBER _qlge_ = { { _qlgenum_, 1, 0 }, { _qlgeden_, 1, 0 }, 1, NULL };/* * cache the natural logarithm of 10 */static NUMBER *ln_10 = NULL;static NUMBER *ln_10_epsilon = NULL;static NUMBER *pivalue[2];static NUMBER *qexprel(NUMBER *q, long bitnum);/* * Evaluate and store in specified locations the sin and cos of a given * number to accuracy corresponding to a specified number of binary digits. */voidqsincos(NUMBER *q, long bitnum, NUMBER **vs, NUMBER **vc){	long n, m, k, h, s, t, d;	NUMBER *qtmp1, *qtmp2;	ZVALUE X, cossum, sinsum, mul, ztmp1, ztmp2, ztmp3;	qtmp1 = qqabs(q);	h = qilog2(qtmp1);	qfree(qtmp1);	k = bitnum + h + 1;	if (k < 0) {		*vs = qlink(&_qzero_);		*vc = qlink(&_qone_);		return;	}	s = k;	if (k) {		do {			t = s;			s = (s + k/s)/2;		}		while (t > s);	}		/* s is int(sqrt(k)) */	s++;	if (s < -h)		s = -h;	n = h + s;	/* n is number of squarings that will be required */	m = bitnum + n;	while (s > 0) {		/* increasing m by ilog2(s) */		s >>= 1;		m++;	}			/* m is working number of bits */	qtmp1 = qscale(q, m - n);	zquo(qtmp1->num, qtmp1->den, &X, 24);	qfree(qtmp1);	if (ziszero(X)) {		zfree(X);		*vs = qlink(&_qzero_);		*vc = qlink(&_qone_);		return;	}	zbitvalue(m, &cossum);	zcopy(X, &sinsum);	zcopy(X, &mul);	d = 1;	for (;;) {		X.sign = !X.sign;		zmul(X, mul, &ztmp1);		zfree(X);		zshift(ztmp1, -m, &ztmp2);		zfree(ztmp1);		zdivi(ztmp2, ++d, &X);		zfree(ztmp2);		if (ziszero(X))			break;		zadd(cossum, X, &ztmp1);		zfree(cossum);		cossum = ztmp1;		zmul(X, mul, &ztmp1);		zfree(X);		zshift(ztmp1, -m, &ztmp2);		zfree(ztmp1);		zdivi(ztmp2, ++d, &X);		zfree(ztmp2);		if (ziszero(X))			break;		zadd(sinsum, X, &ztmp1);		zfree(sinsum);		sinsum = ztmp1;	}	zfree(X);	zfree(mul);	while (n-- > 0) {		zsquare(cossum, &ztmp1);		zsquare(sinsum, &ztmp2);		zsub(ztmp1, ztmp2, &ztmp3);		zfree(ztmp1);		zfree(ztmp2);		zmul(cossum, sinsum, &ztmp1);		zfree(cossum);		zfree(sinsum);		zshift(ztmp3, -m, &cossum);		zfree(ztmp3);		zshift(ztmp1, 1 - m, &sinsum);		zfree(ztmp1);	}	h = zlowbit(cossum);	qtmp1 = qalloc();	if (m > h) {		zshift(cossum, -h, &qtmp1->num);		zbitvalue(m - h, &qtmp1->den);	} else {		zshift(cossum, - m, &qtmp1->num);	}	zfree(cossum);	*vc = qtmp1;	h = zlowbit(sinsum);	qtmp2 = qalloc();	if (m > h) {		zshift(sinsum, -h, &qtmp2->num);		zbitvalue(m - h, &qtmp2->den);	} else {		zshift(sinsum, -m, &qtmp2->num);	}	zfree(sinsum);	*vs = qtmp2;	return;}/* * Calculate the cosine of a number to a near multiple of epsilon. * This calls qsincos() and discards the value of sin. */NUMBER *qcos(NUMBER *q, NUMBER *epsilon){	NUMBER *sin, *cos, *res;	long n;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for cosine");		/*NOTREACHED*/	}	if (qiszero(q))		return qlink(&_qone_);	n = -qilog2(epsilon);	if (n < 0)		return qlink(&_qzero_);	qsincos(q, n + 2, &sin, &cos);	qfree(sin);	res = qmappr(cos, epsilon, 24);	qfree(cos);	return res;}/* * This calls qsincos() and discards the value of cos. */NUMBER *qsin(NUMBER *q, NUMBER *epsilon){	NUMBER *sin, *cos, *res;	long n;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for sine");		/*NOTREACHED*/	}	n = -qilog2(epsilon);	if (qiszero(q) || n < 0)		return qlink(&_qzero_);	qsincos(q, n + 2, &sin, &cos);	qfree(cos);	res = qmappr(sin, epsilon, 24);	qfree(sin);	return res;}/* * Calculate the tangent function. */NUMBER *qtan(NUMBER *q, NUMBER *epsilon){	NUMBER *sin, *cos, *tan, *res;	long n, k, m;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for tangent");		/*NOTREACHED*/	}	if (qiszero(q))		return qlink(q);	n = qilog2(epsilon);	k = (n > 0) ? 4 + n/2 : 4;	for (;;) {		qsincos(q, 2 * k - n, &sin, &cos);		if (qiszero(cos)) {			qfree(sin);			qfree(cos);			k = 2 * k - n + 4;			continue;		}		m = -qilog2(cos);		if (m < k)			 break;		qfree(sin);		qfree(cos);		k = m + 1;	}	tan = qqdiv(sin, cos);	qfree(sin);	qfree(cos);	res = qmappr(tan, epsilon, 24);	qfree(tan);	return res;}/* * Calculate the cotangent function. */NUMBER *qcot(NUMBER *q, NUMBER *epsilon){	NUMBER *sin, *cos, *cot, *res;	long n, k, m;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for cotangent");		/*NOTREACHED*/	}	if (qiszero(q)) {		math_error("Zero argument for cotangent");		/*NOTREACHED*/	}	k = -qilog2(q);	n = qilog2(epsilon);	if (k < 0)		k = (n > 0) ? n/2 : 0;	k += 4;	for (;;) {		qsincos(q, 2 * k - n, &sin, &cos);		if (qiszero(sin)) {			qfree(sin);			qfree(cos);			k = 2 * k - n + 4;			continue;		}		m = -qilog2(sin);		if (m < k)			 break;		qfree(sin);		qfree(cos);		k = m + 1;	}	cot = qqdiv(cos, sin);	qfree(sin);	qfree(cos);	res = qmappr(cot, epsilon, 24);	qfree(cot);	return res;}/* * Calculate the secant function. */NUMBER *qsec(NUMBER *q, NUMBER *epsilon){	NUMBER *sin, *cos, *sec, *res;	long n, k, m;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for secant");		/*NOTREACHED*/	}	if (qiszero(q))		return qlink(&_qone_);	n = qilog2(epsilon);	k = (n > 0) ? 4 + n/2 : 4;	for (;;) {		qsincos(q, 2 * k - n, &sin, &cos);		qfree(sin);		if (qiszero(cos)) {			qfree(cos);			k = 2 * k - n + 4;			continue;		}		m = -qilog2(cos);		if (m < k)			 break;		qfree(cos);		k = m + 1;	}	sec = qinv(cos);	qfree(cos);	res = qmappr(sec, epsilon, 24);	qfree(sec);	return res;}/* * Calculate the cosecant function. */NUMBER *qcsc(NUMBER *q, NUMBER *epsilon){	NUMBER *sin, *cos, *csc, *res;	long n, k, m;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for cosecant");		/*NOTREACHED*/	}	if (qiszero(q)) {		math_error("Zero argument for cosecant");		/*NOTREACHED*/	}	k = -qilog2(q);	n = qilog2(epsilon);	if (k < 0)		k = (n > 0) ? n/2 : 0;	k += 4;	for (;;) {		qsincos(q, 2 * k - n, &sin, &cos);		qfree(cos);		if (qiszero(sin)) {			qfree(sin);			k = 2 * k - n + 4;			continue;		}		m = -qilog2(sin);		if (m < k)			 break;		qfree(sin);		k = m + 1;	}	csc = qinv(sin);	qfree(sin);	res = qmappr(csc, epsilon, 24);	qfree(csc);	return res;}/* * Calculate the arcsine function. * The result is in the range -pi/2 to pi/2. */NUMBER *qasin(NUMBER *q, NUMBER *epsilon){	NUMBER *qtmp1, *qtmp2, *epsilon1;	ZVALUE ztmp;	BOOL neg;	FLAG r;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for asin");		/*NOTREACHED*/	}	if (qiszero(q))		return qlink(&_qzero_);	ztmp = q->num;	neg = ztmp.sign;	ztmp.sign = 0;	r = zrel(ztmp, q->den);	if (r > 0)		return NULL;	if (r == 0) {		epsilon1 = qscale(epsilon, 1L);		qtmp2 = qpi(epsilon1);		qtmp1 = qscale(qtmp2, -1L);	} else {		epsilon1 = qscale(epsilon, -2L);		qtmp1 = qalloc();		zsquare(q->num, &qtmp1->num);		zsquare(q->den, &ztmp);		zsub(ztmp, qtmp1->num, &qtmp1->den);		zfree(ztmp);		qtmp2 = qsqrt(qtmp1, epsilon1, 24);		qfree(qtmp1);		qtmp1 = qatan(qtmp2, epsilon);	}	qfree(qtmp2);	qfree(epsilon1);	if (neg) {		qtmp2 = qneg(qtmp1);		qfree(qtmp1);		return(qtmp2);	}	return qtmp1;}/* * Calculate the acos function. * The result is in the range 0 to pi. */NUMBER *qacos(NUMBER *q, NUMBER *epsilon){	NUMBER *q1, *q2, *epsilon1;	ZVALUE z;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for acos");		/*NOTREACHED*/	}	if (qisone(q))		return qlink(&_qzero_);	if (qisnegone(q))		return qpi(epsilon);	z = q->num;	z.sign = 0;	if (zrel(z, q->den) > 0)		return NULL;	epsilon1 = qscale(epsilon, -3L);		/* ??? */	q1 = qalloc();	zsub(q->den, q->num, &q1->num);	zadd(q->den, q->num, &q1->den);	q2 = qsqrt(q1, epsilon1, 24L);	qfree(q1);	qfree(epsilon1);	epsilon1 = qscale(epsilon, -1L);	q1 = qatan(q2, epsilon1);	qfree(epsilon1);	qfree(q2);	q2 = qscale(q1, 1L);	qfree(q1)	return q2;}/* * Calculate the arctangent function to the nearest or next to nearest * multiple of epsilon.	 Algorithm uses *	atan(x) = 2 * atan(x/(1 + sqrt(1+x^2))) * to reduce x to a small value and then *	atan(x) = x - x^3/3 + ... */NUMBER *qatan(NUMBER *q, NUMBER *epsilon){	long m, k, i;	FULL d;	ZVALUE X, D, DD, sum, mul, term, ztmp1, ztmp2;	NUMBER *qtmp, *res;	BOOL sign;	if (qiszero(epsilon)) {		math_error("Zero epsilon value for arctangent");		/*NOTREACHED*/	}	if (qiszero(q))		return qlink(&_qzero_);	m = 12 - qilog2(epsilon);		/* 4 bits for 4 doublings; 8 for rounding */	if (m < 8)		m = 8;		/* m is number of working binary digits */	qtmp = qscale(q, m);	zquo(qtmp->num, qtmp->den, &X, 24);	qfree(qtmp);	zbitvalue(m, &D);	/* q has become X/D */	zsquare(D, &DD);	i = 4;			/* maybe this should be larger */	while (i-- > 0 && !ziszero(X)) {		zsquare(X, &ztmp1);		zadd(ztmp1, DD, &ztmp2);		zfree(ztmp1);		zsqrt(ztmp2, &ztmp1, 24L);		zfree(ztmp2);		zadd(ztmp1, D, &ztmp2);		zfree(ztmp1);		zshift(X, m, &ztmp1);		zfree(X);		zquo(ztmp1, ztmp2, &X, 24L);		zfree(ztmp1);		zfree(ztmp2);	}	zfree(DD);	zfree(D);	if (ziszero(X)) {		zfree(X);		return qlink(&_qzero_);	}	zcopy(X, &sum);	zsquare(X, &ztmp1);	zshift(ztmp1, -m, &mul);	zfree(ztmp1);	d = 3;	sign = !X.sign;	for (;;) {		if (d > BASE) {			math_error("Too many terms required for atan");			/*NOTREACHED*/		}		zmul(X, mul, &ztmp1);		zfree(X);		zshift(ztmp1, -m, &X);	/* X now (original X)^d */		zfree(ztmp1);		zdivi(X, d, &term);		if (ziszero(term)) {			zfree(term);			break;		}		term.sign = sign;		zadd(sum, term, &ztmp1);		zfree(sum);		zfree(term);		sum = ztmp1;		sign = !sign;		d += 2;	}	zfree(mul);

⌨️ 快捷键说明

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