かいせつ('A`) 投下用作成中

ソースコードでの回答ありがとうございます。
できれば説明がほしかったのですが、自分への試練と思い勉強します。

http://q.hatena.ne.jp/1207585413

がーん('A`)手段が目的にナッテタヨ

3のつく数字を判定する方法は関数 itoa(num,buf,10) (既に用意されている関数)用意されていないらしいで
10進数であると仮定して文字列に変換した後
strchr (こちらも用意されている関数)で文字 '3' をサーチすればいいと思います('A`)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char buf[99];
int ahoninarukazu = 3337;
itoa(ahoninarukazu ,buf,10); // buf に "3337" が入る
if( strchr(buf,'3') != NULL ) printf("あほになるー"); // '3' を含む


以下は投下したコードのコメント?つき

/* --------------------------------------------------------------------
    gcc で itoaを呼んでもまともにコール出来ない
    実際にないらしい。MSCがおまけでつけてるだけだったらしい
*/

/* --------------------------------------------------------------------
    ↓返値 変換された文字へのポインタ char* buf そのもの
    char *

       itoa( 
             ↓変換する数値
             const int num ,

             ↓変換された文字を格納するメモリへのポインタ
             char* buf,

             ↓無視します(stdlibにあるものは8,10,16などを指定しほげほげ進数に変換できます)
             const int ignore )
 */
    char *itoa( const int num ,char* buf, const int ignore )
    {
/* --------------------------------------------------------------------
        文字のテーブルです。
        ここから字引みたいなことやります。
        簡単化のためこんな文字列の感じで書かれていますが、

        これは
        // [要素] -------------  0    1    2    3    4    5    6    7    8    9   10  ----
        const char table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '\0' };
        のことです。

        数値 0など を 文字 '0'など に変換するときに使います。
 */
        const char table[] = "0123456789";

/* --------------------------------------------------------------------
        ポインタ *p はバッファ buf の先頭
        まずは自分のいる位置をポインタさんに教えます「buf の先頭」

        e.g.:
        num     =   12345
                    buf
                    p
        ZZZZZZZZZZZZXXXXXXXXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXXXXXXXXXXXXXXXZZZZZZZZZZZZZZZZZ....
 */
        char *p = buf;

/* --------------------------------------------------------------------
        num を持っておきたいためtmpを用意
 */
        int tmp;

/* --------------------------------------------------------------------
        数値の尻から判定していくので書き込みポインタを
        数値の桁数分すすめます

        e.g.:
        num     =   12345
                    buf
                    >>>>>p
        ZZZZZZZZZZZZXXXXXXXXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXXXXXXXXXXXXXXXZZZZZZZZZZZZZZZZZ....
 */
        for(tmp=num;tmp>0;tmp /= 10) *p++;

/* --------------------------------------------------------------------
        文字の終端は\0 である
        これがないと表示するときにバッファオーバ

        e.g.:
        num     =   12345
                    >>>>>p
                    buf  |
        ZZZZZZZZZZZZXXXXX0XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXXXX"

        注意: \0 を 0として表示してます
 */
        *p='\0';

/* --------------------------------------------------------------------
        数値の尻(一桁目)から数値を判定していく

        1. tmp%10:
        tmp%10 で一番下桁めの数 がわかる 0 1 2 3 4 5 6 7 8 9

        2. table[tmp%10]: table から文字を得る
        tmp%10 が0 のとき  table[0] = '0'
        tmp%10 が1 のとき  table[1] = '1'
        tmp%10 が2 のとき  table[2] = '2'
        tmp%10 が3 のとき  table[3] = '3'
        tmp%10 が4 のとき  table[4] = '4'
        tmp%10 が5 のとき  table[5] = '5'
        tmp%10 が6 のとき  table[6] = '6'
        tmp%10 が7 のとき  table[7] = '7'
        tmp%10 が8 のとき  table[8] = '8'
        tmp%10 が9 のとき  table[9] = '9'

        3. *--p=
        pを一つ前にもってく
        ポインタ*p に ↑で得た文字を突っ込んで

        4. tmp /= 10
        で次の桁を処理する

        というのを
        最後の桁 tmp>0になるまで繰り返す


        e.g.:
        num     =   12345
                    >>>>>p
                    buf  
        ZZZZZZZZZZZZXXXXX0XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXXXX"

        (--p)
        num     =   12345
                    >>>>p
                    b   |
        ZZZZZZZZZZZZXXXXX0XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXXXX"

        (*p = table[tmp%10])
        num     =   12345
        tmp     =   12345
        tmp % 10=       5
        table[5]=      '5'
                    >>>>p
                    b   |
        ZZZZZZZZZZZZXXXX50XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXXX5"

        (--p)
        num     =   12345
                    >>>p
                    b  |
        ZZZZZZZZZZZZXXXX50XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXXX5"


        (*p = table[tmp%10])
        num     =   12345
        tmp     =   1234
        tmp % 10=      4
        table[4]=     '4'
                    >>>p
                    b  |
        ZZZZZZZZZZZZXXX450XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXX45"

        (--p)
        num     =   12345
                    >>p
                    b |
        ZZZZZZZZZZZZXXX450XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XXX45"


        (*p = table[tmp%10])
        num     =   12345
        tmp     =   123
        tmp % 10=     3
        table[3]=    '3'
                    >>p
                    b |
        ZZZZZZZZZZZZXX3450XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XX345"

        (--p)
        num     =   12345
                    >p
                    b|
        ZZZZZZZZZZZZXX3450XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "XX345"


        (*p = table[tmp%10])
        num     =   12345
        tmp     =   12
        tmp % 10=    2
        table[2]=   '2'
                    >p
                    b|
        ZZZZZZZZZZZZX23450XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "X2345"

        (--p)
        num     =   12345
                    p
                    |
        ZZZZZZZZZZZZX23450XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "X2345"


        (*p = table[tmp%10])
        num     =   12345
        tmp     =   1
        tmp % 10=   1
        table[3]=  '1'
                    p
                    |
        ZZZZZZZZZZZZ123450XXXXXXXXXXZZZZZZZZZZZZZZZZZ
        buff     = "12345"

*/
        for(tmp=num;tmp>0;tmp /= 10) *--p=table[tmp%10];

/* --------------------------------------------------------------------
        バッファ buf を返して 数値から文字列変換したものを返す 
*/
        return buf;
    }


/* --------------------------------------------------------------------
    ここからのコメントはネタです。
 */
    int main()
    {
/* --------------------------------------------------------------------
    buf が 99 なのは、 99桁もある数値で実行しないであろうという
    希望からこのような実装にした。

    本音はキーボードを打つ回数が少なく それなりに数値としては大きい値のため採用した
    e.g.:
      1 文字 -           9
      2 文字 -          99
      3 文字 -   0xF   (16)
      3 文字 -         999
      4 文字 -   0xFF (255)
      4 文字 -        9999

 */
    char buf[99];
/* --------------------------------------------------------------------
    要求のある数値の要件は
    整数であることのみであるため int を採用した
 */
    int aho;
/* --------------------------------------------------------------------
    1 から 50未満 までを変数 aho にいれて 繰り返す
 */
    for(aho=1; aho<50; aho++){
/* --------------------------------------------------------------------
    3 の倍数 か 5の倍数 か 3がつく数 とき 数値を表示
     || (論理or) により どれか一つが 0以外なら if(){ .... の中身を実行する

    e.g.:
      1 || 0 || 0 => 1

    0==0 は正しいので => 0以外の数値が返る
    1==0 は違うので   => 0が返る

    aho%3 は 3で割ったときの余り (0か3の倍数のとき答えは 0)
    aho%3==0 (3の倍数のとき)  0以外が返る
   
    itoa(aho,buf,10) は aho に入っている数値を文字列に変換する関数
    buf は おまじない 場所 住み家
    10 は 10進数を表す (がここでは無視してるのでなんでもいい
    itoa から返ってくるのはaho に入っている数値を文字列にしたもの(bufのポインタ)返る

    strchr は 文字列から 1文字を捜す
    strchr( 文字列, '3' ) == NULL 以外のとき 文字列に'3'が含まれている
    ( '3' が含まれている文字列の位置をポインタとして返す)
    ないとき != 0 としている
    (正しくは==NULL しないといけない 通例的に NULL == 0 だと仮定してしまっていたが危険であった)
 */
    if( aho%3==0 || aho%5==0 ||
    strchr(itoa(aho,buf,10),'3')) printf("%d\n",aho);

    }
/* --------------------------------------------------------------------
  0 をなにげに返しているのは プログラムが成功したという希望から
 */
    return 0;
    }

/* --------------------------------------------------------------------
 */

itoa の使い方説明終わり。
んでこれを最適化してみます。
まず文字に変換する処理は遅くなるので消します
消した関数が以下の char *search_3( const int num )です
http://codepad.org/2epZT4W8

#define TRUE  1
#define FALSE 0

char *search_3( const int num )
{
  int tmp;
  for(tmp=num;tmp>0;tmp /= 10)
    if( tmp%10 == 3 )
      return TRUE;

  return FALSE;
}

int main()
{
  int aho;

  for(aho=1; aho<50; aho++){
    if( aho%3==0 || aho%5==0 ||
        search_3(aho) ) printf("%d\n",aho);
  }
  return 0;
}

他のitoa はどんなのだろう...

ライセンス不明 よい
16進のときにつぶしが利かない

X/OPEN 文字テーブル使用

GPL さすがGPL これはひどい
switch内 case〜break文 #defineしてる....
もっと素直にかけないものか...

GPL さすがGPL 問題外...
swapの仕方は悪くない
char s[]、char *sなら暗示的に \0 と考えていいと思うので
番人付けてstrlen(s)いらんはずだが...

GPL 桁数決め打ち(__int32や __int64なんて高々 4294967295や
9223372036854775807 なんだし、決め打ちでいいな..)

というわけで作成

/* keta_v2 */
int map_keta[] = {
                         0,
                        10,
                       100,
                      1000,
                     10000,
                    100000,
                   1000000,
                  10000000,
                 100000000,
                1000000000,
    /*          4294967295 */
               10000000000,
              100000000000,
             1000000000000,
            10000000000000,
           100000000000000,
          1000000000000000,
         10000000000000000,
        100000000000000000,
       1000000000000000000,
    /* 9223372036854775807 */
    -1,
};

int keta_v1( const int num )
{
  int tmp, n = 0;
  for(tmp=num;tmp>0;tmp /= 10) n++;

  return n;
}

int keta_v2( const int num )
{
  int tmp, n = 0;
  for(n=0;map_keta[n] != -1;n++) if(map_keta[n] > num) break;

  return n;
}

int main()
{
  int i;

  for(i=0; i<50; i++)
    printf("%d: %d\n",i*i*i , keta_v2(i*i*i));
  return 0;
}

> time keta_v1.c
0.000u 0.006s 0:00.00 0.0% 0+0k 0+0io 0pf+0w

> time keta_v2.c
0.000u 0.003s 0:00.00 0.0% 0+0k 0+0io 0pf+0w

桁計算ルーチンが50% 速くなったコトがわかる

const int map_keta[] = {
                         3,
                        30,
                       300,
                      3000,
                     30000,
                    300000,
                   3000000,
                  30000000,
                 300000000,
                3000000000,
    /*          4294967295 */
    -1,
};

int search_3_v1( const int num )
{
  int tmp, n = 0;

  for(tmp=num;tmp>0; tmp /= 10) {
    if( tmp % 10 == 3 ) return num;
  }
  return 0;
}

/* 1 〜 29 までは 一桁目しか見ない版 */
int search_3_v2( const int num )
{
  int tmp, n = 0;

  for(n=0, tmp=num;map_keta[n] != -1 || tmp>0;n++, tmp /= 10) {
    if(map_keta[n] > num) break;
/*    printf( "\t%d = %d = %d\n", num , map_keta[n], tmp % 10) ;*/
    if( tmp % 10 == 3 ) return num;
  }
  return 0;
}

int main()
{
  int i;

  for(i=0; i<50; i++)
    printf("%d: %d\n",i , search_3_v2(i));
  return 0;
}
  • 0〜49

> time ./search_3_v1
0.000u 0.006s 0:00.00 0.0% 0+0k 0+0io 0pf+0w

> time ./search_3_v2
0.000u 0.006s 0:00.00 0.0% 0+0k 0+0io 0pf+0w

  • 0〜4999

> time ./search_3_v1
0.084u 0.124s 0:00.24 83.3% 6+3014k 0+0io 0pf+0w

> time ./search_3_v2
0.084u 0.110s 0:00.22 86.3% 6+2974k 0+0io 0pf+0w


4999回ループならsearch_3_v2 の方が2秒程度速い





3 < A
13
23
30
31
32
33
34
35
36
37
38
39
43
53
63
73
83
93 < B

103 < 1A
113
123
130
131
132
133
134
135
136
137
138
139
143
153
163
173
183
193 < 1B

203 < 2A
213
:
283
293 < 2B

300 < 3X
:
399 < 3X

403 < 4A
413
:
483
493 < 4B

403 < 4A
413
:
483
493 < 4B

503 < 5A
513
:
583
593 < 5B


603 < 6A
613
:
683
693 < 6B


703 < 6A
713
:
783
793 < 7B

803 < 7A
813
:
883
893 < 8B

903 < 9A
913
:
983
993 < 9B

1003 < 10A
:
1093 < 10B


1,2桁目が A〜Bパターン以外の数値で3が憑くのは

387
1307
2309...

しかし、3, 13, 23, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 53, 63, 73, 83, 93,のいづれかがかかる。

int map_3[] = { 3, 13, 23, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 43, 53, 63, 73, 83, 93, 0};
int search_3_v3( const int num )
{
  int tmp, n = 0;

  for(tmp=num;tmp>0; tmp /= 100) {

    for(n=0;;n++) {
      if(map_3[n] == 0) break;
      if(map_3[n] == tmp % 100) return num;
//      printf( "\t%d = %d = %d\n", num , map_3[n], tmp % 100);
    }
  }
  return 0;
}

int main()
{
  int i;

  for(i=0; i<5000; i++)
    printf("%d: %d\n",i , search_3_v3(i));
  return 0;
}
  • 0〜4999

> time ./search_3_v1
0.084u 0.124s 0:00.24 83.3% 6+3014k 0+0io 0pf+0w

> time ./search_3_v2
0.084u 0.110s 0:00.22 86.3% 6+2974k 0+0io 0pf+0w

> time ./search_3_v3
0.085u 0.106s 0:00.22 81.8% 6+2826k 0+0io 0pf+0w

v2 よりも 4ミリ秒速くなった。
この場合 v1の派生だから、v1 と比べるベきだが

> ./1 > 1out.txt
> ./2 > 2out.txt
> mv a.out 3
> ./3 >3out.txt
> diff 1out.txt 2out.txt
> diff 3out.txt 2out.txt


v2とv3の対策をくっつけた v4

const int map_keta[] = {
                         3,
                        30,
                       300,
                      3000,
                     30000,
                    300000,
                   3000000,
                  30000000,
                 300000000,
                3000000000,
    /*          4294967295 */
    -1,
};

int map_3[] = { 3, 13, 23,
                30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
                43, 53, 63, 73, 83, 93, 0
};

int search_3_v4( const int num )
{
  int tmp, n, m;

  for(n=0, tmp=num;map_keta[n] != -1 || tmp>0;n++, tmp /= 100) {
    if(map_keta[n] > num) break;
/*    printf( "\t%d = %d = %d\n", num , map_keta[n], tmp % 100) ;*/
    for(m=0;;m++) {
      if(map_3[m] == 0) break;
      if(map_3[m] == tmp % 100) return num;
//      printf( "\t%d = %d = %d\n", num , map_3[m], tmp % 100);
    }
  }

  return 0;
}

int main()
{
  int i;

  for(i=0; i<5000; i++)
    printf("%d: %d\n",i , search_3_v4(i));
  return 0;
}
  • 0〜4999

> time ./search_3_v1
0.084u 0.124s 0:00.24 83.3% 6+3014k 0+0io 0pf+0w

> time ./search_3_v2
0.084u 0.110s 0:00.22 86.3% 6+2974k 0+0io 0pf+0w

> time ./search_3_v3
0.085u 0.106s 0:00.22 81.8% 6+2826k 0+0io 0pf+0w

> time ./search_3_v4
0.059u 0.131s 0:00.21 85.7% 22+3019k 0+0io 0pf+0w

1秒速くなった気がする

オチ

> time ./search_3_v1 > /dev/null
0.000u 0.005s 0:00.00 0.0%      0+0k 0+0io 0pf+0w

> time ./search_3_v2 > /dev/null
0.000u 0.005s 0:00.00 0.0%      0+0k 0+0io 0pf+0w

> time ./search_3_v3 > /dev/null
0.000u 0.004s 0:00.00 0.0%      0+0k 0+0io 0pf+0w

> time ./search_3_v4 > /dev/null
0.000u 0.006s 0:00.00 0.0%      0+0k 0+0io 0pf+0w

printしなければ速い




ps: table[2]が3になってたの修正、tmp , tmp%10 ウォッチ式追加。 インデント修正