Cの速さにがっくり来た
Rubyで書いたグラフィックバッファ処理と同じものをCで書き直してみた。
#include <stdio.h> #include <stdlib.h> #include <time.h> typedef struct { int height; int width; int **raw; } buf; buf *init_buf (int width, int height) { buf *b; int i, j; b = (buf *)malloc(sizeof(int) * 2 + sizeof(int*)); b->height = height; b->width =width; b->raw = (int **)malloc(sizeof(int*) * height); b->raw[0] = (int *)malloc(sizeof(int) * width * height); for (i = 1; i < height; i ++) { b->raw[i] = b->raw[0] + (width * i); } for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { // b->raw[i][j] = 0x00ffccff; // purple-ish white b->raw[i][j] = 0x00ffffff; // white } } return b; } int save_buf (buf *b) { FILE *fp; int i, j; if ((fp = fopen("test.ppm", "w")) == NULL) { printf("Can't open the file\n"); exit(1); } fprintf(fp, "P6\n%d %d\n255\n", b->width, b->height); for (i = 0; i < b->height; i++) { for (j = 0; j < b->width; j++) { fwrite(&b->raw[i][j], sizeof(char), 3, fp); } } fclose(fp); return 0; } int fill_circle (buf *buf, int x, int y, int rad, int color, int opc) { int i, j; float back, fore; unsigned char r, g, b; unsigned char r2, g2, b2; if ((opc < 0) || (opc >100)) { return 1; } r2 = color & 0x000000ff; g2 = (color & 0x0000ff00) / 0x100; b2 = (color & 0x00ff0000) / 0x10000; fore = (float)opc / 100; back = (100 - (float)opc) / 100; for (i = 0; i < buf->height; i++) { for (j = 0; j < buf->width; j++) { if ((rad*rad - (y-i)*(y-i) - (x-j)*(x-j)) > 0) { r = buf->raw[i][j] & 0x000000ff; g = (buf->raw[i][j] & 0x0000ff00) / 0x100; b = (buf->raw[i][j] & 0x00ff0000) / 0x10000; r = (r2 * fore) + (r * back); g = (g2 * fore) + (g * back); b = (b2 * fore) + (b * back); buf->raw[i][j] = (b * 0x10000) + (g * 0x100) + r; } } } return 0; } int main (int argc, char *argv[]) { buf *b; int i; int x, y, r, col; srand(time(NULL)); b = init_buf(320, 240); for (i = 0; i < 100; i++) { x = rand() % b->width; y = rand() % b->height; r = rand() % 50 + 10; col = rand() & 0x00ffffff; fill_circle(b, x, y, r, col, 60); } save_buf(b); return 0; }
intのポインタのポインタを含む構造体の初期化のところで、エラーが出まくって、こんなのきっとぼくには無理だと諦めそうになったほど、メモリとポインタの扱いがややこしい(メモリの解放のほうも単純じゃなくてめんどくさそう)。
うまく動かないときに何はともあれでgdbを起動してブレークポイントを設定すると、これが非常に役立つことを発見しつつある。構造体メンバの初期化忘れとか、intからfloatへのキャストする場所の間違えとか、バグの原因となっているところが、すぐに分かる。
それにしても、Cが劇っ速で驚いた。100個の円を塗りつぶすというほぼ同じ処理をやるのに、Rubyで9秒、Cでは0.09秒と100倍の差がついた。無駄なループを省くとさらに、0.04秒に縮まった。このぐらい速いんなら、ピクセル単位の差分を計算してホゲホゲという処理も、現実的な時間で可能な気がする。