計算機の学習メモ

この想像しがたい状況が成立する過程を、以下に詳述する。

数学パズル問3

プログラマ脳を鍛える数学パズル」の問3をC言語で実装。
今回は実装的にはなんら問題なく、算出された答えに意味があるのだろう。

問3:1〜100の番号が書かれた100枚のカードが裏返しで並べられている。
n番目のカードからn-1枚おきにカードを裏返し、どのカードの向きも変わらなくなるまで
続けたとき、裏向きになっているカードの番号を全て求めよ。

解: 1, 4,9,16,25,36,49,64,81,100
  (1〜10の平方数)


#include <stdio.h>
#define FRONT 1
#define BACK  0

int main(void){
  int array[101] = {BACK};
  int card_status;

  /*2番目のカードから始めるので、i = 2*/
  for(int i = 2; i <= 100; i++){
    /*配列の番号をカードの番号とするので、j = 1*/
    for(int j = 1;j <= 100; j++){
      /*100番目のカードを越えたら次のターンへ*/
      if(i * j <= 100){
        /*カードの向きを表裏逆にする*/
        card_status = array[i * j];
        if(card_status == FRONT){
          array[i * j] = BACK;
        } else {
          array[i * j] = FRONT;
        }
      } else {
        break;
      }
    }
  }


  for(int i = 1; i <= 100; i++){
    if(array[i] == BACK){
      printf("result : %d\n", i);
    }
  }
  return 0;
}

数学パズル問2

プログラマ脳を鍛える数学パズル」の問2をまたまたC言語で実装。
答えを見たところ、C言語では逆ポーランド記法で実装すると書いてあったが、evalと同じく
ふつうpopenとかコンソールでやる方が簡単だと思う・・・。
本には逆ポーランド記法での解法について「初心者向けの練習問題でよく見かける」とあるが、
逆ポーランド記法を実装し始めるのは初心者じゃない気が・・・。K&Rの影響?

ネストが深いが、まあ、一回だけの実装なので勘弁。

問21000〜9999の数値で各桁の間に四則演算子を入れ計算した結果、
元の数の桁を逆から並べた数字と同じになるものは何か。
演算子を入れない場所があっても構わないが、最低でも1つは入れるものとする。

解答:5931(5 * 9 * 31 = 1395)

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

#define MAX_NUM_LEN 20

int judge_palindrome(int,int);

int main(int argc,char *argv[]){
  FILE *fp;
  char buf2[256];
  char ope[] = {'+', '*', '-', '/', ' '};
  int in_num;

  for(int i = 1000; i < 9999; i++){
    printf("%d\n",i);
    char c_tmp[5] = {'\0'};
    char cmd[256] = {'\0'};
    char buf[256];
    sprintf(c_tmp, "%d", i);

    /*全演算子を試行*/
    for(int j = 0; j < 5; j ++){
      for(int k = 0; k < 5; k++){
        for(int l = 0; l < 5; l++){
          /*1つ以上の演算子を含むので、全て空白の時は除外*/
          if( j == 4 && k == 4 && l == 4){
          }
          else{
            char *find_pos;
            /*コマンド生成*/
            sprintf(cmd, "echo \"%c %c %c %c %c %c %c\" | bc",c_tmp[0],ope[j],c_tmp[1],ope[k],c_tmp[2],ope[l],c_tmp[3]);
            /*ゼロの除算を除く*/
            if (strstr(cmd, "/ 0") == NULL){
              /*空白を詰めて数値にする*/
              find_pos = strstr(cmd, "   ");
              if( find_pos == NULL){
              }
              else {
                char tmp[256];
                char *p;
                strcpy(buf,cmd);
                while ((p = strstr(buf, "   ")) != NULL) {
                  *p = '\0';
                  p += strlen("   ");
                  strcpy(tmp, p);
                  strcat(buf, "");
                  strcat(buf, tmp);
                }
              }
              char *cmdline = buf;
              /*コマンド実行*/
              if((fp = popen(cmdline, "r")) == NULL){
                perror("error");
                exit(1);
              }
              fgets(buf2, sizeof(buf2), fp);
              in_num = atoi(buf2);
              if(in_num == 0){
              }
              else{
                /*回文判定*/
                if(judge_palindrome(in_num,i) == 0){
                  printf("resutl : %d\n", i);
                  exit(0);
                }
              }
              pclose(fp);
            }
          }
        }
      }
    }
  }
  return 0;
}

/*回文判定*/
int judge_palindrome(int in_num, int org_in_num){
  int num_len = 0;
  int tmp_len = in_num;
  int flag = 0;
  char rev_num[MAX_NUM_LEN] = {'\0'};
  char org_num[MAX_NUM_LEN] = {'\0'};
  int count = 0;

  sprintf(org_num, "%d", in_num);
  while(tmp_len != 0){
    tmp_len = tmp_len / 10;
    num_len++;
  }
  while(in_num != 0){
    int tmp;
    char c_tmp[MAX_NUM_LEN] = {'\0'};
    count++;
    tmp = in_num % 10;
    in_num = in_num / 10;
    sprintf(c_tmp, "%d", tmp);
    strcat(rev_num,c_tmp);
  }
  sprintf(org_num, "%d", org_in_num);
  flag = strcmp(rev_num,org_num);
  return flag;
}

数学パズル問1

