1 C言語入門 第7週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) 2 多次元配列 3 多次元の値も扱いたい • 例えば行列の演算(1,2次元混合) 𝑎1,1 ⋮ 𝑎𝑚,1 … 𝑎1,𝑛 ⋱ ⋮ … 𝑎𝑚,𝑛 行列は2次元 𝐴𝑥 = 𝑏 𝑥1 𝑏1 ⋮ = ⋮ 𝑥𝑛 𝑏𝑚 ベクトルは1次元 4 多次元の値も扱いたい • 例えば白黒や濃淡画像(2次元) 0 32 64 128 0 32 64 128 32 64 128 192 32 64 128 192 128 128 192 255 128 128 192 255 x,y座標の各点をマス目で表し 各マス目の明るさを 256段階(8bit)の数値で表す 輝度値や明度値と言う それぞれのマス目の数値に応じて 光らせる明るさを調整すると 絵が描ける 5 多次元の値も扱いたい • 例えば白黒や濃淡画像(3次元) 255 0 0 255 255 0 0 255 x,y座標の各点の 光の三原色 赤緑青の明るさ(RGB値)を 数値で表す 0 画面を虫眼鏡で見ると こんな感じに 光っているのが見える 255 0 255 0 0 255 0 255 255 6 多次元の値も扱いたい • 例えば白黒や濃淡画像(3次元) 255 0 0 255 255 0 0 255 遠目で見た場合や ソフトウェア上では 色が混ざって このように見える 0 255 0 255 0 0 255 0 255 255 7 画面表示の仕組み • 方眼紙のような構造 • 光の三原色(RGB=赤緑青)で加法混色 • 通常、各色8bit(256段階)で電圧調整して明暗表現 • 計24bit(16,777,216色)=8bit×3(256×256×256 段階) 8 混色 • 加法混色 • 減法混色 • 画面、光 • RGBカラーモデル • Red, Green, Blue • 印刷、絵の具 • CMYカラーモデル • Cyan, Magenta, Yellow R Y Y M Bk W G C M R G B B C 9 教科書 pp.52-56. メモリの構成 • メモリのアドレスは1次元でした 32bitのOSは32bitのアドレス空間 最大232 Bytes=4GiB 64bitのOSは64bitのアドレス空間 最大264 Bytes=16EiB 0x00000000 0x00 0x0000000000000000 0x00 0x00000001 0x00 0x0000000000000001 0x00 0x00000002 0x00 0x0000000000000002 0x00 0x00000003 0x00 0x0000000000000003 0x00 : : : : 0xffffffff 0x00 アドレス 格納値 : : 0xffffffffffffffff アドレス : : 0x00 格納値 10 教科書 pp.85-108. 二次元配列変数 • 1次元のメモリを折り畳んで2次元にして使う char a[3][4]; // 要素数3*4のchar型変数の宣言 ? ? ? ? ? ? a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] 1行分のデータ ? ... a[2][3] メモリのアドレスは1次元なので 実際には2行目以降も 直線状に並んでいる [1] pp.135-137. 11 教科書 pp.85-108. 二次元配列変数 • 要素数4の配列を3つ並べた例 char a[3][4]; // 要素数3*4のchar型変数の宣言 ? ? ? ? a[0][0] a[0][1] a[0][2] a[0][3] ? ? ? ? a[1][0] a[1][1] a[1][2] a[1][3] ? ? ? 論理的には 2次元的に並んでいると 考えて使えば良い。 ? a[2][0] a[2][1] a[2][2] a[2][3] [1] pp.135-137. 12 行列の行と列 • m行n列の行列 1列 1行 : : m行 𝑎1,1 ⋮ 𝑎𝑚,1 ・・・ n列 … 𝑎1,𝑛 ⋱ ⋮ … 𝑎𝑚,𝑛 13 Row-major と Column-major • 本来1次元のメモリをどう区切って使うか? • 行を連続にするか?列を連続にするか? 1列 1行 : : m行 𝑎1,1 ⋮ 𝑎𝑚,1 ・・・ n列 … 𝑎1,𝑛 ⋱ ⋮ … 𝑎𝑚,𝑛 Row-major は行方向の要素が メモリ上で連続に並ぶ C言語はこのタイプ 1列 𝑎1,1 ⋮ 𝑎𝑚,1 ・・・ n列 … 𝑎1,𝑛 ⋱ ⋮ … 𝑎𝑚,𝑛 Column-major は列方向の要素が メモリ上で連続に並ぶ Fortran等はこのタイプ 14 メモリ上の配列と二次元配列(行列) • Row-major は同じ行が繋がっている a[0][0] a[0][1] a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][1] a[2][2] a[2][3] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] : a[2][3] 二次元配列 Row-major int a[m][n]; a[i][j]; int a[m * n]; a[n * i + j]; C言語はこのタイプ 訂正: 2015-06-20 誤: a[m * i + j] 正: a[n * i + j] 15 メモリ上の配列と二次元配列(行列) • Column-major は同じ列が繋がっている a[0][0] a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][0] a[1][1] a[1][2] a[1][3] a[2][0] a[2][0] a[2][1] a[2][2] a[2][3] a[0][1] a[1][1] a[2][1] a[0][2] : a[2][3] 二次元配列 Column-major int a[m][n]; a[i][j]; int a[m * n]; a[i + j * m]; Fortran等はこのタイプ 訂正: 2015-06-20 誤: a[i + j * n] 正: a[i + j * m] 16 教科書 pp.85-108. 二次元配列のメモリ上の配置 • Row-major と Column-major ? ? ? ? ? ? a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] ? ? ? ? ? a[0][0] a[1][0] a[2][0] a[0][1] a[1][1] a[2][1] 1列分のデータ ... a[2][3] Row-major は行方向の要素が連続に並ぶ C言語はこのタイプ 1行分のデータ ? ? ? ... a[2][3] Column-major は列方向の要素が連続に並ぶ Fortran等はこのタイプ [1] pp.135-137. 17 教科書 pp.85-108. 三次元配列変数 • 1次元のメモリを折り畳んで3次元にして使う char a[2][3][4]; // 要素数2*3*4のchar型変数の宣言 ? ? ? ? ? ? [0][0][0] [0][0][1] [0][0][2] [0][0][3] [0][1][0] [0][1][1] 1行分のデータ ? ... [1][2][3] メモリのアドレスは1次元なので 実際には2行目以降も 直線状に並んでいる [1] pp.135-137. 18 教科書 pp.85-108. 三次元配列変数 • 要素数3*4の配列を2つ並べた例 char a[2][3][4]; // 要素数2*3*4のchar型変数の宣言 ? ? ? ? [0][0][0] [0][0][1] [0][0][2] [0][0][3] ? ? ? ? [0][1][0] [0][1][1] [0][1][2] [0][1][3] ? ? ? ? [0][2][0] [0][2][1] [0][2][2] [0][2][3] ? ? ? ? [1][0][0] [1][0][1] [1][0][2] [1][0][3] ? ? ? ? [1][1][0] [1][1][1] [1][1][2] [1][1][3] ? ? ? ? [1][2][0] [1][2][1] [1][2][2] [1][2][3] [1] pp.135-137. 19 教科書 pp.85-108. 配列変数の使用例 • 同じ次元・要素数でもいろんな解釈で使える char a[2][3][4]; char a[3][4]; a[ch][t]; a[t][x]; a[y][x]; a[t][y][x]; a[z][y][x]; 20 二次元配列の演習 行列の演算 21 演習: 行列とベクトルの演算 • 𝐴 を3×3の行列、 𝒃, 𝒙 を3次元のベクトルとしたとき に以下の計算を行うプログラム作ってみましょう。 • 積(matrix_vector_mul_practice_1.c) 𝑛 𝒃 = 𝐴𝒙: 𝑏𝑖 = 𝑎𝑖,𝑗 𝑥𝑗 𝑗=1 22 演習: 行列の演算 • 𝐴, 𝐵 を3×3の行列としたときに以下の計算を行うプログ ラム作ってみましょう。 • 加算(add)、減算(sub)、要素単位の乗算(times)、 行列乗算(mtimes)、 訂正: 2015-06-20 誤: 𝐶 = 𝐴 + 𝐵 正: 𝐶 = 𝐴.∗ 𝐵 転置(transpose) • • • • • 加算: 減算: 要素単位の乗算: 行列乗算: 転置: 𝐶 𝐶 𝐶 𝐶 𝐶 = 𝐴 + 𝐵: 𝑐𝑖,𝑗 = 𝑎𝑖,𝑗 + 𝑏𝑖,𝑗 = 𝐴 − 𝐵: 𝑐𝑖,𝑗 = 𝑎𝑖,𝑗 − 𝑏𝑖,𝑗 = 𝐴.∗ 𝐵: 𝑐𝑖,𝑗 = 𝑎𝑖,𝑗 𝑏𝑖,𝑗 = 𝐴 ∗ 𝐵: 𝑐𝑖,𝑗 = 𝑚 𝑘=1 𝑎𝑖,𝑘 𝑏𝑘,𝑗 = 𝐴𝑇 : 𝑐𝑖,𝑗 = 𝑎𝑗,𝑖 訂正: 2015-06-20 誤: 𝐶 = 𝐴 + 𝐵 正: 𝐶 = 𝐴 ∗ 𝐵 23 演習: 行列の演算 • matrix_vector_xxx_practice_1.c を元にして以下のファ イル名で作成せよ • 加算: matrix_vector_add_practice_1.c • 減算: matrix_vector_sub_practice_1.c • 要素単位の乗算: matrix_vector_times_practice_1.c • 行列乗算: matrix_vector_mtimes_practice_1.c • 転置: matrix_vector_transpose_practice_1.c 24 重複した処理をループにまとめる 数式をループに変換する ループの組み立て 追加: 2015-06-20 25 ループの組み立て 重複した処理をまとめる sum = 1 + 1 + 1 + 1 + 1; 演算を構成する項を縦に並べる sum = + + + + 1 1 1 1 1; 各項を単文で書き直す sum sum sum sum sum = += += += += 1; 1; 1; 1; 1; 積算の場合 初期値を与えて 各単文を 全く同じ処理の 繰り返しにする sum = 0; // 初期化 for (i = 0; i < 5; i++) { sum += 1; } sum sum sum sum sum sum = += += += += += 0; // 初期化 1; 1; 1; 5回繰り返している 1; 1; 追加: 2015-06-20 26 ループの組み立て 重複した処理をまとめる sum = 1 + 2 + 3 + 4 + 5; 演算を構成する項を縦に並べる sum = + + + + sum sum sum sum sum 1 2 3 4 5; 各項を単文で書き直す = 1; += 2; += 3; += 4; += 5; sum = 0; // 初期化 for (i = 1; i <= 5; i++) { sum += i; } ループカウンタを活用する 積算の場合 初期値を与えて 各単文を 全く同じ処理の 繰り返しにする sum sum sum sum sum sum = += += += += += 0; // 初期化 1; 2; 3; 1~5まで増えている 4; 5; 追加: 2015-06-20 27 ループの組み立て 重複した処理をまとめる sum = a[0]*b[0]+a[1]*b[1]+・・・+a[N-1]*b[N-1]; 演算を構成する項を縦に並べる sum = a[0]*b[0] + a[1]*b[1] ⋮ ⋮ + a[N-1]*b[N-1]; ループカウンタを活用する 各項を単文で書き直す sum = a[0]*b[0]; sum += a[1]*b[1]; ⋮ ⋮ sum += a[N-1]*b[N-1]; sum = 0; // 初期化 for (i = 0; i < N; i++) { sum += a[i]*b[i]; } 積算の場合 初期値を与えて 各単文を 全く同じ処理の 繰り返しにする sum = 0; // 初期化 sum += a[0]*b[0]; sum += a[1]*b[1]; ⋮ ⋮ sum += a[N-1]*b[N-1]; 0~N-1 まで 増えて いる 28 追加: 2015-06-20 加筆: 2015-06-26 ループの組み立て 数式とC言語の対応を考える • 数式 定石の書き方から変形 𝑛 𝑛 𝑠= 𝑠= 1 𝑖=1 𝑖=1 • C言語 𝑖 積算項: 1 ↔ 𝑖 1の積算 𝑖の積算 s = 0; for (i = 1; i <= n; i++) { s += 1; } s = 0; for (i = 1; i <= n; i++) { s += i; } 29 追加: 2015-06-20 加筆: 2015-06-26 ループの組み立て 数式とC言語の対応を考える • 数式 定石の書き方から変形 𝑛 𝑛 𝑠= 𝑏𝑖 = 𝑖 𝑗=1 𝑖=1 • C言語 𝑎𝑖,𝑗 𝑥𝑗 結果: 𝑠 → 𝑏𝑖 カウンタ: 𝑖 → 𝑗 積算項: 𝑖 → 𝑎𝑖,𝑗 𝑥𝑗 𝑖の積算 𝑎𝑖,𝑗 𝑥𝑗 の積算 s = 0; for (i = 1; i <= n; i++) { s += i; } b[i] = 0; for (j = 1; j <= n; j++) { b[j] += a[i][j] * x[j]; } 30 追加: 2015-06-20 加筆: 2015-06-26 ループの組み立て 数式とC言語の対応を考える 要素数𝑛個の数列や配列は 数学では 𝑎1 ⋯ 𝑎𝑛 と書く場合が多いが C言語では a[0]⋯a[n-1] になる • 数式 𝑛 𝑏𝑖 = 𝑎𝑖,𝑗 𝑥𝑗 𝑗=1 • C言語 𝑛−1 C言語に合わせて 添え字を1つずらす 𝑏𝑖 = 𝑎𝑖,𝑗 𝑥𝑗 𝑗=0 単純に置きかえ 範囲: 1: 𝑛 → 0: 𝑛 − 1 → 0: 𝑛 𝑎𝑖,𝑗 𝑥𝑗 の積算 𝑎𝑖,𝑗 𝑥𝑗 の積算 b[i] = 0; for (j = 1; j <= n; j++) { b[j] += a[i][j] * x[j]; } b[i] = 0; for (j = 0; j < n; j++) { b[j] += a[i][j] * x[j]; } 31 追加: 2015-06-20 加筆: 2015-06-26 ループの組み立て 数式とC言語の対応を考える • 数式 𝑛−1 𝑏𝑖 = 𝑎𝑖,𝑗 𝑥𝑗 𝑗=0 • C言語 全ての𝑏𝑖 についてループして計算 𝑎𝑖,𝑗 𝑥𝑗 の積算 𝑎𝑖,𝑗 𝑥𝑗 の積算 for (i = b[i] = for (j b[j] } } b[i] = 0; for (j = 0; j < n; j++) { b[j] += a[i][j] * x[j]; } 0; i < m; i++) { 0; = 0; j < n; j++) { += a[i][j] * x[j]; 32 参考文献 • [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準 拠、共立出版(1989)
© Copyright 2024 ExpyDoc