DCでのゴルフのヒント


18

DCでゴルフをするための一般的なヒントは何ですか?

dcは、C言語より前のUNIX / Linux用の計算ユーティリティです。DCプログラム(計算?)を短くする方法に興味があります。少なくともDCに少し固有の一般的な適用できるアイデアを探してい(たとえば、コメントを削除することは有益な答えではありません)

回答ごとに1つのヒントを投稿してください。


7
代わりにMarvelを使用してください。
魔法のタコUr

回答:


6

If-then-elseステートメント

我々は条件をチェックしたいとしa==b(てみましょうabそのそれぞれ名前のレジスタに格納します)。

編集:
[         # Everything is wrapped in one big macro
  [         # An inner macro for our *then* part
              # <-- Stuff to execute if a==b here
  2Q          # Then quit the inner and outer macro
]sE       # `E' is for Execution register ;)
la lb =E  # if a==b, execute E
          # if E is executed, it will quit the whole macro, so the rest is never reached:
          # <-- Stuff to execute if a!=b here
]x        # End macro; Execute

ましょう(foo)、凝縮の目的のために、プレースホルダーになります:

[[(then)2Q]sE(condition)E(else)]x

これが可能な限り最もコンパクトなifステートメントであることを確認してください(こちらも取り上げます)。


