dc
のマンページにあるこの例を理解できません。
$ dc
1 0:a 0Sa 2 0:a La 0;ap
1
私にとって答えは2でなければなりません:
1 0:a
ここでは、配列a
の0番目の位置に1を格納します。
0Sa
次に、レジスタa
のスタックに0をプッシュします。
2 0:a
ここでも、配列a
の0番目の位置に2を格納します。これにより、その位置に格納されていた前の1が上書きされます。
La
次に、レジスタa
のスタックに格納されている0をポップし、メインスタックにプッシュします。
0;a
ここで、もう一度0をメインスタックにプッシュし、それをポップして配列インデックスとして使用するため、配列a
の0番目の場所に格納されている2をメインスタックにプッシュします。
p
メインスタックの一番上である2を出力します。したがって、答えは2になります。
何が足りないのですか?
PS- dc
をタグとして使用したかったのですが、存在しないようで、少なくとも1つのタグを使用する必要があるため、debian
(私のワークステーションOS)を使用しました。
配列とスタックを混合する場合と同じです。この例では、レジスタa
が配列とスタックの両方として使用されています。
1 0:a
0 Sa
2 0:a
La
0;a p
:a
-レジスタaは配列として扱われます。Sa
--register aはスタックとして扱われます。実際には、配列をpt 1.から下にプッシュし、new配列を作成します。 man
のように:レジスタのスタックされた各インスタンスには独自の配列が関連付けられていることに注意してください。:a
--register aはarrayとして扱われます。前の値と最初の配列値を押し下げます。La
--register aはstackとして扱われます。最初に到達するにはstacked arraya[0]=2
は配列であるため破棄されます。;a
--register aはarrayとして扱われます。これで、残っている値は1つだけになり、最初の配列値がaに追加されます。これは1
です。いくつかの例については回答の最後にあります。
"レジスタごとにいくつの配列とスタックがありますか? 1つのレジスタに1つのスタックと1つの個別の配列があると思いました。"
dc
のスタックは、プッシュダウンスタックまたはLIFO(後入れ先出し)です。レストランのプレートと同じです。
,------ pop / Push - take / leave
/
|
v
[-----] top
[-----] ... ... .
[-----] [-----] [-----] ..
(main) (register-a) (register-b) ...
mainスタックまたはworkスタックがあります。これは、レジスタを要求する操作が指定されていない限り使用されます。各レジスタには独自のスタックがあります。
Sr
:pop one value from main stack and Push it into stack r
。両方のスタックが変更されました。Lr
:pop oner
で指定されたレジスタスタックからの値Pushそれをmainスタックにプッシュします。両方のスタックが変更されました。sr
:pop onemainスタックからの値およびwriteそれを登録するr
。実際には、レジスタr
で指定されたスタックの最上位の値を変更します。そのスタックに値がない場合は、追加します。 mainスタックが変更されました。 スタックの登録変更された値の横に保持されます。lr
:readレジスタr
からの値。事実上、複数ある場合は最上位の値です。 main変更されました。 スタックの登録保存されます。:r
:pop two value from mainスタックし、レジスタr
の配列の2番目の値を格納する場所のインデックスとして最初の最上位を使用します。 main変更されました。 スタックの登録保存されます。;r
:pop oneスタックからの値mainスタックから、r
で指定されたレジスタ内の現在の配列から読み取るインデックスとして使用します。 main変更されました。 スタックの登録保存されます。見る1つの方法はペアです。開始すると、すべてのレジスタが空になります。 Sr
によって要素をスタックに追加すると、hideそのスタック内の基礎となる要素がすべて追加されます。あなたがするように言う:
1 Sx
2 Sx
4 Sx
x = (S) 4 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
これで、changeレジスタの値x、つまり;最上位の要素をsx
で変更すると、スタック内の要素の数を変更せずにlx
で読み取ることができます。
lx p # Read value in register x - in effect read topmost element from stack.
4 # Printed value by p.
3 sx # Change value in register x - in effect change topmost element in stack.
x = (S) 3 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
配列要素を追加することにした場合、物事はより複雑な方向に進み始めます。
4 1:x
5 2:x
x = [A]
[2]=5 VISIBLE
[1]=4 VISIBLE
(S) 3 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
これで、スタック内のcurrent配列に値が追加されました。 [〜#〜] visible [〜#〜]要素を読み取って変更できます。
44 1:x
55 2:x
33 sx
1;x p # Read and print index 1
44
lx p # Read and print stack top.
33
x = [A]
[2]=55 VISIBLE
[1]=44 VISIBLE
(S) 33 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
その場合、addスタック要素は、その上の配列に値を追加したため、stack frameは展開不可能であると言うことができます。したがって、新しいスタックフレームが追加されます。
6 Sx
7 Sx
x = (S) 7 VISIBLE
(S) 6 HIDDEN
[A]
[2]=55 HIDDEN
[1]=44 HIDDEN
(S) 33 HIDDEN
(S) 2 HIDDEN
(S) 1 HIDDEN
last配列にアクセスしようとすると、非表示になります。実際には、空の配列から読み取り、結果はデフォルト値0
になります。レジスタ値7をsr
で変更できますが、上記の2つのスタック要素を削除しない限り、2レベル下の配列にアクセスすることはできません。
ここでいくつかの配列要素を追加することにした場合、それらは最上位のスタック要素とともに(ペアの配列として)配置された新しい配列に追加されます。
8 1:x
9 2:x
x = [A]
[2]=9 VISIBLE
[1]=8 VISIBLE
(S) 7 VISIBLE
(S) 6 HIDDEN
[A]
[2]=55 HIDDEN
[1]=44 HIDDEN
(S) 33 HIDDEN
(S) 2 HIDDEN
(S) 1 HIDDEN
Nowスタックのpopを実行すると、7がポップされますが、配列があるため間(いわば)それも削除されます。
Lx p # Pop + print top stack element.
7 # Value printed.
x = (S) 6 VISIBLE
[A]
[2]=55 HIDDEN
[1]=44 HIDDEN
(S) 33 HIDDEN
(S) 2 HIDDEN
(S) 1 HIDDEN
8および9の配列はなくなりました。値が6のスタック要素が表示されます。ただし、基になるアレイはブロックされます。 1;x p
による読み取りyield 。
ある意味では、スタック要素はブロックされていますが、配列は不透明であると言えます。配列は、スタック要素に対してhanging onのようなものです。
stackからさらに別のpopを実行して、基になるスタック要素+配列を明らかにする必要があります。
Lx p # Pop + print top stack element.
6 # Value printed.
x = [A]
[2]=55 VISIBLE
[1]=44 VISIBLE
(S) 33 VISIBLE
(S) 2 HIDDEN
(S) 1 HIDDEN
結論として、配列とスタックの数はレジスタごとに1つに制限されていないと言えます。
– レジスタごとにいくつの配列とスタックがありますか?
–そのレジスタで実行するSr
操作と:r
操作の交互の数によって異なります。
別の見方をすれば、スタックは1つだけですが、複数の配列がありますiff配列要素の追加の間にスタック要素を追加します...
さらに別の言い方をすれば、現在の配列はいつでもそうではないということです。
[register][array]
だが
[register][stack-element][array]
これは:
[register][stack-element][array][...]
[register][stack-element][array][1]
[register][stack-element][array][0]
また、stack-element
部分は不透明、読み取り専用などです。ただし、その場合は、スタック要素の値は必要ないことも覚えておく必要があります。配列値をレジスタに追加するだけでOKです。
または、各スタック要素は、変更可能なゼロで埋められた配列とペアになっています。
1 Sx
2 Sx
3 Sx
4 1:x
5 2:x
6 Sx
7 Sx
8 1:x
9 2:x
x = (S) 7 + A[0]=0 A[1]=8 A[2]=9 A[3]=0 ... A[2048]=0
(S) 6 + A[0]=0 ... A[2048]=0
(S) 33 + A[0]=0 A[1]=4 A[2]=5 A[3]=0 ... A[2048]=0
(S) 2 + A[0]=0 ... A[2048]=0
(S) 1 + A[0]=0 ... A[2048]=0
それがもう少し明確になったことを願っています。
$ dc
[ein] 0:a
[zwei] Sa
[drei] 0:a
0;ap # Copy + print index 0 of topmost array in register a
drei
Lap # Throws away [drei] and pops+prints first element in stack*
zwei
0;ap # Copy + print index 0 of first array
ein
$ dc
[uno] 0:a # Array a(1)
[dos] 1:a # Array a(1)
[tres] 2:a # Array a(1)
[cuatro] Sa # Array a(2)
[cinco] Sa # Array a(2)
[seis] Sa # Array a(2)
[siete] 0:a # Array a(3)
[ocho] 1:a # Array a(3)
[nueve] 2:a # Array a(3)
Laf # Throws away Array 3 to get to first stack array, Array 2.
seis
Laf
cinco
seis
Laf
cuatro
cinco
seis
2;af # Now we're at the first array, Array 1.
tres
cuatro
cinco
seis
1;af
dos
tres
cuatro
cinco
seis
0;af
uno
dos
tres
cuatro
cinco
seis
dc
はコンパイラーであり、非常に古いコンパイラーであることを覚えておく必要があります。これは一種の機械語であり、スタック指向の計算機です。それはかなり強力ですが、そのインターフェースはあなたのために設計されていません-それはあなたが他の言語で書いた命令を効率的に処理するように設計されています。
dc
は、直感的な方法でデータを保存しません。 dc
stuffs stuff。すぐに実行されない場合に新しい入力を読み取るとき、値はスタックに投げられるだけです。スタック内のすべてのものはすでにプッシュダウンされています-一番上が最新で一番下が最も古いです。最も古いスタックメンバーを取得するには、最新のスタックメンバーを処理する必要があります。
多くの人がそれだけ得ることができます。結局のところ、スタックはそれほど奇妙ではありません-それは一種の洗濯かごのようなものです。しかし、それもかなり1次元であり、dc
はそれよりもはるかに進んでいます。
つまり、入力スタック、つまりメインスタックがあります。これは、dc
のすべての命令入力と出力がデフォルトで行われる場所です。それはあなたがそれにコマンドを与えるときにあなたが働くものです。しかし、他のすべてのレジスターもあります-少なくとも256個です。これらのそれぞれは、それ自体へのスタックでもあります。
通常、レジスタは[Ss]
aveコマンドと[Ll]
oadコマンドを使用して操作します。メインスタックの最上位の値をスカラー値としてレジスタa
に保存するには、sa
を実行します。その後、l
を使用して、いつでもこのスカラー値をメインスタックの最上位にla
oadして戻すことができます。さて、レジスタa
の現在のインスタンスが最新のままである限り、つまり、可能です。
old-スカラー値が残っている-の上にレジスタa
のnewスカラーインスタンスを作成するには、Sa
を使用できます。このコマンドはメインスタックをポップし、レジスタa
スタックをスタックします。 la
とは異なり、La
コマンドはレジスタの破壊的なL
oadです-そのコマンドでスカラー値がメインスタックにポップされると、レジスタのそのインスタンス内のすべてが破棄され、レジスタの以前のインスタンスに再びアクセスできるようになります。
それだけでも、少し練習すれば簡単に理解できます。メインスタックと同じですが、レジスタごとに1つずつあります。しかし、各レジスタにはさらに別の次元があります-それらの配列です。
各レジスタの各インスタンスは配列を取得します。デフォルトのサイズは1つあたり2048インデックスだと思いますが、スタックがどれだけ深くなるのか疑問に思うことがよくあり、かなり深いとしか言えません。レジスタの新しいスカラー値をインスタンス化するときは、そのスカラー値をプッシュダウンするだけでなく、その配列もプッシュダウンします。新しいインスタンスには新しい配列があり、古いインスタンスの配列はそのまま残り、新しいインスタンスをポップした後のスカラー値と同じようにアクセスできます。
配列インデックスへのアクセスには少し注意が必要です。そもそも、ほとんどすべてのメインスタック操作はとにかく破壊的です。また、配列インデックスにアクセスする唯一の方法は、メインスタックからその値を取得して、それを呼び出すことです。インデックス参照はその時点で破棄されるため、思い出すのが難しい場合があります。 o
とO
は、インデックスカウンターを保持するのに役立ちますが、インデックス1または0で試さないでください。
とにかく、レジスタの配列とそのスタックは独立していませんが、むしろ相互依存して多次元です。練習と忍耐、そして少し超人間的な決意があれば、奇妙にクールなことができます。幸運を。
同じ質問に遭遇しましたが、manページ自体の例を囲むテキストを注意深く読み直すだけで十分でした。
:r Will pop the top two values off of the stack. The old sec-
ond-to-top value will be stored in the array r, indexed by
the old top-of-stack value.
;r Pops the top-of-stack and uses it as an index into the array
r. The selected value is then pushed onto the stack.
Note that each stacked instance of a register has its own array
associated with it. Thus 1 0:a 0Sa 2 0:a La 0;ap will print 1,
because the 2 was stored in an instance of 0:a that was later
popped.
ここの最後の段落はあなたの質問に完全に答えます。 2は、後でポップされた0:aのインスタンスに格納されました(Laがレジスタaのスカラー値をメインスタックに配置すると、サイレントに破棄されます)。