10 億回のループ (awka 版)

programming_language_awk.jpg

10 億回のループでは awk は惜敗してしましましたが、awk は比較的 C 言語に近い構文を持ち、「プログラミング言語 AWK」の中でも awk から C 言語への変換が触れられています。 この際の実行速度を補うため awka という awk から C 言語へのコンバーターがあります。 ただし、awka のプロジェクトはほとんど活動を行っていませんので、今のうちにダウンロードしておいた方が良いかもしれません。

使ったコードは以下のとおりです。

#! /usr/bin/gawk -f
# 1_billion_calculation.awk

BEGIN {
    if (ARGC >= 2) {
        sum = 0;

        n = ARGV[1];                # n := コマンドの第一引数
        for (i = 0; i < n; ++i)     # 0 から n-1 まで足し算
            sum += i;
        printf("%d\n", sum);
    }
}

さて、awka のインストールですが、以下のようにして行うことができます。

$ tar -xzvf awka-0.7.5.tar.gz
$ cd awka-0.7.5
$ ./configure --prefix=/usr/local
$ make
$ sudo make install

これで awka が使えるようになっているはずです。 awka-0.7.5 のページの最後には awk2c.sh というスクリプトがありますので、これを利用して変換すると簡単に実行ファイルを作成することができます。

$ awk2c.sh 1_billion_calculation
$ time ./1_billion_calculation 1000000000
-2147483648
./1_billion_calculation 1000000000  19.46s user 0.03s system 99% cpu 19.545 total

結果から言えば、32 bit の演算になってしまうため正確な解答は得られていませんが、前回の結果と比較して大幅にループの時間を短縮することができました。 ただし、C 言語には及ばない結果となりました。 awka で生成された C のコードがそんなに最適化されているわけではないことや awk のように型のない LL からの適切な型変換の問題もあるのではないでしょうか。

ちなみに変換された C のコードは以下のとおり。

/* This file generated by AWKA */

#include <libawka.h>
#include <setjmp.h>

int _split_req = 0, _split_max = INT_MAX;

extern int _dol0_used;
extern char _dol0_only;
extern char _env_used;
extern int _max_base_gc, _max_fn_gc;
extern struct awka_fn_struct *_awkafn;
jmp_buf context;
a_VAR *sum_awk = NULL;
a_VAR *n_awk = NULL;
a_VAR *i_awk = NULL;

struct gvar_struct *_gvar;

a_VAR **_lvar;
a_VAR *_litd0_awka=NULL, *_litd1_awka=NULL, *_litd2_awka=NULL;
a_VAR *_lits0_awka=NULL;
void BEGIN();

void
BEGIN()
{
  if ((awka_var2dblcmp(a_bivar[a_ARGC], 2) >= 0))
  {
    awka_vardblset(sum_awk, 0);
    awka_varcpy(n_awk, awka_arraysearch1(a_bivar[a_ARGV], _litd2_awka, a_ARR_CREATE, 0));
    awka_vardblset(i_awk, 0);
    while ((awka_dbl2varcmp(i_awk->dval, n_awk) < 0))
    {
      awka_setd(sum_awk) += i_awk->dval;
      awka_pri(i_awk);
    }
    awka_printf(NULL, 0, 0, awka_vararg(a_TEMP, _lits0_awka, sum_awk, NULL));
  }
  awka_exit(0);

}



int
main(int argc, char *argv[])
{
  _max_base_gc = 3;
  _max_fn_gc = 2;

  awka_varinit(sum_awk);
  awka_varinit(n_awk);
  awka_varinit(i_awk);

  awka_varinit(_litd0_awka); awka_setd(_litd0_awka) = 2;
  awka_varinit(_litd1_awka); awka_setd(_litd1_awka) = 0;
  awka_varinit(_litd2_awka); awka_setd(_litd2_awka) = 1;
  awka_varinit(_lits0_awka); awka_strcpy(_lits0_awka, "%d\n");

  if (!_lvar) {
    malloc( &_lvar, 5 * sizeof(a_VAR *) );
    _lvar[0] = _litd0_awka;
    _lvar[1] = _litd1_awka;
    _lvar[2] = _litd2_awka;
    _lvar[3] = _lits0_awka;
    _lvar[4] = NULL;
  }

  malloc( &_gvar, 4 * sizeof(struct gvar_struct) );
  awka_initgvar(0, "sum_awk", sum_awk);
  awka_initgvar(1, "n_awk", n_awk);
  awka_initgvar(2, "i_awk", i_awk);
  _gvar[3].name = NULL;
  _gvar[3].var  = NULL;

  malloc( &_awkafn, 1 * sizeof(struct awka_fn_struct) );
  _awkafn[0].name = NULL;
  _awkafn[0].fn   = NULL;

  awka_init(argc, argv, "0.7.5", "12 July 2001");

  _dol0_only = 1;

  BEGIN();

  free(_litd0_awka);
  free(_litd1_awka);
  free(_litd2_awka);
  free(_lits0_awka->ptr); free(_lits0_awka);

  awka_exit(0);
}

ちょっと、それはないかな。(w

tag_nawk.pngtag_nawk.pngtag_nawk.pngtag_nawk.png