数値Xの約数を数える

元の記事とは関係ないけどおまけ

ループその1

何にもわからなかったら、まずは素朴に

int	divisors_count( int	a ){
	debug_printf( "{ " );
	int	result = 0;
	int	n = 1;
	while( n <= a ){
		if( !( a % n )){
			if( n > 1 ){
				debug_printf( ", " );
			}
			debug_printf( "%d"), n );
			++result;
		}
		++n;
	}
	debug_printf( " } ... " );
	return	result;
}

int	main(){
	for( int	n = 0; n < 60; ++n ){
		int	cdivisors = divisors_count( n+1 );
		debug_printf( "... %d の約数の数は %d\n", n+1, cdivisors );
	}
	return	0;
}

ループその2

約数は必ずペアなので、それを考慮して

int	divisors_count( int	a ){
	int	result = 0;
	int	b = a;
	int	n = 1;
	do{
		if( !( a % n )){
			if( n > 1 ){
				debug_printf( ", ");
			}
			debug_printf( "(%d x %d)", n, a / n );
			++result;
			if( n*n == a ){
				break;
			}
			++result;
			b = a / (n+1);
		}
	}while( ++n <= b );
	debug_printf( "... " );
	return	result;
}

int	main(){
	for( int	n = 0; n < 60; ++n ){
		int	cdivisors = divisors_count( n+1 );
		debug_printf( "... %d の約数の数は %d\n", n+1, cdivisors );
	}
	return	0;
}

再帰

ループは再帰にできる

int	divisors_count( int	a ){
	struct detail {
		static int	callback( int	a, int	n, int	b ){
			int	result = 0;
			if( n <= b ){
				if( !( a % n )){
					if( n > 1 ){
						debug_printf( ", " );
					}
					debug_printf( "(%d x %d)"), n, a / n );
					++result;
					if( n*n != a ){
						++result;
					}
					result += callback( a, n+1, a / (n+1));
				}
				else{
					result = callback( a, n+1, b );
				}
			}
			return	result;
		}
	};
	return	detail::callback( a, 1, a );
}

int	main(){
	for( int	n = 0; n < 60; ++n ){
		int	cdivisors = divisors_count( n+1 );
		debug_printf( "... %d の約数の数は %d\n", n+1, cdivisors );
	}
	return	0;
}

テンプレート

再帰条件をコンパイル時に決定できる再帰はテンプレートにできる

template<int lhs,int rhs> struct less_than_or_equal_to_t {
	static const bool	value = ( lhs <= rhs );
};
template<int max_value,int n> struct is_divisor_of_t {
	static const bool	value = !( max_value % n );
};
template<int max_value,int n> struct is_sqrt_of_t {
	static const bool	value = ( n*n == max_value );
};
template<int N, int n = 1, int	max_value = N, int cdivisors = 0, bool = is_divisor_of_t<N,n>::value, bool = less_than_or_equal_to_t<n,max_value>::value> struct divisors_count_helper_t {
	static const int	value = divisors_count_helper_t<N,n+1,max_value,cdivisors>::value;
};
template<int N,int n,int cdivisors,bool = is_sqrt_of_t<N,n>::value> struct divisors_count_increment_helper_t {
	static const int	next = cdivisors+2;
};
template<int N,int n,int cdivisors> struct divisors_count_increment_helper_t<N,n,cdivisors,true> {
	static const int	next = cdivisors+1;
};
template<int N, int n, int	max_value, int cdivisors> struct divisors_count_helper_t<N,n,max_value,cdivisors,true,true> {
	static const int	value = divisors_count_helper_t<N,n+1,N/(n+1),divisors_count_increment_helper_t<N,n,cdivisors>::next>::value;
};
template<int N, int n, int	max_value, int cdivisors, bool is_divisor> struct divisors_count_helper_t<N,n,max_value,cdivisors,is_divisor,false> {
	static const int	value = cdivisors;
};
template<int n> struct divisors_count_t {
	static const int	value = divisors_count_helper_t<n>::value;
};

template<int	max_value,int n=1, bool = less_than_or_equal_to_t<n,max_value>::value> struct divisors_count_print_helper_t {
	static void	print(){
	}
};
template<int	max_value,int n> struct divisors_count_print_helper_t<max_value,n,true> {
	static void	print(){
		debug_printf( "%d の約数の数は %d\n", n, divisors_count_t<n>::value );
		divisors_count_print_helper_t<max_value,n+1>::print();
	}
};

int	main(){
	divisors_count_print_helper_t<60>::print();
	return	0;
}

テンプレートその2

約数の数を数えるだけだと何が約数かわからないので、約数も print してみる

