MPAライブラリ 乗除算ルーチン



[ 簡単な説明 ]

関数プロトタイプ 機能説明
MPA m_mul(MPA a, MPA b) 乗算 a × b
MPA m_mul_s(MPA a, int x) a × x(整数)
void m_mul1(MPA *a, MPA b) a × b → a
void m_mul1_s(MPA *a, int x) a × x(整数)→ a
MPA m_div(MPA a, MPA b) 除算 a ÷ b
MPA m_div_s(MPA a, int x) a ÷ x(整数)
void m_div1(MPA *a, MPA b) a ÷ b → a
void m_div1_s(MPA *a, int x) a ÷ x(整数)→ a
MPA m_idiv(MPA a, MPA b, MPA *r) 戻り値:除算値(整数), r:剰余
int m_mul_ss(int m, MPA a, UINT x, MPA *b) 整数乗算ルーチン( m 桁目以降対象,スレーブルーチン)
int m_div_ss(int m, MPA a, UINT x, MPA *b) 整数除算ルーチン( m 桁目以降対象,スレーブルーチン)
MPA m_inv(MPA b) 逆数
MPA m_pwr_s(MPA a, long x) 整数ベキ乗
MPA m_sqr(MPA a) 平方
MPA m_sqrt(MPA a) 平方根

プログラム・ソース("m_mul.c")           top (トップに戻る)
/*		m_mul.c		MPA * MPA --> MPA	*/
#include "mpa.h"

MPA m_mul(MPA a, MPA b)
{
	MPA c;
	int i, j;
	UINT x[NMPA2];
	UINT *p, *q, *r, *xp;
	ULONG u;
	long exp;

	if(a.zero || b.zero)	return _M0;
	for(i = 0; i < NMPA2; i++)	x[i] = 0;
	for(i = NMPA, xp = x + NMPA2 - 1, p = b.num + i; i >= 0; i--, xp--, p--)
	{
		if(*p)
		{
			u = 0;
			for(j = NMPA, q = a.num + j, r = xp; j >= 0; j--)
			{
				u += (ULONG)(*q--) * (ULONG)*p + *r;
				*r-- = (UINT)u & RADIX1;
				u >>= RADIXBITS;
			}
			while(u)
			{
				u += *r;
				*r-- = (UINT)u & RADIX1;
				u >>= RADIXBITS;
			}
		}
	}
	c.zero = 0;
	c.sign = (a.sign == b.sign)? 1: 0;
	c.exp = a.exp + b.exp + 1;
	for(i = 0, xp = x; i < NMPA2; i++, xp++)
	{
		if(*xp)	break;
		c.exp--;
	}
	if(c.exp > MAXEXP)
	{
		fprintf(stderr, "Error : Overflow  in m_mul()\n");
		return _MMAX;
	}
	if(c.exp < MINEXP)
	{
		fprintf(stderr, "Error : Underflow  in m_mul()\n");
		return _M0;
	}
	for(j = 0, p = c.num; (j <= NMPA) && (i < NMPA2); i++, j++)
		*p++ = *xp++;
	if(j <= NMPA)	for(; j <= NMPA; j++)	*p++ = 0;
	else if(*xp >= RADIX_2)
		for(i = NMPA, p = c.num + i; ++*p & RADIX; i--)	*p-- &= RADIX1;
	return c;
}

/*		m_div		MPA / MPA --> MPA	*/

MPA m_div(MPA a, MPA b)
{
	MPA c, t;
	int b0, bcom, cmp, d, i;
	UINT *p;
	ULONG a0;

	if(a.zero)	return _M0;
	if(b.zero)
	{
		fprintf(stderr, "Error : Divide by 0  in m_div()\n");
		return _MMAX;
	}
	c.zero = 0;
	c.sign = (a.sign == b.sign)? 1: 0;
	a.sign = b.sign = 1;
	if((b.num[0] << 1) & RADIX)	bcom = 1;
	else
	{
		bcom = RADIX / (b.num[0] + 1);
		m_mul1_s(&b, bcom);
	}
	c.exp = a.exp - b.exp;
	a.exp = b.exp = 0;
	if(m_cmp_a(a, b) < 0)
	{
		c.exp--;
		a.exp++;
	}
	i = 0;
	p = c.num;
	b0 = b.num[0] + 1;
	while(1)
	{
		a0 = a.num[0];
		if(a0 > b0)	d = a0 / b0;
		else
		{
			a0 = a0 * RADIX + a.num[1];
			d = a0 / b0;
			if(d < 1)	d = 1;
		}
		while(1)
		{
			t = m_sub(a, m_mul_s(b, d));
			cmp = m_cmp_a(t, b);
			if(cmp < 0)	break;
			d++;
			if(cmp == 0)	break;
		}
		if(i > NMPA)
		{
			if(d >= RADIX_2)
				for(i = NMPA, p = c.num + i; ++*p & RADIX; i--)
					*p-- &= RADIX1;
			break;
		}
		*p++ = d;
		i++;
		if(cmp == 0)
		{
			for(; i <= NMPA; i++)	*p++ = 0;
			break;
		}
		a = t;
		a.exp++;
		if(m_cmp_a(a, b) < 0)
		{
			*p++ = 0;
			i++;
			if(i > NMPA)	break;
			a.exp++;
		}
	}
	if(bcom != 1)	return m_mul_s(c, bcom);
	return c;
}