1
たぶん[[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI fスタートですか?tehnおよびその他のアクションはスタック上にあり、「If」マクロはそれらをスワップし、条件付きで調整されます。スタックの最上部が実行され、未使用のマクロがIにドロップされてスタックがクリーンアップされます。2 4比較するサンプルデータにすぎません。あるいは、[x]sIより読みやすいと考えられる場合、パーツを比較に移動できます[[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI ffスタックはその後きれいで、TATの例では、ちょうど...示さなければならない

1
Rosetta CodeのDcに関するページには3つのフレーバーが記載されてdcおり、OpenBSD dcif-then-else構造を見た最初のページでした。dcすべての主要なオペレーティングシステムで3つのフレーバーすべてを備えたファンバンドルが必要だと思います... o :-) ... if-then-else上記の私の提案dcは、rコマンドが欠けているため、オリジナルでは機能しません... :-(

1
何について: -else部分に到達する前に、すべてを[[(if)2Q]si(condition)i(else)]xマクロでラップし、if部分をその中の別のマクロでラップして、全体2Qから抜け出すことができます。したがって、1 == 1の場合に1を印刷し、その後1を印刷する場合は、2を印刷します1[[1P2Q]si1=i2P]x(ここでDCにアクセスできないため、テストされていません。しかしそれを見つけることができませんでした)
-daniero

うん、私は数学をやった、私の提案は短いです。同じ例と「表記法」で、空白を削除すると、[/*else*/]sE[[/*then*/]sE]sIlalb=IlExvs [[/*then*/2Q]sIlalb=I/*else*/]x-6バイトの違いになります。まだテストされていないtho:P
daniero

1
@danieroさん、すばらしい仕事です!時間があるときに投稿を更新しますが、必要に応じて更新することもできます。
ジョー

5

入力を保存するには d

dToS(スタックの最上部)を複製するを使用することで、入力を使用できるようにしながら、後で使用するために入力を移動できます。


@nooneishereかっこいい!!! ありがとう!
Rɪᴋᴇʀ

5

配列

初心者にとっては頭痛の種ですが、dc配列を提供します。次のように機能します。

value index :a    # store `value' in array linked to top of stack `a', with index `index'
      index ;a    # push a[index] on (main) stack

通常、最初の要素のインデックスは0です。配列は、SUDSIシーケンスのように、特にカウンタと組み合わせてシーケンスを操作する場合役立ちます。環境を破壊することなく特定の要素を選択したい場合、配列は必要な数のシャッフルの量(およびカウンターと比較の数)を減らすことができます。たとえば、多数の数値を配列に移動する場合は、z(スタックの深さ)またはz 1-インデックスとして使用し、要素を保存し、z == 0終了するかどうかを確認する再帰関数を作成できます。

[z 1- :a z 0 !=F]dsFx    # or I could just write such a function for you :)

次のことに注意してください。

  • 配列は、名前付きスタック上のインスタンスに関連付けられます。関連付けられた配列を持つスタックに新しい値をプッシュすると、その配列も「プッシュバック」され、「新しい」配列が代わりに使用されます。古い配列は、名前付きスタック上の対応する値も使用可能になるまで(つまり、スタックの最上部で)使用可能になります。これは複雑な概念であり、優れたアニメーションで説明する方がよいでしょう。
  • あなたは、することができます実際に対応する名前付きレジスタに値を押さずに名前の配列にものを格納します。ただし、これを行うと、残りのセッションではその名前のスタック/レジスタにアクセスできませんdcクラッシュします。
  • 名前付きスタックから値をポップすると、対応する配列の値は失われます。警告も、保護も、何もありません。消えただけです(これも便利です)。

DCのヒントは素晴らしい仕事です!
Rɪᴋᴇʀ

dc最近更新された可能性があり、クラッシュに関してアレイの動作がわずかに変更された可能性があります。現在どちらも確認できませんが、前回Linuxで使用したときは何かが違うと思います。
ジョー

1
設定されていない配列からインデックスを読み取ろうとすると、エラーではなく0が返されます。これは非常に便利ですが、配列に0を挿入する可能性がある場合にも注意する必要があります...インデックスが変更されたことをテストする別の方法が必要です。
brhfl

5

条件/マクロの代わりに0のn乗

ternaryのようなものが必要になる場合があります:

A == B ? C : D;

これを処理する良い方法は、@ Joeの回答で説明されています。しかし、もっとうまくやることができます:

0AB-^E*C+

ここで、EはD-Cです。

これは、2つの値の差の累乗を0にすることで、等しいかどうかをテストします。これは、等しい場合は1、それ以外の場合は0になります。残りは1または0を値CまたはDにスケーリングするだけです。n!= 1に対してdc0 0 = 1および0 n = 0を与えるため、これは機能します。


4

スタックから数字を破棄する必要がある場合があります。これを行う1つの方法は、単純に未使用の変数にポップすることstです。ただし、状況によっては、他のいくつかの場所、たとえば数値入力がなくなった場合の入力ベースや、精度が異なる場合に実行する操作がない場合は精度指定子にポップできます。前者の場合、を使用しますi。後者の場合、を使用しますk


数値出力が重要でない場合は、o使用することもできます。また、これらのいずれかが重要でない場合、ストレージとして使用することも、単に破棄することもできます- I/ K/ Oそれぞれを呼び出し、sa/ laなどでバイトを節約します。有効な値AFAIK:i2-16; k負でない整数。o1より大きい整数
brhfl

4

長計算:ZX、およびz

ZToSをポップし、数字の場合は桁数(10進数)をプッシュし、文字列の場合は文字数をプッシュします。これは、結果の長さの検出(出力のバッファリング)または文字列の長さの計算に役立ちます。数値の場合、Z整数部と小数部を組み合わせた長さをプッシュすることに注意してください。

XToSをポップし、数値の小数部の桁数をプッシュします。ToSが文字列だった場合、0プッシュされます。

整数部の桁数を見つけるには、を使用しますdZrX-。精度をdefaultから変更していない場合k==0、using 1/Zは短くなりますが、操作後に特定のゼロ以外の精度を維持する必要がある場合Kr0k1/Zrkは、かなり目障りです。

zスタック上のアイテムの数をプッシュします。私のお気に入りのコマンドの1つで、実際には値をポップしません!一連の数値を生成したり、カウンターをインクリメントしたりするために使用できます。zd繰り返し使用すると(たとえば、マクロの開始時に)、各自然数または整数の計算を昇順でテストできます。


zこれまでにこれを使用したことがありますが、カウンターのハックとして使用することは私には一度もありませんでした…すばらしい…
-brhfl

4

数字はAするFときに、異なる場所に(仮定入力ベースが10である)、それらは依然としてベース10の数字として効果的に治療されなければならないが15の数10の代わりに使用することができます。つまり、入力ベース10 FFが255を表すのではなく、(15 * 10) + 15165 を表すことになります。

実際には、これはすべての数字のために働く0F任意の入力ベースに2します16。入力ベースが5であれば、それから26Eだろう(2 * 5^2) + (6 * 5) + 14か、94。

この動作は、変更されていないGNUソースに対して有効です。ただし、@ SophiaLechnerが指摘しているように、RedHatベースのディストリビューションはbc-1.06-dc_ibase.patchを使用しているように見えるためibase - 1、実際の値に関係なく、数字> = ibaseがとして扱われます。TIO dc にはbc-1.06-dc_ibase.patchがないように見えます(Fedora 28¯_(ツ)_ /¯であっても)。


これは正しくありません-入力ベースの上の1桁は希望どおりに解釈されますが、リテラルに複数の数字、または小数点がある場合でも、ベースの無効な数字は(base-1)として解釈されます。したがって、入力ベース10はをFF表し99、入力ベース5 26Eは、244ベース10 と同じ74です。
ソフィア・レヒナー

@SophiaLechnerよろしいですか?tio.run/##S0n@/9/QIJ/L0CCTy82tgMs0k8vIzLXg/38A どのdcバージョンを実行していますか?私はMacOSの上でUbuntuとGNU DC 1.3にGNU DC 1.4.1を使用しています
デジタルトラウマ

面白い。Red Hatで1.3.95を実行しています。サンプルプログラムは次のとおりです。[slechner @ XXX] $ dc -e '10o 10i FFp 5i 26Ep' 99 74 [slechner @ XXX] $ dc --version dc(GNU bc 1.06 .95)1.3.95
ソフィア・レヒナー

ああ...コメントでコードブロックを動作させることはできません。ポイントは、1.3.95 でFFp出力99することです。あなたのMacOSバージョンでこれを確認できますか?
ソフィア・レヒナー

1
確実なこと!すべての研究をありがとう。
ソフィア・レヒナー

2

すぐに実行する関数マクロ(を使用しますF)を初期化するときdsFxは、のようなものを使用しますsFlFx。同じことが変数に対しても機能します:dsaではなくsala

格納と読み込みの間に他の処理を行う必要がある場合(例sa[other stuff]la:)、上記が実行可能かどうかを検討してください:他の操作の前にスタックに値を残すと、最後まで戻りますそれらの操作の?


2

偶然これを発見しました。ゼロを生成するさらに別の方法:_

_次の数字が負の数であることを示すdcへの信号です。例:

_3 # pushes -3

しかし、数字に従っていない場合はどうでしょうか?

_ # pushes 0...sometimes

これは、アンダースコアに続く次の非空白文字が数字ではない場合に機能します。改行の後でも数字が続く場合は、負符号として解釈されます。

c4 5_6  # -6,5,4
c4 5_ 6 # -6,5,4
c4 5_
6       # -6,5,4 # still a negative sign since the next thing it sees is a digit
c4 5_z  #  3,0,5,4 # if it's followed by a non-digit, it's a 0
c4 5_p6 #  6,0,5,4
c4 _*   #  0 # 4*0=0

1

スタック全体の内容をプログラムの最後に印刷する必要がある場合、再帰マクロループを使用してこれを実現できます。ただし、単にfコマンドを使用する方がはるかに短いです。


1

dc一度に1行ずつ入力を読み取ります。複数のアイテムを読み込む必要がある場合、1行に1つずつ?読み込むには、すべての行を読み込むか、面倒なマクロループが必要です。代わりに、すべての入力項目をスペースで区切られた1行に配置できる場合、1つの入力項目がすべての入力項目?を読み取り、各項目をスタックにプッシュします。

たとえば、ではseq 10 | dc -e'?f'seq整数1〜10を1行に1つずつ出力します。?ただ最初に読み込まれます1ときに出力されるfスタック全体をダンプします。ただしseq 10 | tr '\n' ' ' | dc -e'?f'trでは、入力整数がすべてのスペースで区切られます。この場合、?は行からすべての整数を一度に読み取り、すべてfを出力します。


1

演算子がソースから制限されている場合、新しい演算子を作成します a

何度か便利になったのは、特定の演算子の使用を避けることです。演算子のASCII値をプッシュし、aそれを使用して文字列に変換し、s後でマクロとして実行されるレジスタに保存します。オン。たとえば、私は除算を行う必要がありますが、キャラクターの使用を許可されないか、使用を避けようとしています/。代わりにできます47asdし、将来的に16を4で割る必要があるときにできます16 4 ldx

  • これは、1文字の演算子(文字列を作成できない)でのみ機能しs、何かで後置する必要があるようなコマンドでは機能しません。
  • これはかなりのバイトを追加するため、特定のキャラクターを避ける必要がある場合、または何らかの理由でスコアボーナスが得られる場合にのみ適しています。

1

空白を避ける

空白を回避することは、いくつかの課題で発生し、一般的には簡単ですdc。文字列は別として、空白が必要になる非常に具体的な時間は、連続して複数の数字をプッシュするときです1 2 3。これを避ける必要がある場合:

  • 間にある空のマクロを実行します1[]x2[]x3[]x
  • 角かっこがテーブルから外れている場合は、事前にマクロのNOPを保存、その間で35asn実行1lnx2lnx3lnxます:。

dc: ',' (054) unimplemented警告に耐える場合は、コンマで区切った番号を使用することもできます。
デジタル外傷

私はそのことを考えていなかった-おそらくコマンドへの決意...面白い...ないそのトークン与えいずれにも適用される
brhfl
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.