template<int lhs,int rhs> struct less_than_or_equal_to_t {
	static const bool	value = ( lhs <= rhs );
};
template<int max_value,int n> struct is_divisor_of_t {
	static const bool	value = !( max_value % n );
};
template<int max_value,int n> struct is_sqrt_of_t {
	static const bool	value = ( n*n == max_value );
};
template<int N,int n,int cdivisors,bool = is_sqrt_of_t<N,n>::value> struct divisors_count_increment_helper_t {
	static const int	next = cdivisors+2;
};
template<int N,int n,int cdivisors> struct divisors_count_increment_helper_t<N,n,cdivisors,true> {
	static const int	next = cdivisors+1;
};
template<int N,int n,int> struct print_divisor_helper_t {
	static void	print(){
		debug_printf( ", (%d x %d)", n, N / n );
	}
};
template<int N,int n> struct print_divisor_helper_t<N,n,0> {
	static void	print(){
		debug_printf( _T("(%d x %d)", n, N / n );
	}
};
template<int N, int n = 1, int	max_value = N, int cdivisors = 0, bool = is_divisor_of_t<N,n>::value, bool = less_than_or_equal_to_t<n,max_value>::value> struct divisors_count_helper_t {
	static const int	value = divisors_count_helper_t<N,n+1,max_value,cdivisors>::value;
	static void	print(){
		divisors_count_helper_t<N,n+1,max_value,cdivisors>::print();
	}
};
template<int N, int n, int	max_value, int cdivisors> struct divisors_count_helper_t<N,n,max_value,cdivisors,true,true> {
	static const int	value = divisors_count_helper_t<N,n+1,N/(n+1),divisors_count_increment_helper_t<N,n,cdivisors>::next>::value;
	static void	print(){
		print_divisor_helper_t<N,n,cdivisors>::print();
		divisors_count_helper_t<N,n+1,N/(n+1),divisors_count_increment_helper_t<N,n,cdivisors>::next>::print();
	}
};
template<int N, int n, int	max_value, int cdivisors, bool is_divisor> struct divisors_count_helper_t<N,n,max_value,cdivisors,is_divisor,false> {
	static const int	value = cdivisors;
	static void	print(){
	}
};
template<int n> struct divisors_count_t {
	static const int	value = divisors_count_helper_t<n>::value;
	static void	print(){
		debug_printf( "%d の約数は ", n );
		divisors_count_helper_t<n>::print();
		debug_printf( " の %d\n", value );
	}
};

template<int	max_value,int n=1, bool = less_than_or_equal_to_t<n,max_value>::value> struct divisors_count_print_helper_t {
	static void	print(){
	}
};
template<int	max_value,int n> struct divisors_count_print_helper_t<max_value,n,true> {
	static void	print(){
		divisors_count_t<n>::print();
		divisors_count_print_helper_t<max_value,n+1>::print();
	}
};

int	main(){
	divisors_count_print_helper_t<60>::print();
	return	0;
}

テンプレートその3

約数のペアじゃなくて 1 から順番に print してみると

template<int lhs,int rhs> struct less_than_t {
	static const bool	value = ( lhs < rhs );
};
template<int lhs,int rhs> struct less_than_or_equal_to_t {
	static const bool	value = ( lhs <= rhs );
};
template<int max_value,int n> struct is_divisor_of_t {
	static const bool	value = !( max_value % n );
};
template<int max_value, int n = 1, int cdivisors = 0, bool = is_divisor_of_t<max_value,n>::value, bool = less_than_or_equal_to_t<n*2,max_value>::value> struct divisors_count_helper_t {
	static const int	value = divisors_count_helper_t<max_value,n+1,cdivisors>::value;
	static void	print(){
		divisors_count_helper_t<max_value,n+1,cdivisors>::print();
	}
};
template<int max_value, int n, int cdivisors> struct divisors_count_helper_t<max_value,n,cdivisors,true,true> {
	static const int	value = divisors_count_helper_t<max_value,n+1,cdivisors+1>::value;
	static void	print(){
		debug_printf( ",%d", n );
		divisors_count_helper_t<max_value,n+1,cdivisors+1>::print();
	}
};
template<int max_value, int cdivisors> struct divisors_count_helper_t<max_value,1,cdivisors,true,true> {
	static const int	value = divisors_count_helper_t<max_value,1+1,cdivisors+1>::value;
	static void	print(){
		debug_printf( "1" );
		divisors_count_helper_t<max_value,1+1,cdivisors+1>::print();
	}
};
template<int max_value, int n, int cdivisors, bool is_divisor> struct divisors_count_helper_t<max_value,n,cdivisors,is_divisor,false> {
	static const int	value = cdivisors;
	static void	print(){
	}
};
template<int n> struct divisors_count_t {
	static const int	value = divisors_count_helper_t<n>::value;
	static void	print(){
		debug_printf( "%d の約数は ", n );
		divisors_count_helper_t<n>::print();
		debug_printf( " の %d\n", value );
	}
};

int	main(){
	divisors_count_t<60>::print();
	return	0;
}