bate's blog

調べたこと実装したことなどを取りとめもなく書きます。

reduction関数を簡潔にしてみた

今までの奴は下記のもの。

// 約分
template<class T> TFriction<T> TFriction<T>::reduction()
{
	Exec();

	// 負の符号の時は、分子から負を取り因数分解する
	if( false == m_sign )
		m_numerator *= -1;

	std::vector<T> n_factor = Factorization<T>( m_numerator );
	std::vector<T> d_factor = Factorization<T>( m_denominator );

	unsigned int counter=0;
	int save_index = 0;
	for( int i = 0; i < (int)n_factor.size(); ++i )
	{
		for( int j = 0; j < (int)d_factor.size(); ++j )
		{
			std::cout << counter << " - " << n_factor.at(i) << ":" << d_factor.at(j) << std::endl;
			++counter;
			if( n_factor.at(i) == d_factor.at(j) )
			{
				n_factor.at(i) = d_factor.at(j) = 1;
			}
		}
	}
	
	T num = 1;
	T den = 1;
	for( int i = 0; i < (int)n_factor.size(); ++i )
		num *= n_factor.at(i);
	for( int j = 0; j < (int)d_factor.size(); ++j )
		den *= d_factor.at(j);

	if( false == m_sign ) num *= -1;

	return TFriction<T>( num, den );
}

下記のmain.cppを実行すると142回ループを実行する

// main.cpp
#include "Friction.h"

int main()
{
	TFriction<int> a( 2*3*4*5, 6*7*8 ), b( 5*6*16, 6*30*2 ), c;
	c = a / b;
	c.Disp();

	return 0;
}

まずは簡単にbreakつけたもので先ほどのmain.cppを実行すると、ループは79回だった。
勿論、答えは同じ15/56になる。

// 約分
template<class T> TFriction<T> TFriction<T>::reduction()
{
	Exec();

	// 負の符号の時は、分子から負を取り因数分解する
	if( false == m_sign )
		m_numerator *= -1;

	std::vector<T> n_factor = Factorization<T>( m_numerator );
	std::vector<T> d_factor = Factorization<T>( m_denominator );

	unsigned int counter=0;
	int save_index = 0;
	for( int i = 0; i < (int)n_factor.size(); ++i )
	{
		for( int j = 0; j < (int)d_factor.size(); ++j )
		{
			std::cout << counter << " - " << n_factor.at(i) << ":" << d_factor.at(j) << std::endl;
			++counter;
			if( n_factor.at(i) == d_factor.at(j) )
			{
				n_factor.at(i) = d_factor.at(j) = 1;
				break;
			}
		}
	}


	
	T num = 1;
	T den = 1;
	for( int i = 0; i < (int)n_factor.size(); ++i )
		num *= n_factor.at(i);
	for( int j = 0; j < (int)d_factor.size(); ++j )
		den *= d_factor.at(j);

	if( false == m_sign ) num *= -1;

	return TFriction<T>( num, den );
}


新しいものは下記のものになる。
同じくmain.cppを実行すると、ループは14回になる。勿論、結果は15/56になっている。
これは、既に素因数分解された要素が昇順(小から大の順番に並ぶ)にソートされていることからくる(降順は大から小の順番に並ぶ)。
もっと早い方法があるかは完成後に取っておく。
加減乗除の演算子を使うたびに約分するか、operator=で一括するか。
どっちがよいだろうか。

// 約分
template<class T> TFriction<T> TFriction<T>::reduction()
{
	Exec();

	// 負の符号の時は、分子から負を取り因数分解する
	if( false == m_sign )
		m_numerator *= -1;

	std::vector<T> n_factor = Factorization<T>( m_numerator );
	std::vector<T> d_factor = Factorization<T>( m_denominator );

	unsigned int counter=0;
	int j = 0, save_index = 0;
	for( int i = 0; i < (int)n_factor.size(); ++i )
	{
		j = save_index;
		while( j < (int)d_factor.size() )
		{
			std::cout << counter << " - " << n_factor.at(i) << ":" << d_factor.at(j) << std::endl;
			++counter;
			if( n_factor.at(i) == d_factor.at(j) )
			{
				n_factor.at(i) = d_factor.at(j) = 1;
				save_index = j+1;
				break;
			}

			++j;
		}
	}


	
	T num = 1;
	T den = 1;
	for( int i = 0; i < (int)n_factor.size(); ++i )
		num *= n_factor.at(i);
	for( int j = 0; j < (int)d_factor.size(); ++j )
		den *= d_factor.at(j);

	if( false == m_sign ) num *= -1;

	return TFriction<T>( num, den );
}