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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +771 -3
  3. data/README.md +7 -6
  4. data/carray-jit.gemspec +1 -3
  5. data/docs/00_Introduction.md +4 -3
  6. data/docs/01_GettingStarted.md +1 -1
  7. data/docs/02_KernelShapes.md +93 -14
  8. data/docs/03_SupportedFeatures.md +582 -26
  9. data/docs/04_Compiling.md +33 -6
  10. data/docs/05_DesignNotes.md +3 -3
  11. data/docs/06_Cheatsheet.md +198 -5
  12. data/docs/07_StepByStep.ja.md +534 -0
  13. data/docs/07_StepByStep.md +535 -0
  14. data/examples/README.md +12 -0
  15. data/examples/applications/alarm.rb +121 -0
  16. data/examples/applications/collatz.rb +105 -0
  17. data/examples/applications/cubic_spline.rb +331 -0
  18. data/examples/applications/dithering.rb +144 -0
  19. data/examples/applications/group_stats.rb +115 -0
  20. data/examples/applications/lookup.rb +126 -0
  21. data/examples/applications/median_filter.rb +153 -0
  22. data/examples/applications/parcel_ascent.rb +220 -0
  23. data/examples/applications/point_in_polygon.rb +111 -0
  24. data/examples/applications/random_walk.rb +98 -0
  25. data/examples/applications/van_der_pol.rb +186 -0
  26. data/examples/applications/wet_bulb.rb +140 -0
  27. data/examples/features/10_complex.rb +14 -4
  28. data/examples/features/15_loops.rb +7 -1
  29. data/lib/carray/jit/access.rb +14 -0
  30. data/lib/carray/jit/analyzer.rb +2077 -136
  31. data/lib/carray/jit/block_reader.rb +37 -6
  32. data/lib/carray/jit/c_function.rb +613 -76
  33. data/lib/carray/jit/c_generator.rb +1595 -156
  34. data/lib/carray/jit/call.rb +68 -0
  35. data/lib/carray/jit/compiler.rb +75 -11
  36. data/lib/carray/jit/kernel.rb +369 -32
  37. data/lib/carray/jit/node.rb +359 -9
  38. data/lib/carray/jit/sorting_networks.rb +182 -0
  39. data/lib/carray/jit/type_assignment.rb +371 -34
  40. data/lib/carray/jit/version.rb +1 -1
  41. data/lib/carray/jit.rb +560 -64
  42. metadata +22 -8
  43. data/ext/carray_jit_access/carray_jit_access.c +0 -460
  44. 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 を裏側から。