指定された数値Xが素数であるかどうかを判定する
素数判定法
簡単な公式は無いので地道に頑張る
というか公式を見つけたら大発見
ある数の素数性を得るためのフェルマー法とかミラー法とかミラー・ラビン法とかを使えば相当の高速化が期待できるから十分に知っているなら使ってもいいとは思うけど、あくまでも「ホワイトボード」プログラミングなのでそういったアルゴリズムを使うか使わないかはあまり意味がないと思うよ
ループ
何にもわからなかったらベタにでもいいからまずは何か書いてみること
小さい方の素因数は元の数の平方根より大きくならないことを利用して
// n は素数かな bool is_prime_number( int n ){ bool result = true; if( n == 2 ){ result = true; } else if(( n < 2 )|| !( n & 1 )){ result = false; } else{ // prime_factor は素因数。2 より大きい最小の素数は 3 なので 3 から始めるよ int prime_factor = 3; // 小さい方の素因数の二乗は必ず n 以下だから √n 以下の素数で割り切れなければ n は素数だよ while(( prime_factor * prime_factor <= n )&&( n % prime_factor )){ prime_factor += 2; } result = ( prime_factor * prime_factor > n ); } return result; } // n より大きい最小の素数を得る int prime_number_next( int n ){ if( n < 2 ){ n = 2; } else if( n < 3 ){ n = 3; } else{ if( !( n & 1 )){ --n; } do{ n += 2; }while( !is_prime_number( n )); } return n; } int main(){ int cprime_numbers = 0; for( int n = 0; n < 100; ++n ){ if( is_prime_number( n )){ debug_printf( "%d,", n ); ++cprime_numbers; } } debug_printf( "\n" ); { int n = 0; for( int m = 0; m < cprime_numbers; ++m ){ n = prime_number_next( n ); debug_printf( "%d,", n ); } } debug_printf( "\n" ); return 0; }
少し高速化
5以上の素数は決して 2 でも 3 でも割り切れないので必ず 3*2*m-1 か 3*2*m+1 になることを利用して
// n は素数かな? bool is_prime_number( int n ){ bool result = true; if(( n == 2 )||( n == 3 )){ result = true; } else if(( n < 2 )|| !( n & 1 )){ result = false; } else{ // 5以上の素数は決して 2 でも 3 でも割り切れないので必ず 3*2*m-1 か 3*2*m+1 になる int n1 = n+1; int n2 = n-1; if(( n1 % (2*3))&&( n2 % (2*3))){ // ということは素数の前後の数は 3*2*m-1+1 か 3*2*m+1-1 になり、つまり少なくともどちらかは必ず 6 の倍数なので、そうじゃなかったらダメ result = false; } else{ // 残りは地道に調べる // 小さい方の素因数は元の数の平方根より大きくはならないのでそこまでチェックすれば十分 int m = 1; for(;;){ int prime_factor1 = 3 * 2 * m - 1; int prime_factor2 = 3 * 2 * m + 1; if( prime_factor1 * prime_factor1 > n ){ break; } else if( !( n % prime_factor1 )){ result = false; break; } else if( prime_factor2 * prime_factor2 > n ){ break; } else if( !( n % prime_factor2 )){ result = false; break; } ++m; } } } return result; } // n より大きい最小の素数を得る int prime_number_next( int n ){ if( n < 2 ){ n = 2; } else if( n < 3 ){ n = 3; } else{ if( !( n & 1 )){ --n; } do{ n += 2; }while( !is_prime_number( n )); } return n; } int main(){ int cprime_numbers = 0; for( int n = 0; n < 100; ++n ){ if( is_prime_number( n )){ debug_printf( "%d,", n ); ++cprime_numbers; } } debug_printf( "\n" ); { int n = 0; for( int m = 0; m < cprime_numbers; ++m ){ n = prime_number_next( n ); debug_printf( "%d,", n ); } } debug_printf( "\n" ); return 0; }
テンプレート:その1
素数かどうかをチェックする対象が定数なのであれば、テンプレートを使ってコンパイル時に調べることもできます
(コンパイル時間が長くなります)
template<int n> struct is_even_t { static const int value = !( n & 1 ); }; template<int n,int prime_factor> struct is_prime_loop_helper_t { static const int value = ( prime_factor * prime_factor > n ); }; template<int n, int prime_factor = 3,bool = is_even_t<n>::value,bool = is_prime_loop_helper_t<n,prime_factor>::value> struct is_prime_t { static const bool value = ( n % prime_factor )&& is_prime_t<n,prime_factor+2,is_even_t<n>::value,is_prime_loop_helper_t<n,prime_factor+2>::value>::value; }; template<int n,int prime_factor> struct is_prime_t<n,prime_factor,false,true> { static const bool value = true; }; template<int n,int prime_factor> struct is_prime_t<n,prime_factor,true,true> { static const bool value = false; }; template<int prime_factor> struct is_prime_t<1,prime_factor,false,true> { static const bool value = false; }; template<int prime_factor> struct is_prime_t<2,prime_factor,true,true> { static const bool value = true; }; template<int prime_factor> struct is_prime_t<3,prime_factor,false,true> { static const bool value = true; }; #define is_prime_number( n ) is_prime_t<(n)>::value template<int N,int n = 1> struct prime_print_t { static void print(){ if( is_prime_number( n )){ debug_printf( "%d,\n", n ); } prime_print_t<N,n+1>::print(); } }; template<int N> struct prime_print_t<N,1> { static void print(){ if( is_prime_number( 1 )){ debug_printf( "1,\n" ); } prime_print_t<N,1+1>::print(); } }; template<int n> struct prime_print_t<n,n> { static void print(){ } }; template<int N> static void prime_print(){ prime_print_t<N>::print(); } int main(){ prime_print<100>(); return 0; }
テンプレート:その2
素数かどうかをチェックするのではなくコンパイル時に n 番目の素数がほしいという場合もテンプレートを使って書くことができます
(コンパイル時間が長くなります)
template<int lhs,int rhs> struct less_than_or_equal_to_t { static const bool value = ( lhs <= rhs ); }; template<int nth,int n = 0,int prime_number = 2,bool = is_prime_t<prime_number>::value,bool = less_than_or_equal_to_t<nth,n>::value> struct nth_prime_number_t { static const int value = nth_prime_number_t<nth,n,prime_number+2,is_prime_t<prime_number+2>::value,less_than_or_equal_to_t<nth,n>::value>::value; }; template<int nth,int n,int prime_number> struct nth_prime_number_t<nth,n,prime_number,true,false> { static const int value = nth_prime_number_t<nth,n+1,prime_number+2,is_prime_t<prime_number+2>::value,less_than_or_equal_to_t<nth,n+1>::value>::value; }; template<int nth> struct nth_prime_number_t<nth,0,2,true,false> { static const int value = nth_prime_number_t<nth,1,3,is_prime_t<3>::value,less_than_or_equal_to_t<nth,1>::value>::value; }; template<int nth,int n,int prime_number> struct nth_prime_number_t<nth,n,prime_number,true,true> { static const int value = prime_number; }; template<> struct nth_prime_number_t<0,0,2,true,true> { static const int value = 2; }; template<> struct nth_prime_number_t<1,1,3,true,true> { static const int value = 3; }; template<int N,int n = 0> struct prime_print_t { static void print(){ debug_printf( "%d,\n", nth_prime_number_t<n>::value ); prime_print_t<N,n+1>::print(); } }; template<int n> struct prime_print_t<n,n> { static void print(){ } }; template<int N> static void prime_print(){ prime_print_t<N>::print(); } int main(){ prime_print<100>(); return 0; }