今日やったことのまとめ

Vimメモ

基本vimperatorと同じ(当たり前
:help user-manualを読む
Ctrl-]でリンク先を開いて、Ctrl-oでたまに戻りつつ読んでいく
:e ./でカレントディレクトリを開くとエクスプローラみたいな感じ。ファイル名にフォーカスしてRでリネーム。tでtabopen、iで詳細表示(作成日時とかわかる)。
:vnewで垂直フレームとして開ける。

Normal mode
xで削除 iで挿入 aで追加 dwで単語削除, ddで行削除 uはundo(「元に戻す」)

Ctrl-d,uで半画面down,upスクロールが便利

Vimperatorのエントリも多いBig skyさんとこにTipsがあった
はてなグループVimとか
↓ここが単一エントリではたぶん一番詳しい
vimで効率的にコードを書くための小技 - bonar note

C以外でやりたいこと

テキスト処理→正規表現覚える
ゲノム解析の初歩はテキスト処理だから。
ハミング距離とかレーベンシュタイン距離とか出せるようにしたい
とりあえず、はじRubyを買ったのでp.68の正規表現の表を眺めて今日はおしまい

メタキャラクタとかCの文字列処理で実装してみたら覚えそう
(…普通に使って覚えてもいいんだけどww

119日目 C引数付き置換マクロで作る、擬似timesメソッド(Ruby)

Rubyのtimesメソッドがうらやましくなってマクロで遊んでみました。
Ruby

    3.times {
        puts "hello"
}

C

#include <stdio.h>

#define times(N) for(num = 0; num < N; num++)

int main()
{
    int num;

    times(3)
        printf("hello\n");
    return 0;
}


次に、times(num, 3)と書けば、numを0から1ずつ増やしながら、3になるまで(つまり3回)以下の行を実行するようにしました。
Ruby

3.times {|num|           /* numを0から1ずつ増やしながら */
    puts "num = #{num}"  /* 3になるまで実行する         */ 
}

C

#include <stdio.h>

#define times(M, N) for(M = 0; M < N; M++) 

int main()
{
    int num;

    times(num, 3)         /* numを0から1ずつ増やしながら */
        printf("num = %d\n", num);
    return 0;
}

で、これを使えば回数のみの多重ループの可読性が上がるはず。
くどいようだがループの回数アスタリスク表示をまたやりましたよ。

#include <stdio.h>

#define times(M, N) for(M = 0; M < N; M++) 

int main()
{
    int ast, num;

    times(num, 10) {         /* numを0から1ずつ増やしつつ */
	printf("%d\t", num);     /*  num == 10 になるまで実行 */
	times(ast, num)      /* astを0から1ずつ増やしなつつ */
	    printf("*");         /*  ast == num になるまで実行 */
	printf("\n");
    }
    return 0;
}

マクロ置換前

#include <stdio.h>

int main()
{
    int num, ast;

    for (num = 0; num < 10; num++){    // numを0から1ずつ増やしつつ
        printf("%d\t", num);             // num == 10 になるまで実行
        for (ast = 0; ast < num; ast++)  // astを0から1ずつ増やしなつつ
            printf("*");                    // ast == num になるまで実行
        printf("\n");
    }
    return 0;
}

一度この置換を経験してみると、2種類のfor文の違いがはっきりしていいかも?

参考:102日目 これは遅延評価勉強法なのか - id:wakutekaのプログラミングメモ
ループの回数だけアスタリスクを表示 - yaottiの日記 - ハチロク世代
36日目 K&amp;RのExerciseをやってみた - id:wakutekaのプログラミングメモ


ちなみにRubyだとこうなるかな。

10.times {|num| 
    print "#{num} "
    num.times {|ast|
	print "*"
    }
    print "\n"
}

動作確認はcodepad.orgでやりました。
codepad



追記

10.times { |num| puts "#{num} #{'*' * num}" }
SKSの申し子 on Twitter: "@wakuteka 今更だけど,「ループの回数だけアスタリスクを表示」はこんな感じで行けるかも(Ruby). 10.times { |num| puts "#{num} #{'*' * num}" }"

rubyだとこれでおkだと教えていただきました。

113日目 等差数列の和

まず末項を計算させる

#include <stdio.h> /* arithmetic progression (print last term)*/
#include <stdlib.h>

int main(int argc, char *argv[])
{
    int i, sum;
    int first = atoi(argv[1]), diff = atoi(argv[2]), num = atoi(argv[3]);

    for (i = 1, sum = first; i < num; i++)
        sum += diff;
    (num >= 1) ? (printf("a(%d) = %d", num, sum)) : (printf("error!"));
    return 0;
}

んで関数化します。

配列を表示して挙動を確認

#include <stdio.h> /* arithmetic progression (print array)*/
#include <stdlib.h>

int func(int first, int diff, int num)
{
    int i, sum;
    for (i = 1, sum = first; i < num; i++)
        sum += diff;
    return sum;
}

int main(int argc, char *argv[])
{
    int i, sum, first = atoi(argv[1]), diff = atoi(argv[2]), num = atoi(argv[3]);
    for (i = 1, sum = first; i < num; i++)
        sum += diff, printf(" %3d", sum);
    printf("\n%3d", first);
    for(i = 1, sum = first; i < num; i++)
        sum += func(first, diff, i+1), printf(" %3d", sum);
    printf("\nsum(%d) = %d", num, sum);
    return 0;
}

和だけを表示させる

#include <stdio.h> /* arithmetic progression (ver 2.0) */
#include <stdlib.h>/* a(1) + a(2)+ ... + a(n-1) + a(n) */

int func(int first, int diff, int num) {
    int i, sum;
    for (i = 1, sum = first; i < num; i++)
        sum += diff;    /* calc a(n) */
    return sum;
}

int main(int argc, char *argv[]) {
    int i, sum;
    int first = atoi(argv[1]), diff = atoi(argv[2]), num = atoi(argv[3]);
    for(i = 1, sum = first; i < num; i++)    /* sum = a(1) */
        sum += func(first, diff, i+1);      /* sum + a(2)+ ... + a(n-1) + a(n) */
    (num >= 1) ? (printf("sum(%d) = %d", num, sum)) : printf("error!");
    return 0;
}

112日目 整数の乗除を加減記号で実装(途中ww)

パズルみたいで面白かったけれども実用とかけ離れてるwww


注1:コマンドライン引数を使用してます
注2:めちゃめちゃですww

割られる数<割る数でもオッケー、ただし両方10のn乗

#include <stdio.h> /* division, if(a < b, both a and b included in pow(10,x))*/
#include <stdlib.h>

int divi(int a, int b);

int main(int argc, char *argv[])
{
    int a = atoi(argv[1]), b = atoi(argv[2]);
    int i , j, num;
    if (b == 0)
        printf("error: zero divisior");
    else if (a >= b)
        printf("%d", divi(a, b));
    else if (a < b) {
        for (i = 0, num = a; divi(num, b) <= 1; ++i)
            num *= 10;
        printf("0.");
        for (j = 0; j < i-1; ++j)
            printf("0");
        printf("%d", divi(num, b));
    }
}

int divi(int a, int b)
{
    int i;
    for (i = 0; a > 0; i++)
        a -= b;
    return i;
}

モジュロ

#include <stdio.h> /* modulo */
#include <stdlib.h>

int mod(int a, int b)
{
    while (a >= b)
        a -= b;
    return a;
}

int main(int argc, char *argv[])
{
    int a = atoi(argv[1]), b = atoi(argv[2]);
    (b != 0) ? (printf("%d", mod(a, b))) : (printf("error: zero divisior"));
}

割られる数≧割る数(両方整数) 小数点切り上げ中

#include <stdio.h> /* division, if(dividend >= divisor) */
#include <stdlib.h>

int divi(int a, int b)
{
    int i;
    for (i = 0; a > 0; i++)
        a -= b;
    return i;
}

int main(int argc, char *argv[])
{
    int a = atoi(argv[1]), b = atoi(argv[2]);
    (b != 0) ? (printf("%d", divi(a, b))) : (printf("error: zero divisior"));
}

乗算

#include <stdio.h> /* multiply */
#include <stdlib.h>

int mtp(int a, int b)
{
    int i, num = 0;
    for (i = 0; i < b; i++)
        num += a;
    return num;
}

int main(int argc, char *argv[])
{
    int a = atoi(argv[1]), b = atoi(argv[2]);
    printf("%d", mtp(a, b));
}


参考文献

いやでも楽しめる算数 (講談社文庫)

いやでも楽しめる算数 (講談社文庫)

103日目 第4章 逆ポーランド記法型電卓プログラム

本文のソースを参考に、とりあえずわかるところまでやってみた。

//main()                        MAXOP, NUMBER
//    getop()                        NUMBER
//        getch()
//        !isdigit()    <ctype.h>
//        ungetch()                BUFSIZE
//    !atof()            <stdlib.h>
//    push()                        MAXVAL
//    pop()
//    !printf()        <stdio.h>

#include<ctype.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>                // Ex.4-5

#define MAXOP 100
#define NUMBER '0'
#define BUFSIZE 100
#define MAXVAL 100


int getop(char []);
int getch(void);
void ungetch(int);
void push(double);
double pop(void);


main()
{
    int type;
    double op2;
    char s[MAXOP];

    while((type=getop(s)) != EOF) {
        switch (type) {
        case NUMBER:
            push(atof(s));
            break;
        case '+':
            push(pop() + pop());
            break;
        case '-':
            op2 = pop();
            push(pop() - op2);
            break;
        case '*':
            push(pop()*pop());
            break;
        case '/':
            op2 = pop();
            if(op2 != 0.0)
                push(pop() / op2);
            else
                printf("error: zero divisor\n");
        break;
        case 's':
            push(sin(pop()));
            break;
        case 'e':
            push(exp(pop()));
            break;
        case 'p':
            op2 = pop();
            push(pow(pop(), op2));
            break;
        case '\n':                    // answer
            printf("\tans:%.8g\n", pop());
            break;
        default:
            printf("error: unknown command %s\n", s);
            break;
        }
    }
    return 0;
}

int getop(char s[])
{
    int i, c;

    while ((s[0] = c = getch()) == ' ' || c == '\t')
        ;                            // 読み込んだ文字が空白かタブだったら何もしない
    s[1] = '\0';
    if(!isdigit(c) && c != '.')
        return c;                    // 数字でも小数点でもなければそれを返す
    i = 0;
    if (isdigit(c))
        while (isdigit(s[++i] = c = getch()))
            ;                        // 読み込んだ値が数字だったら、何もしないで次の値も読み込んで配列に格納
    if (c == '.')
        while (isdigit(s[++i] = c = getch()))
            ;                        // 読み込んだ値が小数点だったら、何もしないで次の値も読み込んで配列に格納
    s[i] = '\0';
    if (c != EOF)
        ungetch(c);                    // EOFを吐き出す
    return NUMBER;
}

char buf[BUFSIZE];
int bufp = 0;

int getch(void)
{
    return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c)
{
    if (bufp >= BUFSIZE)
        printf("ungetch: too many characters\n");
    else
        buf[bufp++] = c;
}

int sp = 0;
double val[MAXVAL];

void push(double f)
{
    if (sp < MAXVAL)
        val[sp++] = f;
    else
        printf("error: stack full, can't push %g\n", f);
}

double pop(void)
{
    if (sp > 0)
        return val[--sp];
    else {
        printf("error: stack empty\n");
        return 0.0;
    }
}

ruby複利計算のお題をCでやってみた

RubyistじゃないけどRuby会議にスネークしてみた!

そこでRubyKaigi2008 Golfコンペなるものがあったので自重しないで参加してみたよ。
日本 Ruby 会議 2008 - RubyKaigi2008 Golfコンペ




…Cで。

回数:初期値:パーセント の形で入力して複利計算の結果を表示しろ。(ただし計算途中の小数点は切り捨て)

anarchy golfの146番目の問題。

難易度はそんなに高くない、らしい。
とりあえず覚えたばっかのコマンドライン引数使ってみるか。
要求された使用とちょっと違うがとりあえずここまでしかできません><

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

main(int argc, char *argv[])
{
    int i, k = atoi(argv[1]);
    double j = atoi(argv[2]);

    for(i = 0; i < k; i++)
        printf("%.0f\n", j); {
        j = floor(j*(100+atoi(argv[3]))/100
    }
}

floor関数はじめて使った。