/*		m_mul_s		MPA * int --> MPA	*/

MPA m_mul_s(MPA a, int x)
{
	MPA b;
	int i;
	UINT *p, *q;
	ULONG t, xl;

	if(a.zero || x == 0)	return _M0;
	b.zero = 0;
	b.sign = (x > 0)? a.sign: 1 - a.sign;
	b.exp = a.exp;
	xl= (x > 0)? (ULONG)x: (ULONG)(-x);
	t = 0;
	for(i = NMPA, p = a.num + i, q = b.num + i; i >= 0; i--)
	{
		t += (ULONG)*p-- * xl;
		*q-- = (UINT)t & RADIX1;
		t >>= RADIXBITS;
	}
	while(t)
	{
		if(a.exp == RADIX1)
		{
			fprintf(stderr, "Error : Overflow  in m_mul_s()\n");
			return _MMAX;
		}
		for(i = NMPA, p = b.num + i, q = p - 1; i > 0; i--)	*p-- = *q--;
		*p = (UINT)t & RADIX1;
		t >>= RADIXBITS;
		b.exp++;
	}
	return b;
}

/*		m_div_s			MPA / int --> MPA	*/

MPA m_div_s(MPA a, int x)
{
	MPA b;
	int i, n;
	UINT *p, *q;
	ULONG u;

	if(x == 0)
	{
		fprintf(stderr, "Error : Divide by 0  in m_div_s()\n");
		return _MMAX;
	}
	if(a.zero)	return _M0;
	b.zero = 0;
	b.sign = (x > 0)? a.sign: 1 - a.sign;
	if(x < 0)	x = - x;
	b.exp = a.exp;
	if(a.num[0] < x)
	{
		u = a.num[0];
		n = 1;
		b.exp--;
	}
	else
	{
		u = 0;
		n = 0;
	}
	for(i = n, p = b.num, q = a.num + n; i <= NMPA; i++)
	{
		u = (u << RADIXBITS) + *q++;
		*p++ = u / x;
		u %= x;
	}
	if(n)
	{
		*p = (u << RADIXBITS) / x;
		u %= x;
	}
	if(2 * u >= x)
		for (i = NMPA, q= b.num + i; ++*q & RADIX; i--)	*q-- &= RADIX1;
	return b;
}

/*		m_mul1		MPA *= MPA	*/

void m_mul1(MPA *a, MPA b)
{
	int i, j;
	UINT x[NMPA2];
	UINT *p, *q, *r, *xp;
	ULONG u;
	long exp;

	if(a->zero)	return;
	if(b.zero)
	{
		*a = _M0;
		return;
	}
	for(i = 0; i < NMPA2; i++)	x[i] = 0;
	for(i = NMPA, xp = x + NMPA2 - 1, p = b.num + i; i >= 0; i--, xp--, p--)
	{
		if(*p)
		{
			u = 0;
			for(j = NMPA, q = a->num + j, r = xp; j >= 0; j--)
			{
				u += (ULONG)(*q--) * (ULONG)*p + *r;
				*r-- = (UINT)u & RADIX1;
				u >>= RADIXBITS;
			}
			while(u)
			{
				u += *r;
				*r-- = (UINT)u & RADIX1;
				u >>= RADIXBITS;
			}
		}
	}
	a->sign = (a->sign == b.sign)? 1: 0;
	a->exp += ++b.exp;
	for(i = 0, xp = x; i < NMPA2; i++, xp++)
	{
		if(*xp)	break;
		a->exp--;
	}
	if(a->exp > MAXEXP)
	{
		fprintf(stderr, "Error : Overflow  in m_mul1()\n");
		*a = _MMAX;
		return;
	}
	if(a->exp < MINEXP)
	{
		fprintf(stderr, "Error : Underflow  in m_mul1()\n");
		*a = _M0;
		return;
	}
	for(j = 0, p = a->num; (j <= NMPA) && (i < NMPA2); i++, j++)
		*p++ = *xp++;
	if(j <= NMPA)	for(; j <= NMPA; j++)	*p++ = 0;
	else if(*xp >= RADIX_2)
		for(i = NMPA, p = a->num + i; ++*p & RADIX; i--)	*p-- &= RADIX1;
	return;
}

