ヒューマン・リソース・マシーン 攻略 入社20年目 掛け算のしかた
ここで解説している内容なりヒントなりはあくまで筆者の解法に基づいたものなので、別の考え方ももちろんあるよ。ってのは念頭に置いてください。
課題
左側の数値を2つごとに、掛け算を行った結果を右側へ運んでください。
この課題では0以上の数値だけが運ばれてきます。
使用可能な命令
- inbox
- outbox
- copyfrom
- copyto
- add
- sub
- bump+
- bump-
- jump
- jump_if_zero
- jump_if_neg
効率目標
- サイズ:15行
- スピード:109ステップ
ヒント
その1
掛け算を加算だけで定義するとどうなる?
その2
19年目で実施したカウントダウンは、カウンタって概念。
処理のたびにカウントダウンすると、0になった時 = カウンタの回数分処理を繰り返した時 になる。
その3(スピード目標)
0は何を掛けても0になる。
その4(スピード目標)
ループ回数は少ない方が処理が早い。
大きさの比較は14年目で実施済み
回答例 + 解説
サイズ
回答例 + 解説
1. jump:ラベル1へ ラベル2:// 計算結果を運ぶ 2. copyfrom hello 3. outbox ラベル1:// 1セットの開始位置 4. copyfrom zero! 5. copyto hello 6. inbox 7. copyto A 8. inbox 9. copyto B ラベル3:// 加算 10. jump_if_zero:ラベル2へ 11. copyfrom hello 12. add A 13. copyto hello 14. bump- B 15. jump:ラベル3へ
掛け算 = A を B回 加算 なので、そのままAをB回加算する処理を組む。
B回繰り返す = 処理するたびにBを減算し0になったら処理を終了。
この時、0から開始するように毎回初期化(計算結果=0)してから、加算処理を始めるようにする。
初期値として0を取得(copyform zero!)して、計算結果を保持する場所に設定(copyto hello)
左のパネルを取って(inbox)、Aとして保持(copyto)
次のパネルを取って(inbox)、Bとして保持(copyto)
Bをカウンタとして、0(=B回分処理した)なら(jump_if_zero)、計算結果を手元に用意して(copyfrom)、運ぶ(outbox)。
0じゃないなら、今の計算結果(copyfrom)にAを加算(add)して計算結果を保持(copyto)。
カウンタを更新して(bump-)、B回分処理を繰り返す(jump)
この時、例によって無駄なジャンプが発生しないようにoutboxとinboxがつながるように配置して、初回の無駄処理(inboxより前)は実行しないように飛ばす(jump)。
スピード
回答例 + 解説
1. jump:ラベル1へ ラベル3:A=0の時の特別処理 2. inbox 3. copyfrom zero! 4. jump:ラベル4へ ラベル2:// 計算結果を取得 5. copyfrom hello ラベル4:// 右側へ運ぶ 6. outbox ラベル1:// 1セットの開始位置 7. inbox 8. jump_if_zero:ラベル3へ 9. copyto A 10. inbox 11. jump_if_zero:ラベル4へ 12. copyto B 13. sub A 14. jump_if_neg:ラベル5へ 15. copyfrom B ラベル6:// AをカウンタとしてBで加算を行う 16. copyto hello 17. bump- A 18. jump_if_zero:ラベル2へ 19. copyfrom hello 20. add B 21. jump:ラベル6へ ラベル5:// Aの方が大きい 22. copyfrom A ラベル7:// BをカウンタとしてAで加算を行う 23. copyto hello 24. bump- B 25. jump_if_zero:ラベル2へ 26. copyfrom hello 27. add A 28. jump:ラベル7へ
サイズ目標を満たしている前提で、そこからの変更点を
処理を早くするために省ける行程は省く。
* A=0ならBは即捨てて0を運ぶ。B=0ならそのまま運ぶ
* 0のことは↑で考慮出来てるため、毎回実施していた初期化も要らない
* ループ回数を減らすために、数が少ない方をカウンタとして、数の大きい方で加算を行う
左のパネルをとって(inbox)、0ならA=0用の特別処理(jump_if_zero)。 * A=0用の特別処理 数合わせのためにパネルを取って(inbox)、0を運ぶ(copyfrom zero!)
0じゃないなら、Aとして一旦保持(copyto)
次のパネルをとって(inbox)、0なら(jump_if_zero)運ぶ(outbox)
0じゃないなら、Bとして一旦保持(copyto)
Aとの大きさを比較して(sub)、Aの方が大きいなら(jump_if_neg)、Aで加算処理
Bの方が大きいならBで加算処理
* 加算処理
初回の加算として、加算対象(copyfrom)を計算結果に保持(copyto hello)
カウンタを更新して(bump-)0なら(jump_if_zero)、計算結果を手元に用意して(copyfrom)、運ぶ(outbox)。
0じゃないなら、今の計算結果と加算対象の合算(copyfrom hello -> add)を繰り返す(jump)。