当サイトの一部ページには、アフィリエイト・アドセンス・アソシエイト・プロモーション広告を掲載しています。

Amazonのアソシエイトとして、Security Akademeiaは適格販売により収入を得ています。

広告配信等の詳細については、プライバシーポリシーページに掲載しています。

消費者庁が、2023年10月1日から施行する景品表示法の規制対象(通称:ステマ規制)にならないよう、配慮して記事を作成しています。もし問題のある表現がありましたら、問い合わせページよりご連絡ください。

参考:令和5年10月1日からステルスマーケティングは景品表示法違反となります。 | 消費者庁

Add、Sub、Neg、And、Or【NandGame編】

2023年11月28日

スタックを演算に利用する

スタックを使えば、特定のレジスターに依存しないマクロ演算(加算や減算など)を実現できます。

代わりに、演算はオペランドをスタックからPOPし、演算結果をスタックにPUSHし直します。

この方法だと、利用可能なレジスターの数に制限されないので、任意の複雑な計算ができます。

Addレベル

Addレベルのゴールは、スタックで加算を実現することです。

スタックに2つの値をPOPして、それらを加算してから、その合計値をスタックにPUSHします。

Addレベルを解く

POP_D
POP_A
D = D + A
PUSH_D

スタックからPOPした値を2つのレジスターにセットします。

※1~2行目は逆でも構いません。

レジスターの値を加算したら、PUSHでスタックに戻します。

その際、マクロPUSH_Aは存在しませんので、計算結果はレジスターDに入れてから、PUSH_Dを呼び出します。

Subレベル

Subレベルのゴールは、スタックで減算を実現することです。

スタックから2つの値をPOPし、2つ目の値から1つ目の値を引きます(最初にPOPした値が引く値、後にPOPした値が引かれる値になる)。計算結果はスタックに戻します。

Subレベルを解く

Addレベルのアセンブリーコードでは加算でしたが、代わりに減算すればよいだけです。

ただし、1点だけ注意が必要です。加算では足す側と足される側を区別しなくても計算結果は変わりませんが、減算はそういきません。Subレベルに要求されていたのは、後からPOPされる側が引かれる数ということです。

POP_D
POP_A
D = A - D
PUSH_D

初回のPOPはレジスターD、次のPOPはレジスターAにセットしていているため、3行目のように「D = A – D」とする必要があります。

Negレベル

Negレベルのゴールは、スタックを使って算術否定を実現することです。算術否定とは、符号を逆転することを意味します。例えば、2の(算術)否定は-2になります。

Negレベルを解く

POP_D
D = - D
PUSH_D

Andレベル

Andレベルのゴールは、スタックでAND演算を実現することです。

スタックから2つ値をPOPして、ビットごとのAND演算(ここでは16ビットなので16ビットAND演算)を実行し、計算結果をスタックに戻します。

Andレベルを解く

NandGameのアセンブリー言語では、AND演算のために&演算子を使います。

POP_D
POP_A
D = D & A
PUSH_D

Orレベル

Orレベルのゴールは、スタックでOR演算を実現することです。

スタックから2つ値をPOPして、ビットごとのOR演算(ここでは16ビットなので16ビットOR演算)を実行し、計算結果をスタックに戻します。

Orレベルを解く

NandGameのアセンブリー言語では、AND演算のために|演算子を使います。

POP_D
POP_A
D = D | A
PUSH_D