/*		m_div1		MPA /= MPA	*/

void m_div1(MPA *a, MPA b)
{
	int sflag;

	if(a->zero)	return;
	if(b.zero)
	{
		sflag = a->sign;
		fprintf(stderr, "Error : Divide by 0  in m_div1()\n");
		*a = _MMAX;
		a->sign = sflag;
		return;
	}
	*a = m_div(*a, b);
	return;
}

/*		m_mul1_s		MPA *= int */

void m_mul1_s(MPA *a, int x)
{
	int i;
	UINT *p, *q;
	ULONG t, xl;

	if(a->zero)	return;
	if(x == 0)
	{
		*a = _M0;
		return;
	}
	if(x < 0)
	{
		a->sign = 1 - a->sign;
		x = - x;
	}
	xl= (ULONG)x;
	t = 0;
	for(i = NMPA, p = a->num + i; i >= 0; i--)
	{
		t += (ULONG)*p * xl;
		*p-- = (UINT)t & RADIX1;
		t >>= RADIXBITS;
	}
	while(t)
	{
		if(a->exp == MAXEXP)
		{
			fprintf(stderr, "Error : Overflow  in m_mul1_s()\n");
			*a = _MMAX;
			return;
		}
		for(i = NMPA, p = a->num + i, q = p - 1; i > 0; i--)	*p-- = *q--;
		*p = (UINT)t & RADIX1;
		t >>= RADIXBITS;
		a->exp++;
	}
	return;
}

/*		m_div1_s		MPA /= int	*/

void m_div1_s(MPA *a, int x)
{
	int i, n;
	UINT *p, *q;
	ULONG u;

	if(x == 0)
	{
		fprintf(stderr, "Error : Divide by 0  in m_div1_s()\n");
		*a = _MMAX;
		return;
	}
	if(a->zero)	return;
	if(x < 0){
		a->sign = 1 - a->sign;
		x = - x;
	}
	if(a->num[0] < x)
	{
		u = a->num[0];
		n = 1;
		a->exp--;
	}
	else
	{
		u = 0;
		n = 0;
	}
	for(i = n, p = a->num, q = p + n; i <= NMPA; i++)
	{
		u = (u << RADIXBITS) + *q++;
		*p++ = u / x;
		u %= x;
	}
	if(n)
	{
		*p = (u << RADIXBITS) / x;
		u %= x;
	}
	if(2 * u >= x)
		for (i = NMPA, q= a->num + i; ++*q & RADIX; i--)	*q-- &= RADIX1;
	return;
}

/*		m_mul_ss		MPA * int -> MPA  for a.num[m...NMPA]	*/

int m_mul_ss(int m, MPA a, UINT x, MPA *b)
{
	int i;
	UINT *p;
	ULONG t, xl;

	if(a.zero || x == 0)
	{
		*b = _M0;
		return NMPA1;
	}
	*b = a;
	xl = (ULONG)x;
	t = 0;
	for(i = NMPA, p = b->num + i; i >= m; i--)
	{
		t += (ULONG)*p * xl;
		*p++ = (UINT)t & RADIX1;
		t >>= RADIXBITS;
	}
	while(t)
	{
		t += (ULONG)*p;
		*p++ = (UINT)t & RADIX1;
		t >>= RADIXBITS;
		m--;
	}
	return m;
}

/*		m_div_ss		MPA / int -> MPA  for a.num[m...NMPA]	*/

int m_div_ss(int m, MPA a, UINT x, MPA *b)
{
	int i;
	UINT *p;
	ULONG t;

	if(a.zero)
	{
		for(i = m, p = b->num + m; i <= NMPA; i++)	*p++ = 0;
		return NMPA1;
	}
	*b = a;
	t = 0;
	for(i = m, p = b->num + m; i <= NMPA; i++)
	{
		t = (t << RADIXBITS) + *p;
		*p++ = t / x;
		t %= x;
	}
	if(2 * t >= x)
		for(i = NMPA, p = b->num + i; ++*p & RADIX; i--)	*p-- &= RADIX1;
	for(i = m, p = b->num + i; i <= NMPA; i++)	if(*p++)	break;
	return i;
}

