再挑戦

先日のスクリプトを C でリライトしてみた。

いやはや C なんて何年振りだろう。

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>

#define MAX_LENGTH 9
#define MIN_LENGTH 7
#define NO_MORE_REPEAT 2

void generate(char[]);
int is_over_repeated(char[], int);
void print_buff(char[]);
void print_time(time_t);

int count = 0;
int logs = 0;
FILE *fp;
clock_t all_start_time;
clock_t sub_start_time;

int main(int argc, char *argv[]) {
  char buff[MAX_LENGTH + 1] = { '\0' };

  all_start_time = clock();
  sub_start_time = all_start_time;
  generate(buff);
  print_time(all_start_time);
  fclose(fp);
  return 0;
}

void generate(char buff[]) {
  int length = strlen(buff);
  int new_length = length + 1;
  char new_buff[MAX_LENGTH + 1] = { '\0' };
  char c;

  if (length >= MAX_LENGTH) return;
  for (c = 'a'; c <= 'z'; c++) {
    strcpy(new_buff, buff);
    new_buff[length] = c;
    if (is_over_repeated(new_buff, length)) continue;
    if (new_length >= MIN_LENGTH) {
      print_buff(new_buff);
    }
    generate(new_buff);
  }
}

int is_over_repeated(char buff[], int length) {
  if (length < NO_MORE_REPEAT) return 0;
  if (buff[length] != buff[length - 1]) return 0;
  if (buff[length] != buff[length - 2]) return 0;
  return 1;
}

void print_buff(char buff[]) {
  char filename[16];
  if (count % 100000000 == 0) {
    if (fp) {
      print_time(sub_start_time);
      fclose(fp);
    }
    sub_start_time = clock();
    sprintf(filename, "result%03d.log", ++logs);
    fp = fopen(filename, "w");
  }
  fprintf(fp, "%10d: %s\n", ++count, buff);
}

void print_time(time_t start_time) {
  double sec = (double)(clock() - start_time) / CLOCKS_PER_SEC;
  int hour = (int)sec / (60 * 60);
  int min = ((int)sec % (60 * 60)) / 60;
  double msec;

  sec = fmod(sec, 60.0);
  msec = fmod(sec, 1.0) * 100;
  fprintf(fp, "\n所要時間:");
  if (hour > 0) fprintf(fp, " %d 時間", hour);
  if (min > 0) fprintf(fp, " %02d 分", min);
  fprintf(fp, " %02d%02d\n", (int)sec, (int)msec);
}
$ gcc lama.c -o lama -D_FILE_OFFSET_BITS=64 -lm ↵
./lama ↵

我が家の環境だと「-D_FILE_OFFSET_BITS=64」をつけないと「file size limit exceeded」で落ちる。


それにしても。当たり前の話だが C は Ruby よりも段違いに速い。Ruby が一千万件出力するのに 6 分半かかるのに対して、C は高々 1 分 20 秒程度で一億件出力である。


書きやすさで言えばもちろん Ruby に軍配があがるのだが、久々に C の威力を実感した思いだ。