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

📄 zmath.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * zmath - extended precision integral arithmetic primitives * * Copyright (C) 1999  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.3 $ * @(#) $Id: zmath.c,v 29.3 2006/12/15 16:20:04 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/zmath.c,v $ * * Under source code control:	1990/02/15 01:48:28 * File existed as early as:	before 1990 * * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/ */#include <stdio.h>#include "zmath.h"HALF _zeroval_[] = { 0 };HALF _oneval_[] = { 1 };HALF _twoval_[] = { 2 };HALF _threeval_[] = { 3 };HALF _fourval_[] = { 4 };HALF _fiveval_[] = { 5 };HALF _sixval_[] = { 6 };HALF _sevenval_[] = { 7 };HALF _eightval_[] = { 8 };HALF _nineval_[] = { 9 };HALF _tenval_[] = { 10 };HALF _elevenval_[] = { 11 };HALF _twelveval_[] = { 12 };HALF _thirteenval_[] = { 13 };HALF _fourteenval_[] = { 14 };HALF _fifteenval_[] = { 15 };HALF _sixteenval_[] = { 16 };HALF _seventeenval_[] = { 17 };HALF _eightteenval_[] = { 18 };HALF _nineteenval_[] = { 19 };HALF _twentyval_[] = { 20 };HALF _sqbaseval_[] = { 0, 1 };HALF _pow4baseval_[] = { 0, 0, 1 };HALF _pow8baseval_[] = { 0, 0, 0, 0, 1 };ZVALUE zconst[] = {    { _zeroval_, 1, 0}, { _oneval_, 1, 0}, { _twoval_, 1, 0},    { _threeval_, 1, 0}, { _fourval_, 1, 0}, { _fiveval_, 1, 0},    { _sixval_, 1, 0}, { _sevenval_, 1, 0}, { _eightval_, 1, 0},    { _nineval_, 1, 0}, { _tenval_, 1, 0}, { _elevenval_, 1, 0},    { _twelveval_, 1, 0}, { _thirteenval_, 1, 0}, { _fourteenval_, 1, 0},    { _fifteenval_, 1, 0}, { _sixteenval_, 1, 0}, { _seventeenval_, 1, 0},    { _eightteenval_, 1, 0}, { _nineteenval_, 1, 0}, { _twentyval_, 1, 0}};ZVALUE _zero_ = { _zeroval_, 1, 0};ZVALUE _one_ = { _oneval_, 1, 0 };ZVALUE _two_ = { _twoval_, 1, 0 };ZVALUE _ten_ = { _tenval_, 1, 0 };ZVALUE _sqbase_ = { _sqbaseval_, 2, 0 };ZVALUE _pow4base_ = { _pow4baseval_, 4, 0 };ZVALUE _pow8base_ = { _pow8baseval_, 4, 0 };ZVALUE _neg_one_ = { _oneval_, 1, 1 };/* * 2^64 as a ZVALUE */#if BASEB == 32ZVALUE _b32_ = { _sqbaseval_, 2, 0 };ZVALUE _b64_ = { _pow4baseval_, 3, 0 };#elif BASEB == 16ZVALUE _b32_ = { _pow4baseval_, 3, 0 };ZVALUE _b64_ = { _pow8baseval_, 5, 0 };#else	-=@=- BASEB not 16 or 32 -=@=-#endif/* * highhalf[i] - masks off the upper i bits of a HALF * rhighhalf[i] - masks off the upper BASEB-i bits of a HALF * lowhalf[i] - masks off the upper i bits of a HALF * rlowhalf[i] - masks off the upper BASEB-i bits of a HALF * bitmask[i] - (1 << i) for  0 <= i <= BASEB*2 */HALF highhalf[BASEB+1] = {#if BASEB == 32	0x00000000,	0x80000000, 0xC0000000, 0xE0000000, 0xF0000000,	0xF8000000, 0xFC000000, 0xFE000000, 0xFF000000,	0xFF800000, 0xFFC00000, 0xFFE00000, 0xFFF00000,	0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000,	0xFFFF8000, 0xFFFFC000, 0xFFFFE000, 0xFFFFF000,	0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00, 0xFFFFFF00,	0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0,	0xFFFFFFF8, 0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF#elif BASEB == 16	0x0000,	0x8000, 0xC000, 0xE000, 0xF000,	0xF800, 0xFC00, 0xFE00, 0xFF00,	0xFF80, 0xFFC0, 0xFFE0, 0xFFF0,	0xFFF8, 0xFFFC, 0xFFFE, 0xFFFF#else	-=@=- BASEB not 16 or 32 -=@=-#endif};HALF rhighhalf[BASEB+1] = {#if BASEB == 32	0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFC, 0xFFFFFFF8,	0xFFFFFFF0, 0xFFFFFFE0, 0xFFFFFFC0, 0xFFFFFF80,	0xFFFFFF00, 0xFFFFFE00, 0xFFFFFC00, 0xFFFFF800,	0xFFFFF000, 0xFFFFE000, 0xFFFFC000, 0xFFFF8000,	0xFFFF0000, 0xFFFE0000, 0xFFFC0000, 0xFFF80000,	0xFFF00000, 0xFFE00000, 0xFFC00000, 0xFF800000,	0xFF000000, 0xFE000000, 0xFC000000, 0xF8000000,	0xF0000000, 0xE0000000, 0xC0000000, 0x80000000,	0x00000000#elif BASEB == 16	0xFFFF, 0xFFFE, 0xFFFC, 0xFFF8,	0xFFF0, 0xFFE0, 0xFFC0, 0xFF80,	0xFF00, 0xFE00, 0xFC00, 0xF800,	0xF000, 0xE000, 0xC000, 0x8000,	0x0000#else	-=@=- BASEB not 16 or 32 -=@=-#endif};HALF lowhalf[BASEB+1] = {	0x0,	0x1,  0x3, 0x7, 0xF,	0x1F,  0x3F, 0x7F, 0xFF,	0x1FF,	0x3FF, 0x7FF, 0xFFF,	0x1FFF,	 0x3FFF, 0x7FFF, 0xFFFF#if BASEB == 32       ,0x1FFFF,  0x3FFFF, 0x7FFFF, 0xFFFFF,	0x1FFFFF,  0x3FFFFF, 0x7FFFFF, 0xFFFFFF,	0x1FFFFFF,  0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,	0x1FFFFFFF,  0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF#endif};HALF rlowhalf[BASEB+1] = {#if BASEB == 32	0xFFFFFFFF, 0x7FFFFFFF, 0x3FFFFFFF, 0x1FFFFFFF,	0xFFFFFFF, 0x7FFFFFF, 0x3FFFFFF, 0x1FFFFFF,	0xFFFFFF, 0x7FFFFF, 0x3FFFFF, 0x1FFFFF,	0xFFFFF, 0x7FFFF, 0x3FFFF, 0x1FFFF,#endif	0xFFFF, 0x7FFF, 0x3FFF, 0x1FFF,	0xFFF, 0x7FF, 0x3FF, 0x1FF,	0xFF, 0x7F, 0x3F, 0x1F,	0xF, 0x7, 0x3, 0x1,	0x0};HALF bitmask[(2*BASEB)+1] = {#if BASEB == 32	0x00000001, 0x00000002, 0x00000004, 0x00000008,	0x00000010, 0x00000020, 0x00000040, 0x00000080,	0x00000100, 0x00000200, 0x00000400, 0x00000800,	0x00001000, 0x00002000, 0x00004000, 0x00008000,	0x00010000, 0x00020000, 0x00040000, 0x00080000,	0x00100000, 0x00200000, 0x00400000, 0x00800000,	0x01000000, 0x02000000, 0x04000000, 0x08000000,	0x10000000, 0x20000000, 0x40000000, 0x80000000,	0x00000001, 0x00000002, 0x00000004, 0x00000008,	0x00000010, 0x00000020, 0x00000040, 0x00000080,	0x00000100, 0x00000200, 0x00000400, 0x00000800,	0x00001000, 0x00002000, 0x00004000, 0x00008000,	0x00010000, 0x00020000, 0x00040000, 0x00080000,	0x00100000, 0x00200000, 0x00400000, 0x00800000,	0x01000000, 0x02000000, 0x04000000, 0x08000000,	0x10000000, 0x20000000, 0x40000000, 0x80000000,	0x00000001#elif BASEB == 16	0x0001, 0x0002, 0x0004, 0x0008,	0x0010, 0x0020, 0x0040, 0x0080,	0x0100, 0x0200, 0x0400, 0x0800,	0x1000, 0x2000, 0x4000, 0x8000,	0x0001, 0x0002, 0x0004, 0x0008,	0x0010, 0x0020, 0x0040, 0x0080,	0x0100, 0x0200, 0x0400, 0x0800,	0x1000, 0x2000, 0x4000, 0x8000,	0x0001#else	-=@=- BASEB not 16 or 32 -=@=-#endif};		/* actual rotation thru 8 cycles */BOOL _math_abort_;		/* nonzero to abort calculations *//* * popcnt - popcnt[x] number of 1 bits in 0 <= x < 256 */char popcnt[256] = {    0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,    1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,    2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,    3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,    4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};#ifdef ALLOCTESTstatic long nalloc = 0;static long nfree = 0;#endifHALF *alloc(LEN len){	HALF *hp;	if (_math_abort_) {		math_error("Calculation aborted");		/*NOTREACHED*/	}	hp = (HALF *) malloc((len+1) * sizeof(HALF));	if (hp == 0) {		math_error("Not enough memory");		/*NOTREACHED*/	}#ifdef ALLOCTEST	++nalloc;#endif	return hp;}#ifdef ALLOCTESTvoidfreeh(HALF *h){	if ((h != _zeroval_) && (h != _oneval_)) {		free(h);		++nfree;	}}voidallocStat(void){	fprintf(stderr, "nalloc: %ld nfree: %ld kept: %ld\n",		nalloc, nfree, nalloc - nfree);}#endif/* * Convert a normal integer to a number. */voiditoz(long i, ZVALUE *res){	long diddle, len;	res->len = 1;	res->sign = 0;	diddle = 0;	if (i == 0) {		res->v = _zeroval_;		return;	}	if (i < 0) {		res->sign = 1;		i = -i;		if (i < 0) {	/* fix most negative number */			diddle = 1;			i--;		}	}	if (i == 1) {		res->v = _oneval_;		return;	}	len = 1 + (((FULL) i) >= BASE);	res->len = (LEN)len;	res->v = alloc((LEN)len);	res->v[0] = (HALF) (i + diddle);	if (len == 2)		res->v[1] = (HALF) (i / BASE);}/* * Convert a number to a normal integer, as far as possible. * If the number is out of range, the largest number is returned. */longztoi(ZVALUE z){	long i;	if (zgtmaxlong(z)) {		i = MAXLONG;		return (z.sign ? -i : i);	}	i = ztolong(z);	return (z.sign ? -i : i);}/* * Convert a normal unsigned integer to a number. */voidutoz(FULL i, ZVALUE *res){	long len;	res->len = 1;	res->sign = 0;	if (i == 0) {		res->v = _zeroval_;		return;	}	if (i == 1) {		res->v = _oneval_;		return;	}	len = 1 + (((FULL) i) >= BASE);	res->len = (LEN)len;	res->v = alloc((LEN)len);	res->v[0] = (HALF)i;	if (len == 2)		res->v[1] = (HALF) (i / BASE);}/* * Convert a normal signed integer to a number. */voidstoz(SFULL i, ZVALUE *res){	long diddle, len;	res->len = 1;	res->sign = 0;	diddle = 0;	if (i == 0) {		res->v = _zeroval_;		return;	}	if (i < 0) {		res->sign = 1;		i = -i;		if (i < 0) {	/* fix most negative number */			diddle = 1;			i--;		}	}	if (i == 1) {		res->v = _oneval_;		return;	}	len = 1 + (((FULL) i) >= BASE);	res->len = (LEN)len;	res->v = alloc((LEN)len);	res->v[0] = (HALF) (i + diddle);	if (len == 2)		res->v[1] = (HALF) (i / BASE);}/* * Convert a number to a unsigned normal integer, as far as possible. * If the number is out of range, the largest number is returned. * The absolute value of z is converted. */FULLztou(ZVALUE z){	if (z.len > 2) {		return MAXUFULL;	}	return ztofull(z);}/* * Convert a number to a signed normal integer, as far as possible. * * If the number is too large to fit into an integer, than the largest * positive or largest negative integer is returned depending on the sign. */SFULLztos(ZVALUE z){	FULL val;	/* absolute value of the return value */	/* negative value processing */	if (z.sign) {	    if (z.len > 2) {		return MINSFULL;	    }	    val = ztofull(z);	    if (val > TOPFULL) {		return MINSFULL;	    }	    return (SFULL)(-val);	}	/* positive value processing */	if (z.len > 2) {	    return (SFULL)MAXFULL;	}	val = ztofull(z);	if (val > MAXFULL) {	    return (SFULL)MAXFULL;	}	return (SFULL)val;}/* * Make a copy of an integer value */voidzcopy(ZVALUE z, ZVALUE *res){	res->sign = z.sign;	res->len = z.len;	if (zisabsleone(z)) {	/* zero or plus or minus one are easy */		res->v = (z.v[0] ? _oneval_ : _zeroval_);		return;	}	res->v = alloc(z.len);	zcopyval(z, *res);}/* * Add together two integers. */voidzadd(ZVALUE z1, ZVALUE z2, ZVALUE *res){	ZVALUE dest;	HALF *p1, *p2, *pd;	long len;	FULL carry;	SIUNION sival;	if (z1.sign && !z2.sign) {		z1.sign = 0;		zsub(z2, z1, res);		return;	}	if (z2.sign && !z1.sign) {		z2.sign = 0;		zsub(z1, z2, res);		return;	}	if (z2.len > z1.len) {		pd = z1.v; z1.v = z2.v; z2.v = pd;		len = z1.len; z1.len = z2.len; z2.len = (LEN)len;	}	dest.len = z1.len + 1;	dest.v = alloc(dest.len);	dest.sign = z1.sign;	carry = 0;	pd = dest.v;	p1 = z1.v;	p2 = z2.v;	len = z2.len;	while (len--) {		sival.ivalue = ((FULL) *p1++) + ((FULL) *p2++) + carry;		/* ignore Saber-C warning #112 - get ushort from uint */		/*	  ok to ignore on name zadd`sival */		*pd++ = sival.silow;		carry = sival.sihigh;	}	len = z1.len - z2.len;	while (len--) {		sival.ivalue = ((FULL) *p1++) + carry;		*pd++ = sival.silow;		carry = sival.sihigh;	}	*pd = (HALF)carry;	zquicktrim(dest);	*res = dest;}/* * Subtract two integers. */voidzsub(ZVALUE z1, ZVALUE z2, ZVALUE *res){	register HALF *h1, *h2, *hd;	long len1, len2;	FULL carry;	SIUNION sival;	ZVALUE dest;	if (z1.sign != z2.sign) {		z2.sign = z1.sign;		zadd(z1, z2, res);		return;	}	len1 = z1.len;	len2 = z2.len;	if (len1 == len2) {		h1 = z1.v + len1;		h2 = z2.v + len2;		while ((len1 > 0) && ((FULL)*--h1 == (FULL)*--h2)) {			len1--;		}		if (len1 == 0) {			*res = _zero_;			return;		}		len2 = len1;		carry = ((FULL)*h1 < (FULL)*h2);	} else {		carry = (len1 < len2);	}	dest.sign = z1.sign;	h1 = z1.v;	h2 = z2.v;	if (carry) {		carry = len1;		len1 = len2;		len2 = (long)carry;		h1 = z2.v;		h2 = z1.v;		dest.sign = !dest.sign;	}	hd = alloc((LEN)len1);	dest.v = hd;	dest.len = (LEN)len1;	len1 -= len2;	carry = 0;	while (--len2 >= 0) {		/* ignore Saber-C warning #112 - get ushort from uint */		/*	  ok to ignore on name zsub`sival */		sival.ivalue = (BASE1 - ((FULL) *h1++)) + *h2++ + carry;		*hd++ = (HALF)(BASE1 - sival.silow);		carry = sival.sihigh;	}	while (--len1 >= 0) {		sival.ivalue = (BASE1 - ((FULL) *h1++)) + carry;		*hd++ = (HALF)(BASE1 - sival.silow);		carry = sival.sihigh;	}	if (hd[-1] == 0)		ztrim(&dest);	*res = dest;}/* * Multiply an integer by a small number. */voidzmuli(ZVALUE z, long n, ZVALUE *res){	register HALF *h1, *sd;	FULL low;	FULL high;	FULL carry;	long len;	SIUNION sival;	ZVALUE dest;	if ((n == 0) || ziszero(z)) {		*res = _zero_;		return;	}	if (n < 0) {		n = -n;		z.sign = !z.sign;	}	if (n == 1) {		zcopy(z, res);		return;	}#if LONG_BITS > BASEB	low = ((FULL) n) & BASE1;	high = ((FULL) n) >> BASEB;#else	low = (FULL)n;	high = 0;#endif	dest.len = z.len + 2;	dest.v = alloc(dest.len);	dest.sign = z.sign;	/*	 * Multiply by the low digit.	 */	h1 = z.v;	sd = dest.v;	len = z.len;	carry = 0;	while (len--) {		/* ignore Saber-C warning #112 - get ushort from uint */		/*	  ok to ignore on name zmuli`sival */		sival.ivalue = ((FULL) *h1++) * low + carry;		*sd++ = sival.silow;		carry = sival.sihigh;	}	*sd = (HALF)carry;	/*	 * If there was only one digit, then we are all done except	 * for trimming the number if there was no last carry.	 */	if (high == 0) {		dest.len--;		if (carry == 0)			dest.len--;		*res = dest;		return;	}	/*	 * Need to multiply by the high digit and add it into the	 * previous value.  Clear the final word of rubbish first.	 */	*(++sd) = 0;	h1 = z.v;	sd = dest.v + 1;	len = z.len;	carry = 0;	while (len--) {		sival.ivalue = ((FULL) *h1++) * high + ((FULL) *sd) + carry;		*sd++ = sival.silow;		carry = sival.sihigh;	}	*sd = (HALF)carry;	zquicktrim(dest);	*res = dest;}/* * Divide two numbers by their greatest common divisor. * This is useful for reducing the numerator and denominator of * a fraction to its lowest terms.

⌨️ 快捷键说明

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