UsefullCode.net


Visual Studio 2005/2008/2010やandroid SDK/NDKでの開発者向けに便利なソースコードを提供
This site provide you with useful source codes under 'USEFULLCODE license'.

分数を約分する

2007年02月11日 18:13
0件のコメント

test111.gif
分数の約分をしたいときは最初に分母と分子から共通因子を取り出す。ここでは共通因子を取り出す方法として素因数分解を利用した。分母、分子を素因数分解し、共通して含まれる素因数を消去することで約分した。

約分の過程で用いた素因数分解処理用のクラスと関数は「数値を素因数分解する」と同じものを利用している。

依存環境:ATL
#include "math.h"
#include "atlcoll.h"
#include "atlstr.h"



class	CElementInfo
{
public:
	long	_nElement;
	ULONG	_nCount;

	CElementInfo()
	{
		_nElement = 0;
		_nCount = 0;
	}

	CElementInfo(long nElement,ULONG nCount)
	{
		_nElement = nElement;
		_nCount = nCount;
	}

	CElementInfo&	operator++()
	{
		_nCount++;
		return	*this;
	}
	CElementInfo&	operator++(int)
	{
		_nCount++;
		return	*this;
	}

	CElementInfo&	operator--()
	{
		if(_nCount)
			_nCount--;
		return	*this;
	}
	CElementInfo&	operator--(int)
	{
		if(_nCount)
			_nCount--;
		return	*this;
	}
};



//
//	素因数分解
//
bool	Digest(long nData,CAtlArray<CElementInfo>* pacElements)
{
	long	nElement;
	ULONG	nCount;
	long	nLoopMax;

	if(pacElements == NULL)
		return	false;
	pacElements->RemoveAll();

	//負の数なら素因数として-1を与える
	if(nData < 0)
	{
		pacElements->Add(CElementInfo(-1,1));
		nData *= -1;
	}
	if(nData == 0 || nData == 1)
		return	true;

	nLoopMax = (long)sqrt((double)nData) + 1;
	for(nElement = 2; nElement <= nLoopMax; nElement += 2)
	{
		if(nElement == 4)	//2で素因数分解を1回行った後は3,5,7...2n+1で処理を
			nElement--;	//行なうように4のときに1を減算

		nCount = 0;
		while(1)
		{
			if(nData % nElement)
				break;

			nCount++;
			nData /= nElement;
		}
		if(nCount > 0)
			pacElements->Add(CElementInfo(nElement,nCount));
		if(nData == 1)
			break;
	}
	if(nData > 1)
		pacElements->Add(CElementInfo(nData,1));

	return	true;
}


//
//	約分
//
//nDenominator	:分母
//nNumerator	:分子
//
bool	Reduction(long nDenominator,long nNumerator,CAtlArray<CElementInfo>* pacDenominatorElements,CAtlArray<CElementInfo>* pacNumeratorElements)
{
	CAtlArray<CElementInfo>*	pA;
	CAtlArray<CElementInfo>*	pB;

	if(pacDenominatorElements)
		pacDenominatorElements->RemoveAll();
	if(pacNumeratorElements)
		pacNumeratorElements->RemoveAll();
	if(pacNumeratorElements == NULL || pacDenominatorElements == NULL)
		return	false;

	if(nDenominator == 0 || nNumerator == 0)
		return	true;
	if(nDenominator == -1)
	{
		//分母が-1だったら、分子に-1をかけて終わり
		nDenominator = 1;
		nNumerator *= -1;
		return	true;
	}
	if(nDenominator == 1 || nNumerator == 1)
		return	true;


	///////////////////////////////
	//約分前処理
	//

	if(nDenominator < 0)
	{
		//分母がマイナスだったら分子にマイナス記号を移す
		nDenominator *= -1;
		nNumerator *= -1;
	}

	//分母・分子ともに素因数分解
	Digest(nDenominator,pacDenominatorElements);
	Digest(nNumerator,pacNumeratorElements);

	//素因数の数が少ない方をpA、多い方をpBにする
	if(pacDenominatorElements->GetCount() < pacNumeratorElements->GetCount())
	{
		pA = pacDenominatorElements;
		pB = pacNumeratorElements;
	}
	else
	{
		pA = pacNumeratorElements;
		pB = pacDenominatorElements;
	}


	///////////////////////////////
	//約分処理
	//
	size_t	i;
	size_t	j;
	size_t	nSizeA;
	size_t	nSizeB;

	i = 0;
	nSizeA = pA->GetCount();
	nSizeB = pB->GetCount();
	for(j = 0; j < nSizeB; j++)
	{
		for(; i < nSizeA; i++)
		{
			if((*pA)[i]._nElement < (*pB)[j]._nElement)
				continue;
			if((*pA)[i]._nElement > (*pB)[j]._nElement)
				break;

			//共通する素因数の数だけnCountを減らす
			if((*pA)[i]._nCount < (*pB)[j]._nCount)
			{
				(*pB)[j]._nCount -= (*pA)[i]._nCount;
				(*pA)[i]._nCount = 0;
			}
			else if((*pA)[i]._nCount > (*pB)[j]._nCount)
			{
				(*pA)[i]._nCount -= (*pB)[j]._nCount;
				(*pB)[j]._nCount = 0;
			}
			else
			{
				(*pA)[i]._nCount = 0;
				(*pB)[j]._nCount = 0;
			}
			break;
		}
	}

	return	true;
}


//
//	約分
//
//nDenominator	:分母
//nNumerator	:分子
//
bool	Reduction(long& nDenominator,long& nNumerator)
{
	bool	ret;
	CAtlArray<CElementInfo>		acElementsA;
	CAtlArray<CElementInfo>		acElementsB;

	///////////////////////////////
	//約分
	//
	ret = Reduction(nDenominator,nNumerator,&acElementsA,&acElementsB);
	if(ret == false)
		return	false;


	///////////////////////////////
	//約分結果の数値計算
	//
	size_t	i;
	size_t	j;
	size_t	nSizeI;
	size_t	nSizeJ;

	nDenominator = 1;
	nSizeI = acElementsA.GetCount();
	for(i = 0; i < nSizeI; i++)
	{
		nSizeJ = acElementsA[i]._nCount;
		for(j = 0; j < nSizeJ; j++)
			nDenominator *= acElementsA[i]._nElement;
	}

	nNumerator = 1;
	nSizeI = acElementsB.GetCount();
	for(i = 0; i < nSizeI; i++)
	{
		nSizeJ = acElementsB[i]._nCount;
		for(j = 0; j < nSizeJ; j++)
			nNumerator *= acElementsB[i]._nElement;
	}

	return	true;
}




bool	Test()
{
	long	nA;
	long	nB;

	CAtlString	strBuff;
	CAtlString	strMessage;

	nA = 384;
	nB = 96;

	strBuff.Format(_T("%d/%d = "),nB,nA);
	strMessage += strBuff;

	//約分
	Reduction(nA,nB);

	strBuff.Format(_T("%d/%d"),nB,nA);
	strMessage += strBuff;

	::MessageBox(NULL,strMessage,_T("結果"),MB_OK);

	return	true;
}

プロジェクトファイルをダウンロード


数値を素因数分解する
数値の平方根を計算する
トップページに戻る
issei.