数値Xを2,8,10,16進数で表示する
元の記事とは関係ないけどおまけ
ループその1
それぞれの記数法で各桁を分解することができるでしょうか
わからないときはまずは簡単なところからやりましょう
表示の前にまず桁数を数えるだけやってみましょう
int log2_i( int n ){ int cdigits = 0; do{ ++cdigits; n >>= 1; }while( n ); return cdigits; } int log8_i( int n ){ int cdigits = 0; do{ ++cdigits; n >>= 3; }while( n ); return cdigits; } int log10_i( int n ){ int cdigits = 0; do{ ++cdigits; n /= 10; }while( n ); return cdigits; } int log16_i( int n ){ int cdigits = 0; do{ ++cdigits; n >>= 4; }while( n ); return cdigits; } void print_log2_i( int m ){ int n = 1; while( n < m ){ debug_printf( "0x%08x は %d桁\n", n-1, log2_i( n-1 )); debug_printf( "0x%08x は %d桁\n", n, log2_i( n )); debug_printf( "0x%08x は %d桁\n", n+1, log2_i( n+1 )); n <<= 1; } } void print_log8_i( int m ){ int n = 1; while( n < m ){ debug_printf( "0%o は %d桁\n", n-1, log8_i( n-1 )); debug_printf( "0%o は %d桁\n", n, log8_i( n )); debug_printf( "0%o は %d桁\n", n*4, log8_i( n*4 )); n <<= 3; } } void print_log10_i( int m ){ int n = 1; while( n < m ){ debug_printf( "%d は %d桁\n", n-1, log10_i( n-1 )); debug_printf( "%d は %d桁\n", n, log10_i( n )); debug_printf( "%d は %d桁\n", n*5, log10_i( n*5 )); n *= 10; } } void print_log16_i( int m ){ int n = 1; while( n < m ){ debug_printf( "0x%08x は %d桁\n", n-1, log16_i( n-1 )); debug_printf( "0x%08x は %d桁\n", n, log16_i( n )); debug_printf( "0x%08x は %d桁\n", n*8, log16_i( n*8 )); n <<= 4; } } int main(){ print_log2_i( 0x10000 ); print_log8_i( 010000 ); print_log10_i( 10000 ); print_log16_i( 0x10000 ); return 0; }
ループその2
それぞれの記数法で各桁を分解できるようになったら、それを表示してみましょう
まずは素朴にやってみればいいでしょう
template<typename _value_type> void reverse_array( _value_type* pelt, int celt ){ int first = 0; int last = celt-1; while( first < last ){ int temp = pelt[first]; pelt[first] = pelt[last]; pelt[last] = temp; ++first; --last; } } void binary_print( int m ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ digits[cdigits] = '0' + ( n & 1 ); ++cdigits; n >>= 1; }while( n ); digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } void octal_print( int m ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ digits[cdigits] = '0' + ( n & 7 ); ++cdigits; n >>= 3; }while( n ); digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } void decimal_print( int m ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ digits[cdigits] = '0' + ( n % 10 ); ++cdigits; n /= 10; }while( n ); digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } void hexadecimal_print( int m ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ int c = ( n & 0x0f ); digits[cdigits] = ( c >= 0x0a ) ? ( 'A' + c - 0x0a ) : ( '0' + c ); ++cdigits; n >>= 4; }while( n ); digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } int main(){ binary_print( 0x1234 ); octal_print( 01234 ); decimal_print( 1234 ); hexadecimal_print( 0x1234 ); return 0; }
ループその3
桁数を指定できるようにしてみましょう
template<typename _value_type> void reverse_array( _value_type* pelt, int celt ){ int first = 0; int last = celt-1; while( first < last ){ int temp = pelt[first]; pelt[first] = pelt[last]; pelt[last] = temp; ++first; --last; } } void binary_print( int m, int length ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ digits[cdigits] = '0' + ( n & 1 ); ++cdigits; n >>= 1; }while( n ); while( cdigits < length ){ digits[cdigits] = '0'; ++cdigits; } digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } void octal_print( int m, int length ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ digits[cdigits] = '0' + ( n & 7 ); ++cdigits; n >>= 3; }while( n ); while( cdigits < length ){ digits[cdigits] = '0'; ++cdigits; } digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } void decimal_print( int m, int length ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ digits[cdigits] = '0' + ( n % 10 ); ++cdigits; n /= 10; }while( n ); while( cdigits < length ){ digits[cdigits] = '0'; ++cdigits; } digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } void hexadecimal_print( int m, int length ){ char digits[100] = {}; int n = m; int cdigits = 0; do{ int c = ( n & 0x0f ); digits[cdigits] = ( c >= 0x0a ) ? ( 'A' + c - 0x0a ) : ( '0' + c ); ++cdigits; n >>= 4; }while( n ); while( cdigits < length ){ digits[cdigits] = '0'; ++cdigits; } digits[cdigits] = 0; reverse_array( digits, cdigits ); debug_printf( digits ); debug_printf( "\n" ); } int main(){ binary_print( 0x1234, 64 ); octal_print( 01234, 64 ); decimal_print( 1234, 64 ); hexadecimal_print( 0x1234, 64 ); return 0; }
ループその4
次にはバッファを使わないようにしてみましょう
int pow10_i( int n ){ int a = 1; for( int m = 0; m < n; ++m ){ if( a * 10 < a ){ a = 0; break; } a *= 10; } return a; } void binary_print( int m, int length ){ for( int n = 0; n < length; ++n ){ int l = ( length - n - 1 ); int value = 0; if(( l >= 0 )&&( l < sizeof( m )*8 )){ value = (( m >> l ) & 1 ); } char digit[] = { '0' + value, 0 }; debug_printf( digit ); } debug_printf( "\n" ); } void octal_print( int m, int length ){ for( int n = 0; n < length; ++n ){ int l = ( length - n - 1 ) * 3; int value = 0; if(( l >= 0 )&&( l < sizeof( m )*8 )){ value = (( m >> l ) & 7 ); } char digit[] = { '0' + value, 0 }; debug_printf( digit ); } debug_printf( "\n" ); } void decimal_print( int m, int length ){ for( int n = 0; n < length; ++n ){ int l = length - n - 1; int a = pow10_i( l ); int value = 0; if( a ){ value = ( m / a ) % 10; } char digit[] = { '0' + value, 0 }; debug_printf( digit ); } debug_printf( "\n" ); } void hexadecimal_print( int m, int length ){ for( int n = 0; n < length; ++n ){ int l = ( length - n - 1 ) * 4; int value = 0; if(( l >= 0 )&&( l < sizeof( m )*8 )){ value = (( m >> l ) & 0x0f ); } char digit[] = { ( value >= 0x0a ) ? ( 'A' + value - 0x0a ) : ( '0' + value ), 0 }; debug_printf( digit ); } debug_printf( "\n" ); } int main(){ binary_print( 0x1234, 64 ); octal_print( 01234, 64 ); decimal_print( 1234, 64 ); hexadecimal_print( 0x1234, 64 ); return 0; }
ループその5
さらに事前に桁数をチェックして余計な部分の 0 は先に表示してしまうようにしてみましょう
int log2_i( int n ){ int cdigits = 0; do{ ++cdigits; n >>= 1; }while( n ); return cdigits; } int log8_i( int n ){ int cdigits = 0; do{ ++cdigits; n >>= 3; }while( n ); return cdigits; } int log10_i( int n ){ int cdigits = 0; do{ ++cdigits; n /= 10; }while( n ); return cdigits; } int log16_i( int n ){ int cdigits = 0; do{ ++cdigits; n >>= 4; }while( n ); return cdigits; } int pow10_i( int n ){ int a = 1; for( int m = 0; m < n; ++m ){ if( a * 10 < a ){ a = 0; break; } a *= 10; } return a; } void binary_print( int m, int max_length ){ int length = log2_i( m ); while( max_length > length ){ debug_printf( "0" ); --max_length; } for( int n = 0; n < length; ++n ){ int value = (( m >> ( length - n - 1 )) & 1 ); char digit[] = { '0' + value, 0 }; debug_printf( digit ); } debug_printf( "\n" ); } void octal_print( int m, int max_length ){ int length = log8_i( m ); while( max_length > length ){ debug_printf( "0" ); --max_length; } for( int n = 0; n < length; ++n ){ int value = (( m >> (( length - n - 1 ) * 3 )) & 7 ); char digit[] = { '0' + value, 0 }; debug_printf( digit ); } debug_printf( "\n" ); } void decimal_print( int m, int max_length ){ int length = log10_i( m ); while( max_length > length ){ debug_printf( "0" ); --max_length; } for( int n = 0; n < length; ++n ){ int value = ( m / pow10_i( length - n - 1 )) % 10; char digit[] = { '0' + value, 0 }; debug_printf( digit ); } debug_printf( "\n" ); } void hexadecimal_print( int m, int max_length ){ int length = log16_i( m ); while( max_length > length ){ debug_printf( "0" ); --max_length; } for( int n = 0; n < length; ++n ){ int value = (( m >> (( length - n - 1 ) * 4 )) & 0x0f ); char digit[] = { ( value >= 0x0a ) ? ( 'A' + value - 0x0a ) : ( '0' + value ), 0 }; debug_printf( digit ); } debug_printf( "\n" ); } int main(){ binary_print( 0x1234, 64 ); octal_print( 01234, 64 ); decimal_print( 1234, 64 ); hexadecimal_print( 0x1234, 64 ); return 0; }
ループその6
それぞれの記数法に特化したコードがあるのは実行効率の点からはいいのですが、ここは一つで全部に対応できるようにしてみるとどうなるかやってみましょう
int log_i( int m, int n ){ int cdigits = 0; do{ ++cdigits; n /= m; }while( n ); return cdigits; } int pow_i( int m, int n ){ int a = 1; for( int i = 0; i < n; ++i ){ if( a * m < a ){ a = 0; break; } a *= m; } return a; } void digits_print( int m, int n, int max_length ){ int length = log_i( m, n ); while( max_length > length ){ debug_printf( "0" ); --max_length; } for( int i = 0; i < length; ++i ){ int value = ( n / pow_i( m, length - i - 1 )) % m; char digit[] = { ( value >= 0x0a ) ? ( 'A' + value - 0x0a ) : ( '0' + value ), 0 }; debug_printf( digit ); } debug_printf( "\n" ); } int main(){ digits_print( 2, 0x1234, 64 ); digits_print( 8, 01234, 64 ); digits_print( 10, 1234, 64 ); digits_print( 16, 0x1234, 64 ); return 0; }
テンプレートその1
さて対象が定数ならテンプレートを使ってコンパイル時に解決することができるということはもうおわかりでしょう
まずは桁数を数えてみましょう
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 n> struct log2_i_helper_t { static const int next = n >> 1; }; template<int N, int n = N, int cdigits = 0, bool = less_than_t<0,n>::value> struct log2_i_t { static const int value = cdigits; }; template<int N, int n, int cdigits> struct log2_i_t<N,n,cdigits,true> { static const int value = log2_i_t<N,log2_i_helper_t<n>::next,cdigits+1>::value; }; template<> struct log2_i_t<0,0,0,false> { static const int value = 1; }; template<int n> struct log8_i_helper_t { static const int next = n >> 3; }; template<int N, int n = N, int cdigits = 0, bool = less_than_t<0,n>::value> struct log8_i_t { static const int value = cdigits; }; template<int N, int n, int cdigits> struct log8_i_t<N,n,cdigits,true> { static const int value = log8_i_t<N,log8_i_helper_t<n>::next,cdigits+1>::value; }; template<> struct log8_i_t<0,0,0,false> { static const int value = 1; }; template<int n> struct log10_i_helper_t { static const int next = n / 10; }; template<int N, int n = N, int cdigits = 0, bool = less_than_t<0,n>::value> struct log10_i_t { static const int value = cdigits; }; template<int N, int n, int cdigits> struct log10_i_t<N,n,cdigits,true> { static const int value = log10_i_t<N,log10_i_helper_t<n>::next,cdigits+1>::value; }; template<> struct log10_i_t<0,0,0,false> { static const int value = 1; }; template<int n> struct log16_i_helper_t { static const int next = n >> 4; }; template<int N, int n = N, int cdigits = 0, bool = less_than_t<0,n>::value> struct log16_i_t { static const int value = cdigits; }; template<int N, int n, int cdigits> struct log16_i_t<N,n,cdigits,true> { static const int value = log16_i_t<N,log16_i_helper_t<n>::next,cdigits+1>::value; }; template<> struct log16_i_t<0,0,0,false> { static const int value = 1; }; template<int max_value, int n = 1, bool = less_than_or_equal_to_t<n,max_value>::value> struct print_log2_i_helper_t { static void print(){ } }; template<int max_value, int n> struct print_log2_i_helper_t<max_value,n,true> { static void print(){ debug_printf( "0x%08x は %d桁\n", n-1, log2_i_t<n-1>::value ); debug_printf( "0x%08x は %d桁\n", n, log2_i_t<n>::value ); debug_printf( "0x%08x は %d桁\n", n+1, log2_i_t<n+1>::value ); print_log2_i_helper_t<max_value,(!n?1:(n*2))>::print(); } }; template<int max_value, int n = 1, bool = less_than_or_equal_to_t<n,max_value>::value> struct print_log8_i_helper_t { static void print(){ } }; template<int max_value, int n> struct print_log8_i_helper_t<max_value,n,true> { static void print(){ debug_printf( "0%o は %d桁\n", n-1, log8_i_t<n-1>::value ); debug_printf( "0%o は %d桁\n", n, log8_i_t<n>::value ); debug_printf( "0%o は %d桁\n", n*4, log8_i_t<n*4>::value ); print_log8_i_helper_t<max_value,(!n?1:(n*8))>::print(); } }; template<int max_value, int n = 1, bool = less_than_or_equal_to_t<n,max_value>::value> struct print_log10_i_helper_t { static void print(){ } }; template<int max_value, int n> struct print_log10_i_helper_t<max_value,n,true> { static void print(){ debug_printf( "%d は %d桁\n", n-1, log10_i_t<n-1>::value ); debug_printf( "%d は %d桁\n", n, log10_i_t<n>::value ); debug_printf( "%d は %d桁\n", n*5, log10_i_t<n*5>::value ); print_log10_i_helper_t<max_value,(!n?1:(n*10))>::print(); } }; template<int max_value, int n = 1, bool = less_than_or_equal_to_t<n,max_value>::value> struct print_log16_i_helper_t { static void print(){ } }; template<int max_value, int n> struct print_log16_i_helper_t<max_value,n,true> { static void print(){ debug_printf( "0x%08x は %d桁\n", n-1, log16_i_t<n-1>::value ); debug_printf( "0x%08x は %d桁\n", n, log16_i_t<n>::value ); debug_printf( "0x%08x は %d桁\n", n*8, log16_i_t<n*8>::value ); print_log16_i_helper_t<max_value,(!n?1:(n*16))>::print(); } }; int main(){ print_log2_i_helper_t<0x10000>::print(); print_log8_i_helper_t<010000>::print(); print_log10_i_helper_t<10000>::print(); print_log16_i_helper_t<0x10000>::print(); return 0; }
テンプレートその2
桁数を数えることができるようになったらでは表示をしてみましょう
template<int lhs, int rhs> struct less_than_t { static const bool value = ( lhs < rhs ); }; template<int M,int _value = 1,bool = less_than_t<M,0>::value> struct pow10_i_t { static const int value = _value; }; template<int M,int _value> struct pow10_i_t<M,_value,false> { static const int value = 10 * pow10_i_t<M-1,_value*10>::value; }; template<int _value> struct pow10_i_t<0,_value,false> { static const int value = 1; }; template<> struct pow10_i_t<0,1,false> { static const int value = 1; }; template<int n> struct log10_i_helper_t { static const int next = n / 10; }; template<int N, int n = N, int cdigits = 0, bool = less_than_t<0,n>::value> struct log10_i_t { static const int value = cdigits; }; template<int N, int n, int cdigits> struct log10_i_t<N,n,cdigits,true> { static const int value = log10_i_t<N,log10_i_helper_t<n>::next,cdigits+1>::value; }; template<> struct log10_i_t<0,0,0,false> { static const int value = 1; }; template<int N,int n = 0, bool = less_than_t<n,0>::value,bool = less_than_t<n,sizeof( N )*8>::value> struct binary_digit_t { static const int value = ( N >> n ) & 1; }; template<int N,int n, bool is_negative> struct binary_digit_t<N,n,is_negative,false> { static const int value = 0; }; template<int N,int n,bool is_end> struct binary_digit_t<N,n,true,is_end> { static const int value = 0; }; template<int N,int n = 0, bool = less_than_t<n*3,0>::value,bool = less_than_t<n*3,sizeof( N )*8>::value> struct octal_digit_t { static const int value = ( N >> (n*3)) & 0x07; }; template<int N,int n, bool is_negative> struct octal_digit_t<N,n,is_negative,false> { static const int value = 0; }; template<int N,int n,bool is_end> struct octal_digit_t<N,n,true,is_end> { static const int value = 0; }; template<int N,int n = 0, bool = less_than_t<n,0>::value,bool = less_than_t<n,log10_i_t<N>::value>::value> struct decimal_digit_t { static const int value = ( N / pow10_i_t<n>::value ) % 10; }; template<int N,int n, bool is_negative> struct decimal_digit_t<N,n,is_negative,false> { static const int value = 0; }; template<int N,int n,bool is_end> struct decimal_digit_t<N,n,true,is_end> { static const int value = 0; }; template<int N,int n = 0, bool = less_than_t<n*4,0>::value,bool = less_than_t<n*4,sizeof( N )*8>::value> struct hexadecimal_digit_t { static const int value = ( N >> (n*4)) & 0x0f; }; template<int N,int n, bool is_negative> struct hexadecimal_digit_t<N,n,is_negative,false> { static const int value = 0; }; template<int N,int n,bool is_end> struct hexadecimal_digit_t<N,n,true,is_end> { static const int value = 0; }; template<int N,int length,int n = 0,int = binary_digit_t<N,length-n-1>::value,bool = less_than_t<n,length>::value> struct binary_print_t { static void print(){ debug_printf( "\n" ); } }; template<int N,int length,int n, int value> struct binary_print_t<N,length,n,value,true> { static void print(){ const char s[] = { '0' + value, 0 }; debug_printf( s ); binary_print_t<N,length,n+1>::print(); } }; template<int N,int length,int n = 0,int = octal_digit_t<N,length-n-1>::value,bool = less_than_t<n,length>::value> struct octal_print_t { static void print(){ debug_printf( "\n" ); } }; template<int N,int length,int n, int value> struct octal_print_t<N,length,n,value,true> { static void print(){ const char s[] = { '0' + value, 0 }; debug_printf( s ); octal_print_t<N,length,n+1>::print(); } }; template<int N,int length,int n = 0,int = decimal_digit_t<N,length-n-1>::value,bool = less_than_t<n,length>::value> struct decimal_print_t { static void print(){ debug_printf( "\n" ); } }; template<int N,int length,int n, int value> struct decimal_print_t<N,length,n,value,true> { static void print(){ const char s[] = { '0' + value, 0 }; debug_printf( s ); decimal_print_t<N,length,n+1>::print(); } }; template<int N,int length,int n = 0,int = hexadecimal_digit_t<N,length-n-1>::value,bool = less_than_t<n,length>::value> struct hexadecimal_print_t { static void print(){ debug_printf( "\n" ); } }; template<int N,int length,int n, int value> struct hexadecimal_print_t<N,length,n,value,true> { static void print(){ const char s[] = { ( value >= 0x0a ) ? ( 'A' + value - 0x0a ) : ( '0' + value ), 0 }; debug_printf( s ); hexadecimal_print_t<N,length,n+1>::print(); } }; int main(){ binary_print_t<0x1234,64>::print(); octal_print_t<01234,64>::print(); decimal_print_t<1234,64>::print(); hexadecimal_print_t<0x1234,64>::print(); return 0; }
テンプレートその3
共通のコードをまとめると
template<int lhs, int rhs> struct less_than_t { static const bool value = ( lhs < rhs ); }; template<int N,int M,int _value = 1,bool = less_than_t<M,0>::value> struct pow_i_t { static const int value = _value; }; template<int N,int M,int _value> struct pow_i_t<N,M,_value,false> { static const int value = N * pow_i_t<N,M-1,_value*N>::value; }; template<int N,int _value> struct pow_i_t<N,0,_value,false> { static const int value = 1; }; template<int M,int _value,bool is_end> struct pow_i_t<0,M,_value,is_end> { static const int value = 0; }; template<> struct pow_i_t<0,0,1,false> { static const int value = 1; }; template<int N,int M> struct log_i_helper_t { static const int next = M / N; }; template<int M> struct log_i_helper_t<0,M> { static const int next = 0; }; template<int N,int M,int m = M, int cdigits = 0, bool = less_than_t<0,m>::value> struct log_i_t { static const int value = cdigits; }; template<int N,int M,int m, int cdigits> struct log_i_t<N,M,m,cdigits,true> { static const int value = log_i_t<N,M,log_i_helper_t<N,m>::next,cdigits+1>::value; }; template<int N> struct log_i_t<N,0,0,0,false> { static const int value = 1; }; template<int N,int M,int m, bool = less_than_t<m,0>::value,bool = less_than_t<m,log_i_t<N,M>::value>::value> struct digit_t { static const int value = ( M / pow_i_t<N,m>::value ) % N; }; template<int N,int M,int m, bool is_negative> struct digit_t<N,M,m,is_negative,false> { static const int value = 0; }; template<int N,int M,int m,bool is_end> struct digit_t<N,M,m,true,is_end> { static const int value = 0; }; template<int n, bool = less_than_t<n,0x0a>::value> struct digit_char_t { static const char value = '0' + n; }; template<int n> struct digit_char_t<n,false> { static const char value = 'A' + n - 0x0a; }; template<int N,int M,int length,int m = 0,int = digit_t<N,M,length-m-1>::value,bool = less_than_t<m,length>::value> struct digits_print_t { static void print(){ debug_printf( "\n" ); } }; template<int N,int M,int length,int m, int value> struct digits_print_t<N,M,length,m,value,true> { static void print(){ const char s[] = { digit_char_t<value>::value, 0 }; debug_printf( s ); digits_print_t<N,M,length,m+1>::print(); } }; int main(){ digits_print_t<2,0x1234,64>::print(); digits_print_t<8,01234,64>::print(); digits_print_t<10,1234,64>::print(); digits_print_t<16,0x1234,64>::print(); return 0; }