多倍長演算ライブラリ ルーチン5



[ 簡単な説明 ]

行列式の値を計算します。行列式は、サイズ n × n の大きさの1次元配列 aa[ ] で指定します。


プログラム・ソース("det.c")           top (トップに戻る)
/*		det.c		行列式の値計算		*/
#include "longint.h"

LINT det(LINT *aa, int n)
{
	LINT *a, d, dd, g, min, w, x, k1, k2;
	int i, j, k, p, ip, jp;

	if(n < 1)
	{
		fprintf(stderr, "Error : illegal size in  det()\n");
		exit(-1);
	}
	if(n == 1)	return *a;

	a = (LINT *)malloc(n * n * sizeof(LINT));
	if(a == NULL)
	{
		fprintf(stderr, "Error : out of memory  in det().\n");
		exit(-2);
	}
	for(i = 0; i < n * n; i++)	a[i] = aa[i];

	d.sign = dd.sign = 0;
	d.len = dd.len = 1;
	d.num[1] = dd.num[1] = 1;
	for(p = n; p > 2; p--)
	{
		if(a[0].len == 0)
		{
			for(i = 1; i < p; i++)	if(a[i * p].len > 0)	break;
			if(i == p)
			{
				d.len = 0;
				free(a);
				return d;
			}
			d.sign = (d.sign == -1)? 0: -1;
			i *= p;
			for(j = 0; j < p;)
			{
				w = a[j];
				a[j++] = a[i];
				a[i++] = w;
			}
		}
		g = lllcm(a, p);
		k1 = ldivide(g, a[0], &w);
		lmul1(&dd, k1);
		lmul1(&d, g);
		for(i = 1; i < p; i++)	lmul1(&a[i * p], k1);
		for(j = 1; j < p; j++)
		{
			if(a[j].len > 0)
			{
				k2 = ldivide(g, a[j], &w);
				lmul1(&dd, k2);
				for(i = 1; i < p; i++)
				{
					k = i * p;
					a[k + j] = lsub(lmul(a[k + j], k2), a[k]);
				}
			}
		}
		for(i = 1, k = 0; i < p; i++)
			for(j = 1; j < p; j++)	a[k++] = a[i * p + j];
	}
	lmul1(&d, lsub(lmul(a[0], a[3]), lmul(a[1], a[2])));
	d = ldivide(d, dd, &w);
	free(a);
	return d;
}