Cのマクロの練習

まずは Hello, World!。

#define P MAIN BEGIN PRINT_HELLO RETURN END
#define MAIN int main()
#define BEGIN {
#define END }
#define PRINT_HELLO PRINT(HELLO_STRING)
#define PRINT(a) printf(a);
#define HELLO_STRING STRING_NL(HELLO,\n)
#define STRING_NL(a,b) QUOTE""a""QUOTE#b
#define HELLO Hello, World!
#define QUOTE "
#define RETURN RET(linux-unix*i386)
#define RET(a) return (a);
P

gcc hoge.cだとコンパイルが通らないのに、gcc -E hoge.c | gcc -x c -だとコンパイルできる。なぜだろう? ちなみにコンパイラgcc-3.4.6。

小さな数をたくさん足す時の情報落ち対策

足し残しを次の足し算に繰り越すアルゴリズムは、よくあるパターンのような気がするので、マクロか何かを使うと何度も似たような構文を書かなくていいのではないかと思った。ということで、C のマクロで試してみる。
するとこんな手抜きプログラムができた。

#include<stdio.h>
#include<math.h>
#define SUM(funcname,init,cond,proc,next)\
    double funcname(double x){\
        double s=0,r=0,olds,t,term;\
        init;\
        while( cond ){\
            olds=s;\
            t=(proc)+r;\
            s+=t;\
            r=t-(s-olds);\
            next;\
        }\
        return s;\
    }
SUM(exp_s,int i=0;term=1,term>1e-10,term,i++;term*=x/i)
SUM(log_s,int i=1;double u=(x-1)/(x+1);term=2*u,term>1e-10,
    term/i,i+=2;term*=u*u)
int main()
{
    printf("%g %g\n",exp(3),exp_s(3));
    printf("%g %g\n",log(3),log_s(3));
    return 0;
}

結論、読みづらい。これを綺麗に書く方法は無いのだろうか?
他の言語ではどうなるのだろう。

追記:上のプログラムに改行を入れたりしてちょっと読みやすくしてみた。 まあ要するに、下みたいなことがしたいわけです。
#include<stdio.h>
#include<math.h>

void sum(double *s,double term,double *r)
{
    double olds,t;
    olds=*s;
    t=term+*r;
    *s+=t;
    *r=t-(*s-olds);
    return;
}
double exp_s(double x){
    int i=0;
    double s=0, term=1, r=0;
    while(term>1e-10){
        sum(&s,term,&r);
        i++;
        term*=x/i;
    }
    return s;
}
double log_s(double x){
    int i=1;
    double s=0, term, u=(x-1)/(x+1), r=0;
    term=2*u;
    while(term>1e-10){
        sum(&s,term/i,&r);
        i+=2;
        term*=u*u;
    }
    return s;
}

int main()
{
    printf("%g %g\n",exp(3),exp_s(3));
    printf("%g %g\n",log(3),log_s(3));
    return 0;
}
なんか、これでいいんじゃないかという気がするけど。