carray-jit 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +771 -3
- data/README.md +7 -6
- data/carray-jit.gemspec +1 -3
- data/docs/00_Introduction.md +4 -3
- data/docs/01_GettingStarted.md +1 -1
- data/docs/02_KernelShapes.md +93 -14
- data/docs/03_SupportedFeatures.md +582 -26
- data/docs/04_Compiling.md +33 -6
- data/docs/05_DesignNotes.md +3 -3
- data/docs/06_Cheatsheet.md +198 -5
- data/docs/07_StepByStep.ja.md +534 -0
- data/docs/07_StepByStep.md +535 -0
- data/examples/README.md +12 -0
- data/examples/applications/alarm.rb +121 -0
- data/examples/applications/collatz.rb +105 -0
- data/examples/applications/cubic_spline.rb +331 -0
- data/examples/applications/dithering.rb +144 -0
- data/examples/applications/group_stats.rb +115 -0
- data/examples/applications/lookup.rb +126 -0
- data/examples/applications/median_filter.rb +153 -0
- data/examples/applications/parcel_ascent.rb +220 -0
- data/examples/applications/point_in_polygon.rb +111 -0
- data/examples/applications/random_walk.rb +98 -0
- data/examples/applications/van_der_pol.rb +186 -0
- data/examples/applications/wet_bulb.rb +140 -0
- data/examples/features/10_complex.rb +14 -4
- data/examples/features/15_loops.rb +7 -1
- data/lib/carray/jit/access.rb +14 -0
- data/lib/carray/jit/analyzer.rb +2077 -136
- data/lib/carray/jit/block_reader.rb +37 -6
- data/lib/carray/jit/c_function.rb +613 -76
- data/lib/carray/jit/c_generator.rb +1595 -156
- data/lib/carray/jit/call.rb +68 -0
- data/lib/carray/jit/compiler.rb +75 -11
- data/lib/carray/jit/kernel.rb +369 -32
- data/lib/carray/jit/node.rb +359 -9
- data/lib/carray/jit/sorting_networks.rb +182 -0
- data/lib/carray/jit/type_assignment.rb +371 -34
- data/lib/carray/jit/version.rb +1 -1
- data/lib/carray/jit.rb +560 -64
- metadata +22 -8
- data/ext/carray_jit_access/carray_jit_access.c +0 -460
- data/ext/carray_jit_access/extconf.rb +0 -8
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
# carray-jit 練習問題 31 問(解答つき)
|
|
2
|
+
|
|
3
|
+
[07_StepByStep.md](07_StepByStep.md) の日本語版です。ドキュメントが導入する順
|
|
4
|
+
に並べた三十一の小さな課題と、その解答。おおむね難しくなる順で、星は「subset の
|
|
5
|
+
どこまでを使うか」であって、コードの長さではありません。
|
|
6
|
+
|
|
7
|
+
書いてあるとおりに動きます。まず
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
require "carray"
|
|
11
|
+
require "carray/jit"
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
としてください。`#=>` はその行が実際に返す値です。
|
|
15
|
+
|
|
16
|
+
課題を読み、やってみて、それから見る。コンパイラが断ることが答えである問題で
|
|
17
|
+
は、拒否のメッセージがコードの下に出ています。
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
#### 1. `a + b * c` を `out` に、途中の配列を作らず一回の走査で (★☆☆)
|
|
22
|
+
|
|
23
|
+
`ヒント: 隣に手を伸ばさない仕事のためのメソッド`
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
a = CA_DOUBLE([1, 2, 3])
|
|
27
|
+
b = CA_DOUBLE([2, 3, 4])
|
|
28
|
+
c = CA_DOUBLE([3, 4, 5])
|
|
29
|
+
out = CArray.double(3)
|
|
30
|
+
|
|
31
|
+
CArray.jit_each { out = a + b * c }
|
|
32
|
+
out.to_a #=> [7.0, 14.0, 23.0]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
#### 2. int32 の配列三つで `(a + b * c) / 2` を計算し、結果を新しい配列として受け取る。そのデータ型は? (★☆☆)
|
|
36
|
+
|
|
37
|
+
`ヒント: もう一方の要素ごとメソッド`
|
|
38
|
+
|
|
39
|
+
```ruby
|
|
40
|
+
a = CA_INT32([1, 2, 3])
|
|
41
|
+
b = CA_INT32([2, 3, 4])
|
|
42
|
+
c = CA_INT32([3, 4, 5])
|
|
43
|
+
|
|
44
|
+
half = CArray.jit_map { (a + b * c) / 2.0 }
|
|
45
|
+
half.to_a #=> [3.5, 7.0, 11.5]
|
|
46
|
+
half.data_type_name #=> "float64"
|
|
47
|
+
# 型は配列からではなくブロックの最後の値から決まる。`2.0` は自分の幅を持た
|
|
48
|
+
# ないので出会った幅を取る。これが無ければ int64。
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### 3. 三要素の行を 2x3 の表の全行に足して `out` へ。行は複製せずに (★☆☆)
|
|
52
|
+
|
|
53
|
+
`ヒント: CArray は軸を伸ばすが、rank は捏造しない`
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
table = CArray.double(2, 3).seq!(1.0)
|
|
57
|
+
row = CA_DOUBLE([10, 20, 30]).reshape(1, 3) # 3 ではなく 1x3。でないと ndim mismatch
|
|
58
|
+
out = CArray.double(2, 3)
|
|
59
|
+
|
|
60
|
+
CArray.jit_each { out = table + row }
|
|
61
|
+
out.to_a #=> [[11.0, 22.0, 33.0], [14.0, 25.0, 36.0]]
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### 4. ブロックが捕まえた Float で、値を変えて二度スケールする。コンパイルは一度だけで、両方の結果を集める (★☆☆)
|
|
65
|
+
|
|
66
|
+
`ヒント: 特別なことは要らない`
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
a = CA_DOUBLE([1, 2])
|
|
70
|
+
out = CArray.double(2)
|
|
71
|
+
|
|
72
|
+
[2.0, 5.0].map { |gain|
|
|
73
|
+
CArray.jit_each { out = a * gain } # 捕捉したスカラーは引数であって、
|
|
74
|
+
out.to_a # 焼き込まれた定数ではない
|
|
75
|
+
} #=> [[2.0, 4.0], [5.0, 10.0]]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### 5. 自分のデータ型を持つ係数で配列をスケールして `out` へ (★☆☆)
|
|
79
|
+
|
|
80
|
+
`ヒント: CScalar`
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
a = CA_DOUBLE([1, 2])
|
|
84
|
+
gain = CScalar.double() { 2.5 }
|
|
85
|
+
out = CArray.double(2)
|
|
86
|
+
|
|
87
|
+
CArray.jit_each { out = a * gain }
|
|
88
|
+
out.to_a #=> [2.5, 5.0]
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### 6. 各値を `out` へ。負の値はゼロで打ち切って (★☆☆)
|
|
92
|
+
|
|
93
|
+
`ヒント: 分岐は式`
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
a = CA_DOUBLE([-2, 0, 1.5, 3])
|
|
97
|
+
out = CArray.double(4)
|
|
98
|
+
|
|
99
|
+
CArray.jit_each { out = a < 0.0 ? 0.0 : a }
|
|
100
|
+
out.to_a #=> [0.0, 0.0, 1.5, 3.0]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### 7. ベクトルを逆順にして `out` へ (★☆☆)
|
|
104
|
+
|
|
105
|
+
`ヒント: どのセルを読むかをセルが言わねばならない`
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
a = CArray.double(5).seq!(1.0)
|
|
109
|
+
out = CArray.double(5)
|
|
110
|
+
|
|
111
|
+
CArray.jit_for(5) { |i| out[i] = a[4 - i] }
|
|
112
|
+
out.to_a #=> [5.0, 4.0, 3.0, 2.0, 1.0]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### 8. 階差 `out[i] = a[i] - a[i-1]`。`out[0]` はゼロのまま (★☆☆)
|
|
116
|
+
|
|
117
|
+
`ヒント: 範囲はどこから始められるか`
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
a = CA_DOUBLE([1, 3, 6, 10])
|
|
121
|
+
out = CArray.double(4)
|
|
122
|
+
|
|
123
|
+
CArray.jit_for(1...4) { |i| out[i] = a[i] - a[i - 1] }
|
|
124
|
+
out.to_a #=> [0.0, 2.0, 3.0, 4.0]
|
|
125
|
+
# 0... ではなく 1...。範囲の検査は書かれたとおりの添字に対してループの前に
|
|
126
|
+
# 行われるので、本体の中にガードを置いても通らない。
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### 9. `out[i] = 0.5 * a[i] + 0.5 * out[i-1]`、ただし `out[0] = a[0]` (★★☆)
|
|
130
|
+
|
|
131
|
+
`ヒント: このループが今書いたものを読む`
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
a = CA_DOUBLE([4, 8, 8, 8])
|
|
135
|
+
out = CArray.double(4)
|
|
136
|
+
out[0] = a[0]
|
|
137
|
+
|
|
138
|
+
CArray.jit_for(1...4) { |i| out[i] = 0.5 * a[i] + 0.5 * out[i - 1] }
|
|
139
|
+
out.to_a #=> [4.0, 6.0, 7.0, 7.5]
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### 10. 2x3 を転置して 3x2 の `out` へ (★☆☆)
|
|
143
|
+
|
|
144
|
+
`ヒント: 引数二つ、extent 二つ`
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
a = CArray.double(2, 3).seq!(1.0)
|
|
148
|
+
out = CArray.double(3, 2)
|
|
149
|
+
|
|
150
|
+
CArray.jit_for(2, 3) { |i, j| out[j, i] = a[i, j] }
|
|
151
|
+
out.to_a #=> [[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]]
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### 11. 各行の最大値を `out` へ (★☆☆)
|
|
155
|
+
|
|
156
|
+
`ヒント: セルの中のループ`
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
a = CA_DOUBLE([[1, 3, 2], [9, 4, 5]])
|
|
160
|
+
out = CArray.double(2)
|
|
161
|
+
|
|
162
|
+
CArray.jit_for(2) { |i|
|
|
163
|
+
best = a[i, 0]
|
|
164
|
+
(1...3).each { |j| best = a[i, j] if a[i, j] > best }
|
|
165
|
+
out[i] = best
|
|
166
|
+
}
|
|
167
|
+
out.to_a #=> [3.0, 9.0]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### 12. int32 の配列を、カーネルが書けるひとつの値に合計する (★☆☆)
|
|
171
|
+
|
|
172
|
+
`ヒント: ローカルは反復を越えて残らない`
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
a = CArray.int32(10).seq!(1)
|
|
176
|
+
total = CScalar.int32() { 0 }
|
|
177
|
+
|
|
178
|
+
CArray.jit_for(10) { |i| total[] += a[i] }
|
|
179
|
+
total[0] #=> 55
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### 13. 各読みがどのビンに属するかが与えられている。ビンごとの個数を `counts` へ (★★☆)
|
|
183
|
+
|
|
184
|
+
`ヒント: 添字が添字ではなく値`
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
bin = CA_INT32([0, 2, 1, 1, 0, 1])
|
|
188
|
+
counts = CArray.int32(3)
|
|
189
|
+
|
|
190
|
+
CArray.jit_for(6) { |i| counts[bin[i]] += 1 }
|
|
191
|
+
counts.to_a #=> [2, 3, 1]
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### 14. 各 (x, y) の原点からの距離を `out` へ (★☆☆)
|
|
195
|
+
|
|
196
|
+
`ヒント: Math`
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
x = CA_DOUBLE([3, 5])
|
|
200
|
+
y = CA_DOUBLE([4, 12])
|
|
201
|
+
out = CArray.double(2)
|
|
202
|
+
|
|
203
|
+
CArray.jit_each { out = Math.sqrt(x * x + y * y) }
|
|
204
|
+
out.to_a #=> [5.0, 13.0]
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### 15. `jit_each` に添字を名乗るブロックを、`jit_for` に名乗らないブロックを渡す。何が返るか (★★☆)
|
|
208
|
+
|
|
209
|
+
`ヒント: どちらも推測しない`
|
|
210
|
+
|
|
211
|
+
```ruby
|
|
212
|
+
a = CA_DOUBLE([1, 2, 3])
|
|
213
|
+
out = CArray.double(3)
|
|
214
|
+
|
|
215
|
+
CArray.jit_each { |i| out[i] = a[i] + 1.0 }
|
|
216
|
+
#=> CArray::JIT::Unsupported: this block names the arrays it reaches, so it
|
|
217
|
+
# takes no parameters; for a loop that names its indices, see `jit_for`
|
|
218
|
+
|
|
219
|
+
CArray.jit_for(3) { out = a + 1.0 }
|
|
220
|
+
#=> CArray::JIT::Unsupported: jit_for's block names the cells it is on, so it
|
|
221
|
+
# takes the loop indices as its parameters; a block that names none is
|
|
222
|
+
# element-wise and belongs to jit_each
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
#### 16. 各数が十進で何桁かを `digits` へ (★★☆)
|
|
226
|
+
|
|
227
|
+
`ヒント: 無くなるまで 10 で割る。それは何回か`
|
|
228
|
+
|
|
229
|
+
```ruby
|
|
230
|
+
value = CA_INT32([7, 42, 1000, 65536])
|
|
231
|
+
digits = CArray.int32(4)
|
|
232
|
+
|
|
233
|
+
CArray.jit_for(4) { |i|
|
|
234
|
+
n = value[i]
|
|
235
|
+
count = 0
|
|
236
|
+
while n > 0 # 一周で終わるセルもあれば、五周するセルも
|
|
237
|
+
n = n / 10 # 整数除算、しかも Ruby のもの(床関数)
|
|
238
|
+
count = count + 1
|
|
239
|
+
end
|
|
240
|
+
digits[i] = count
|
|
241
|
+
}
|
|
242
|
+
digits.to_a #=> [1, 2, 4, 5]
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### 17. 各行で最初に 4.0 を超える列を `first` へ。無ければ -1 (★★☆)
|
|
246
|
+
|
|
247
|
+
`ヒント: 見るのをやめる`
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
rows = CA_DOUBLE([[1, 2, 9, 3], [5, 1, 1, 8]])
|
|
251
|
+
first = CArray.int32(2)
|
|
252
|
+
|
|
253
|
+
CArray.jit_for(2) { |i|
|
|
254
|
+
found = -1
|
|
255
|
+
(0...4).each { |j|
|
|
256
|
+
if rows[i, j] > 4.0
|
|
257
|
+
found = j
|
|
258
|
+
break
|
|
259
|
+
end
|
|
260
|
+
}
|
|
261
|
+
first[i] = found
|
|
262
|
+
}
|
|
263
|
+
first.to_a #=> [2, 0]
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
#### 18. 2x3 と 3x2 の積を受け取る (★★☆)
|
|
267
|
+
|
|
268
|
+
`ヒント: 繰り返される添字`
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
a = CArray.double(2, 3).seq!(1.0)
|
|
272
|
+
b = CArray.double(3, 2).seq!(1.0)
|
|
273
|
+
|
|
274
|
+
CArray.jit_contract { |i, j, k| a[i, k] * b[k, j] }.to_a
|
|
275
|
+
#=> [[22.0, 28.0], [49.0, 64.0]]
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### 19. 2x3 の配列二つについて、各行 `i` ごとの `x[i, k] * y[i, k]` の `k` についての和を受け取る (★★★)
|
|
279
|
+
|
|
280
|
+
`ヒント: 行の添字も繰り返されるが、和にしてはいけない`
|
|
281
|
+
|
|
282
|
+
```ruby
|
|
283
|
+
x = CA_DOUBLE([[1, 2, 3], [4, 5, 6]])
|
|
284
|
+
y = CA_DOUBLE([[1, 1, 1], [2, 2, 2]])
|
|
285
|
+
|
|
286
|
+
CArray.jit_contract(:b) { |k| x[b, k] * y[b, k] }.to_a
|
|
287
|
+
#=> [6.0, 30.0]
|
|
288
|
+
# `b` は呼び出しで名乗り、ブロック引数にはしない。両方は断られる
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### 20. 各セルと両隣の和を受け取る。端からはみ出すセルはゼロとして読む (★★☆)
|
|
292
|
+
|
|
293
|
+
`ヒント: 添字も extent も端も出てこない`
|
|
294
|
+
|
|
295
|
+
```ruby
|
|
296
|
+
a = CA_DOUBLE([1, 2, 3, 4])
|
|
297
|
+
|
|
298
|
+
CArray.jit_stencil(a, border: :zero) { |w| w[-1] + w[0] + w[1] }.to_a
|
|
299
|
+
#=> [3.0, 6.0, 9.0, 7.0]
|
|
300
|
+
# border: :zero, :clamp, :wrap は枠を計算し、:mask と :skip は枠のセル自体
|
|
301
|
+
# について答える
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### 21. 各セルを `out` へ。`UNDEF` はゼロに置き換えて (★★☆)
|
|
305
|
+
|
|
306
|
+
`ヒント: 一セルについて尋ねる`
|
|
307
|
+
|
|
308
|
+
```ruby
|
|
309
|
+
a = CA_DOUBLE([1, 2, 3])
|
|
310
|
+
a[1] = UNDEF
|
|
311
|
+
out = CArray.double(3)
|
|
312
|
+
|
|
313
|
+
CArray.jit_for(3) { |i| out[i] = a[i] == UNDEF ? 0.0 : a[i] }
|
|
314
|
+
out.to_a #=> [1.0, 0.0, 3.0]
|
|
315
|
+
# 欲しい答えが「伝播」なら何も書かない。マスクは入力側で OR され、出力へ
|
|
316
|
+
# 勝手に運ばれる
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
#### 22. 3x3 の中央の列に 1, 2, 3 を書く。他はそのまま (★★☆)
|
|
320
|
+
|
|
321
|
+
`ヒント: カーネルに列を渡す`
|
|
322
|
+
|
|
323
|
+
```ruby
|
|
324
|
+
table = CArray.double(3, 3)
|
|
325
|
+
column = table[nil, 1]
|
|
326
|
+
|
|
327
|
+
CArray.jit_for(3) { |i| column[i] = i + 1.0 }
|
|
328
|
+
table.to_a #=> [[0.0, 1.0, 0.0], [0.0, 2.0, 0.0], [0.0, 3.0, 0.0]]
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
#### 23. uint64 の配列を、ローカルの累算器で合計する。何に止められ、何で通るか (★★★)
|
|
332
|
+
|
|
333
|
+
`ヒント: リテラルは自分の幅を持たない`
|
|
334
|
+
|
|
335
|
+
```ruby
|
|
336
|
+
source = CArray.uint64(2).seq!(1)
|
|
337
|
+
out = CArray.uint64(1)
|
|
338
|
+
|
|
339
|
+
CArray.jit_for(1) { |i|
|
|
340
|
+
total = 0
|
|
341
|
+
(0...2).each { |j| total = total + source[j] }
|
|
342
|
+
out[i] = total
|
|
343
|
+
}
|
|
344
|
+
#=> CArray::JIT::Unsupported: `total` enters this loop as an Integer and comes
|
|
345
|
+
# back round as a uint64; the value carried to the next pass would change
|
|
346
|
+
# type, and one C variable is one type -- give it one type before the loop
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
```ruby
|
|
350
|
+
seed = CScalar.uint64() { 0 } # データ型を持つ値
|
|
351
|
+
|
|
352
|
+
CArray.jit_for(1) { |i|
|
|
353
|
+
total = seed
|
|
354
|
+
(0...2).each { |j| total = total + source[j] }
|
|
355
|
+
out[i] = total
|
|
356
|
+
}
|
|
357
|
+
out.to_a #=> [3]
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
#### 24. 後ろからの累積和 `out[i] = a[i] + out[i+1]`。`out[4]` は設定済み (★★★)
|
|
361
|
+
|
|
362
|
+
`ヒント: ループはどちら向きに走るべきか。そしてそれをどこで言うか`
|
|
363
|
+
|
|
364
|
+
```ruby
|
|
365
|
+
a = CA_DOUBLE([1, 2, 3, 4, 5])
|
|
366
|
+
out = CArray.double(5)
|
|
367
|
+
out[4] = a[4]
|
|
368
|
+
|
|
369
|
+
CArray.jit_for(3.step(0, -1)) { |i| out[i] = a[i] + out[i + 1] }
|
|
370
|
+
out.to_a #=> [15.0, 14.0, 12.0, 9.0, 5.0]
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
```ruby
|
|
374
|
+
out = CArray.double(5)
|
|
375
|
+
out[4] = a[4]
|
|
376
|
+
|
|
377
|
+
CArray.jit_for(0...4) { |i| out[i] = a[i] + out[i + 1] }
|
|
378
|
+
out.to_a #=> [1.0, 2.0, 3.0, 9.0, 5.0]
|
|
379
|
+
# 向きを述べる場所は extent だけで、間違って述べても断られない。どのセルも
|
|
380
|
+
# そこに残っていたゼロを読んだ
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
#### 25. `i` 番目のフィボナッチ数を `out[i]` へ。配列を読み返さず、ローカル二つを進めて (★★★)
|
|
384
|
+
|
|
385
|
+
`ヒント: 二つの名前が同時に変わる`
|
|
386
|
+
|
|
387
|
+
```ruby
|
|
388
|
+
out = CArray.int64(12)
|
|
389
|
+
|
|
390
|
+
CArray.jit_for(12) { |i|
|
|
391
|
+
a = 0
|
|
392
|
+
b = 1
|
|
393
|
+
i.times { |k| a, b = b, a + b }
|
|
394
|
+
out[i] = a
|
|
395
|
+
}
|
|
396
|
+
out.to_a #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
|
|
397
|
+
# 右辺の値はすべて、左辺に何かが書かれる前に確定する。だから
|
|
398
|
+
# `a + b` はこの回に入ってきたほうの `a` を読む。二行に分けて
|
|
399
|
+
# `a = b`、`b = a + b` と書くと、二行目は一行目が書いたばかりの
|
|
400
|
+
# `a` を読み、`a` はただ倍々になる: [0, 1, 2, 4, 8, ...]。断られ
|
|
401
|
+
# はしないし、このコンパイラのせいでもない。その二行は Ruby でも
|
|
402
|
+
# 同じ意味になる
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
#### 26. 0 と 1 の列で、1 が最も長く続いた長さ (★★★)
|
|
406
|
+
|
|
407
|
+
`ヒント: 反復を越えて残るものが二つあり、どちらも和ではない`
|
|
408
|
+
|
|
409
|
+
```ruby
|
|
410
|
+
flag = CA_INT32([0, 1, 1, 1, 0, 1, 1, 0])
|
|
411
|
+
run = CScalar.int32() { 0 }
|
|
412
|
+
best = CScalar.int32() { 0 }
|
|
413
|
+
|
|
414
|
+
CArray.jit_for(8) { |i|
|
|
415
|
+
run[] = flag[i] == 1 ? run[] + 1 : 0
|
|
416
|
+
best[] = run[] if run[] > best[]
|
|
417
|
+
}
|
|
418
|
+
best[0] #=> 3
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### 27. 各問い合わせについて、それを超えない最後の格子点の添字を `found` へ (★★★)
|
|
422
|
+
|
|
423
|
+
`ヒント: 格子は整列している`
|
|
424
|
+
|
|
425
|
+
```ruby
|
|
426
|
+
grid = CA_DOUBLE([0, 1, 4, 9, 16])
|
|
427
|
+
query = CA_DOUBLE([0.5, 5.0, 9.0, 12.0])
|
|
428
|
+
found = CArray.int32(4)
|
|
429
|
+
|
|
430
|
+
CArray.jit_for(4) { |i|
|
|
431
|
+
t = query[i]
|
|
432
|
+
low = 0
|
|
433
|
+
high = 4
|
|
434
|
+
while high - low > 1
|
|
435
|
+
middle = (low + high) / 2
|
|
436
|
+
if grid[middle] > t
|
|
437
|
+
high = middle
|
|
438
|
+
else
|
|
439
|
+
low = middle
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
found[i] = low
|
|
443
|
+
}
|
|
444
|
+
found.to_a #=> [0, 2, 3, 3]
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### 28. 配列から読んだ `bound[i]` まで数える。何に止められ、何で通るか (★★★)
|
|
448
|
+
|
|
449
|
+
`ヒント: 内側の range はループの前に分かっている`
|
|
450
|
+
|
|
451
|
+
```ruby
|
|
452
|
+
bound = CA_INT32([2, 3])
|
|
453
|
+
out = CArray.int32(2)
|
|
454
|
+
|
|
455
|
+
CArray.jit_for(2) { |i|
|
|
456
|
+
count = 0
|
|
457
|
+
(0...bound[i]).each { |j| count = count + 1 }
|
|
458
|
+
out[i] = count
|
|
459
|
+
}
|
|
460
|
+
#=> CArray::JIT::Unsupported: an inner loop's range is an integer expression
|
|
461
|
+
# over literals, captured scalars and the indices around it
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
```ruby
|
|
465
|
+
CArray.jit_for(2) { |i|
|
|
466
|
+
count = 0
|
|
467
|
+
j = 0
|
|
468
|
+
while j < bound[i] # データが決める上限を運ぶのは while
|
|
469
|
+
count = count + 1
|
|
470
|
+
j = j + 1
|
|
471
|
+
end
|
|
472
|
+
out[i] = count
|
|
473
|
+
}
|
|
474
|
+
out.to_a #=> [2, 3]
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
#### 29. 複素配列の二乗を `squared` へ、元の絶対値を `size` へ (★★☆)
|
|
478
|
+
|
|
479
|
+
`ヒント: 他と同じデータ型`
|
|
480
|
+
|
|
481
|
+
```ruby
|
|
482
|
+
z = CA_CMPLX128([Complex(0, 1), Complex(1, 1)])
|
|
483
|
+
squared = CArray.cmplx128(2)
|
|
484
|
+
size = CArray.double(2)
|
|
485
|
+
|
|
486
|
+
CArray.jit_each { squared = z * z }
|
|
487
|
+
CArray.jit_each { size = z.abs }
|
|
488
|
+
|
|
489
|
+
squared.to_a #=> [(-1.0+0.0i), (0.0+2.0i)]
|
|
490
|
+
size.to_a #=> [1.0, 1.4142135623730951]
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
#### 30. カーネルの中で引いた [0, 1) の乱数 10 万個で配列を埋める (★★☆)
|
|
494
|
+
|
|
495
|
+
`ヒント: Ruby の rand ではない。ループは GVL を手放して走る`
|
|
496
|
+
|
|
497
|
+
```ruby
|
|
498
|
+
random = CArray::Rng.new(seed: 3)
|
|
499
|
+
draws = CArray.double(100_000)
|
|
500
|
+
|
|
501
|
+
CArray.jit_for(100_000) { |i| draws[i] = random.random }
|
|
502
|
+
draws.mean.round(4) #=> 0.5006
|
|
503
|
+
# どの引きがどのセルに落ちるかはループの順序。そこが問題になるなら、先に
|
|
504
|
+
# CArray#random! で配列を埋めて、そのセルを読む
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
#### 31. int32 のセルを持つローカルを int64 の配列に二乗して書く。ローカルの C の型は? (★★★)
|
|
508
|
+
|
|
509
|
+
`ヒント: コンパイルされたものを読む`
|
|
510
|
+
|
|
511
|
+
```ruby
|
|
512
|
+
source = CArray.int32(4).seq!(1)
|
|
513
|
+
out = CArray.int64(4)
|
|
514
|
+
|
|
515
|
+
kernel = CArray.jit_for(4) { |i|
|
|
516
|
+
v = source[i]
|
|
517
|
+
out[i] = v * v
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
kernel.c_source.lines.grep(/int64_t v;/).first.strip
|
|
521
|
+
#=> "int64_t v;"
|
|
522
|
+
# and the assignment below it:
|
|
523
|
+
# v = (int64_t)*(int32_t *)(p_source + (i) * source_s0);
|
|
524
|
+
# `v = source[i]` の側は 64 ビットを要求していない。ローカルの型は本体全体
|
|
525
|
+
# から決まり、`v * v` が int64 の配列に着地する
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
次に行く先: 引くなら [06_Cheatsheet.md](06_Cheatsheet.md)、一機能一ファイルの
|
|
531
|
+
巡回なら [examples/features/](../examples/features)、これら全部を使って何かを
|
|
532
|
+
する program なら [examples/applications/](../examples/applications) —
|
|
533
|
+
`mandelbrot.rb` は 16 と同じく長さがセルごとに違うループ、`alarm.rb` は 25 をヒステリシス付きで、
|
|
534
|
+
`lookup.rb` は 26 を 50 万件の問い合わせで、`sieve.rb` は 27 を裏側から。
|