/*		m_inv		1 / MPA --> MPA		*/

MPA m_inv(MPA b)
{
	if(b.zero)
	{
		fprintf(stderr, "Error : Divide by 0  in m_inv()\n");
		return _MMAX;
	}
	return m_div(_M1, b);
}

/*		m_pwr_s			MPA ^ int --> MPA	*/

MPA  m_pwr_s(MPA a, long x)
{
	MPA b;
	int flag = 0;

	b = m_set_l(1L);
	if(x == 0L)	return b;
	if(x < 0L)
	{
		flag = 1;
		x = - x;
	}
	if(x % 2 == 1)	b = a;
	x /= 2;
	while(x > 0)
	{
		a = m_sqr(a);
		if(x % 2 == 1)	m_mul1(&b, a);
		x /= 2;
	}
	if(flag)	return m_inv(b);
	return b;
}

/*		m_sqr		MPA ^ 2 --> MPA		*/

MPA m_sqr(MPA a)
{
	MPA b;
	int i, j;
	UINT x[NMPA2];
	UINT *p, *q, *r, *xp;
	ULONG u, pl;
	long exp;

	if(a.zero)	return _M0;
	for(i = 0, xp = x; i < NMPA2; i++)	*xp++ = 0;
	for(i = NMPA, xp = x + NMPA2 - 1, p = a.num + i; i >= 0; i--, xp -= 2, p--)
	{
		if(*p)
		{
			pl = (double)*p;
			r = xp;
			u = pl * pl + *r;
			*r-- = (UINT)u & RADIX1;
			u >>= RADIXBITS;
			pl *= 2;
			for(j = i - 1, q = p - 1; j >= 0; j--)
			{
				u += (ULONG)(*q--) * pl + *r;
				*r-- = (UINT)u & RADIX1;
				u >>= RADIXBITS;
			}
			while(u)
			{
				u += *r;
				*r-- = (UINT)u & RADIX1;
				u >>= RADIXBITS;
			}
		}
	}
	b.zero = 0;
	b.sign = 1;
	b.exp = a.exp * 2 + 1;
	for(i = 0, xp = x; i < NMPA2; i++, xp++)
	{
		if(*xp)	break;
		b.exp--;
	}
	if(b.exp > MAXEXP)
	{
		fprintf(stderr, "Error : Overflow  in m_sqr()\n");
		return _MMAX;
	}
	if(b.exp < MINEXP)
	{
		fprintf(stderr, "Error : Underflow  in m_sqr()\n");
		return _M0;
	}
	for(j = 0, p = b.num; (j <= NMPA) && (i < NMPA2); i++, j++)	*p++ = *xp++;
	if(j <= NMPA)	for(; j <= NMPA; j++)	*p++ = 0;
	else if(*xp >= RADIX_2)
		for(i = NMPA, p = b.num + i; ++*p & RADIX; i--)	*p-- &= RADIX1;
	return b;
}

/*		m_sqrt			MPA ^ 1/2 --> MPA	*/

MPA m_sqrt(MPA a)
{
	MPA b, s;

	if(a.zero)	return _M0;
	if(a.sign == 0)
	{
		fprintf(stderr, "Error : Illegal parameter  in m_sqrt()\n");
		return _M0;
	}
	s = _M1;
	b = a;
	while(m_cmp(s, b) < 0)
	{
		m_mul1_s(&s, 2);
		m_div1_s(&b, 2);
	}
	do
	{
		b = s;
		s = m_div_s(m_add(m_div(a, s), s), 2);
	} while(m_cmp(s, b) < 0);
	return b;
}

/*		m_idiv		integer (MPA / MPA) --> MPA		r : residue		*/

MPA m_idiv(MPA a, MPA b, MPA *r)
{
	MPA c;
	int a0, b0, cmp, d, i;
	UINT *p;

	if(a.zero || m_cmp_a(a, b) < 0)
	{
		*r = a;
		return _M0;
	}
	if(b.zero)
	{
		fprintf(stderr, "Error : Divide by 0  in m_idiv()\n");
		*r = _M0;
		return _MMAX;
	}
	c = m_int(m_div(a, b));
	while(1)
	{
		*r = m_sub(a, m_mul(b, c));
		cmp = m_cmp_a(*r, b);
		if(cmp < 0)	break;
		*r = _M1;
		m_add1_a(&c, *r);
		if(cmp == 0)
		{
			*r = _M0;
			break;
		}
	}
	return c;
}