プログラマ脳を鍛える数学パズル」という本を買った。
書籍ではRubyPHPでの実装が多いので、C言語で実装してみた。
C言語Rubyのように一発で変換できる関数がないので大変だった・・・。

問1:10進数・8進数・2進数のいずれで表現しても回文数となるうち、
10進数で10以上の最小値を求めなさい。

解:585

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

#define START_NUM 10
#define END_NUM 9999
#define MAX_NUM_LEN 20

int decimal_to_nary(int, int);
int judge_palindrome(int);

int main(void){
  int binary_flag;  /*2進数の回文判定結果*/
  int octal_flag;   /*8進数の回文判定結果*/
  int decimal_flag; /*10進数の回文判定結果*/

  for(int i = START_NUM; i < END_NUM; i++){
    binary_flag = judge_palindrome(decimal_to_nary(i,2));
    octal_flag = judge_palindrome(decimal_to_nary(i,8));
    decimal_flag = judge_palindrome(i);
    if (binary_flag == 0 && octal_flag == 0 && decimal_flag == 0){
      puts("ok\n");
      printf("result : %d\n",i);
      exit(0);
    } else{
      puts("ng\n");
    }
  }
  return 0;
}

/*n進法*/
int decimal_to_nary(int in_num, int fund_num){
  int rem_num = 0;
  int quot_num;
  int res = 0;
  int count = 1;

  quot_num = in_num;
  while(quot_num != 0){
    rem_num = quot_num % fund_num;
    quot_num = quot_num / fund_num;
    res = res + rem_num * count;
    count = count * 10;
  }

  return res;
}

/*回文判定*/
int judge_palindrome(int in_num){
  int num_len = 0;
  int tmp_len = in_num;
  int flag = 0;
  char rev_num[MAX_NUM_LEN] = {'\0'};
  char org_num[MAX_NUM_LEN] = {'\0'};
  int count = 0;

  sprintf(org_num, "%d", in_num);
  while(tmp_len != 0){
    tmp_len = tmp_len / 10;
    num_len++;
  }
  while(in_num != 0){
    int tmp;
    char c_tmp[MAX_NUM_LEN] = {'\0'};
    count++;
    tmp = in_num % 10;
    in_num = in_num / 10;
    sprintf(c_tmp, "%d", tmp);
    strcat(rev_num,c_tmp);
  }
  flag = strcmp(rev_num,org_num);
  printf("reverse number : %s\n",rev_num);
  printf("original number : %s\n", org_num);
  printf("cmp string : %d\n",flag);
  return flag;
}

最初にコードリーディングした際の参考リスト

レビュー対象は非公開だが、以下サイトを参考に読み進めた。

ポインタ虎の巻〜ダブルポインタ **argv の使い方

&つけが必要な変数の正体

変数を宣言したら初期化処理を行おう!

C言語システムコール-sigaction CapmNetwork

argc,argvは何の略 | C言語のTipsとサンプル | C入門 基本情報対策講座のcClip

コマンドライン引数の取得とgetopt

Big Sky :: ヘッダファイルだけでC++から使えるJSONパーサ「picojson」が凄い!

C 言語の基本的な質問: fgets

C言語関数リファレンス - sscanf(bufからの書式付き入力)

C言語におけるinclude文とgcc -Iオプションの関係 - Qiita

ファイル入出力

VB JSONのシリアライズ・デシリアライズ - シリアル化 逆シリアル化

Tech Tips: 知ってると便利なSTL(2) pair

linuxカーネル参考サイトまとめ

Linuxカーネルを読む上で参考になりそうなサイトを列挙。
読み物も含む。

(3/3)はじめてのカーネル・ソース - 第4回 カーネルが構造体を好むワケ:ITpro

記者の眼 - 誰も読まないOSのソース・コード:ITpro

今後読みたい本のまとめ

各サイトで良書が紹介されている。
今後機会があれば参考にして読んでみたい。

第1回 みなさんの飛躍のきっかけとなった本は? :イマドキのエンジニアの勉強事情|gihyo.jp … 技術評論社

プログラミングのスキルを鍛える10の方法 | TRIVIAL TECHNOLOGIES 4 @ats のイクメン日記

最初の壁,デバッグ完全解説 - わさっき

Linux/gccプログラミングをこれから始める人にお勧めしたい本 - Akio’s Log

macのvirtualboxで開発作成

macvirtualboxLinux用の開発環境を整備するまとめ。

1,Linuxのインストール
以下を参照してvirtualboxCentOSをインストール
VirtualBoxにCentOS7をインストールしてみる - yk5656 diary

2,ネットワークの有効化
標準ではCUIになる。
デフォルトではネットワークがoffになっているので、yumが使えない。
そこで、以下のとおりネットワークを有効化する。
[CentOS] ネットワークを有効化する方法(CUI) | SEECK.JP サポート

3,GNOMEの導入
yumを使ってGNOMEをインストールする。
MinimalインストールしたCentOS7にGNOMEを入れてみる - yk5656 diary

4,EMACSのインストール
以下コマンドでemacsをインストール
sudo yum install emacs

(参考)
emacs のインストール(yum, ソース) | 本日も乙

5,gccのインストール
以下コマンドでgccをインストール
yum install gcc

(参考)
[CentOS] yum を使って gcc をインストールする。 | 僕とガジェット

以上で完了。
無事開発環境が整いました。