Gauche:2次元配列のプログラムの移植
2次元配列のプログラムの移植
- 2次元配列を扱うプログラムの移植で、おおよそ以下のように書き換えて使用しました。
- データ構造は、試行錯誤があったのですが、結局1次元のベクタにしました。
(pt x y) という補助的な手続きを作って、x と y でデータにアクセスできるようにしています。
また、2重ループは、let loop ... 1個に置き換えました。
- そういえば、C言語を始めたころに for (i = 0; i < 10; i++) ... という文を見て、
括弧内の3つの式が、それぞれ実行されるタイミングが異なることに混乱したことがありました。
今考えると、Lisp/Scheme の構文が、同じ括弧でも場所によって意味が変わるので
とっつきにくいという話と、似たようなことだったのかなと思います。
(参考URL :
http://qiita.com/dico_leque/items/2fa485771a3bc09ab551
http://qiita.com/SaitoAtsushi/items/fc9e210d30ca00cad162
https://practical-scheme.net/wiliki/wiliki.cgi?Lisp%3AS%E5%BC%8F%E3%81%AE%E7%90%86%E7%94%B1 )
<元ソース>
#include <stdio.h> #define MW 10 #define MH 10 int mdata[MH][MW]; int main(void) { int x, y; for (y = 0; y < MH; y++) { for (x = 0; x < MW; x++) { mdata[y][x] = y * MW + x; printf("%2d ", mdata[y][x]); if (x == MW - 1) printf("\n"); } } return 0; }
<移植後>
(define mw 10) (define mh 10) (define mdata (make-vector (* mw mh) 0)) (define (pt x y) (+ (* y mw) x)) (let loop ((x 0) (y 0)) (set! (~ mdata (pt x y)) (+ (* y mw) x)) (display (format "~2d " (~ mdata (pt x y)))) (if (= x (- mw 1)) (newline)) (cond ((< x (- mw 1)) (loop (+ x 1) y)) ((< y (- mh 1)) (loop 0 (+ y 1)))))
hamayama(2017/08/12 10:19:04 UTC)(2017/08/13 04:02:16 UTC)
(2017/08/15 13:10:02 UTC)
array を使った場合 (齊藤 2017/11/15 17:48:54 UTC)
一次元のベクタを使ったのには相応の理由があるのでしょうが、あえて array を使った場合を考えてみるとこんな感じになりますね。
(use gauche.array) (define mw 10) (define mh 10) (define mdata (tabulate-array (shape 0 mh 0 mw) (^(y x) (+ (* y mw) x)))) (array-for-each-index mdata (^(y x)(format #t "~2d " (array-ref mdata y x)) (when (= x (- mw 1)) (newline))))
内部的にはベクタに色々とかぶせる形で実装されているので、必要であればベクタとして取り出すことも出来るようです。
(~ mdata 'backing-storage)
ドキュメントに書かれていないやり方なので非公式扱いだとは思いますが。
- hamayama(2018/08/14 12:43:06 UTC): その後、C++ の Eigen ライブラリを使って
gauche.array の行列演算を高速化するモジュールを作ってみました。
( https://github.com/Hamayama/eigenmat ) (<f64array> のごく一部の演算のみですが。。。)
backing-storage スロットが有用でした。