Conseils pour jouer au golf en DC

18

Quels conseils généraux avez-vous pour jouer au golf en DC ?

dc est un utilitaire de calculatrice pour UNIX / Linux qui est antérieur au langage C. Je souhaite savoir comment raccourcir mes programmes DC (calculs?). Je cherche des idées qui peuvent être appliquées au qui sont au moins un peu spécifiques au DC (par exemple, supprimer des commentaires n'est pas une réponse utile)

Veuillez poster un pourboire par réponse.

mriklojn
la source
7
Utilisez plutôt Marvel.
Magic Octopus Urn du

Réponses:

6

Instructions if-then-else

Supposons que nous voulons vérifier la condition a==b(laisser aet bêtre stockés dans leurs registres respectivement nommés).

Éditer:
[         # 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

Soit (foo)un espace réservé, dans le but de condenser:

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

Je suis sûr que c'est la déclaration la plus compacte possible (également présentée ici ).

Joe
la source
1
C'est peut [[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI f- être un début? Les actions pour tehn et autres sont sur la pile, la Imacro " f" les échange et est appelée conditionnellement. alors le haut de la pile sera exécuté et la macro inutilisée sera déposée dans I pour nettoyer la pile. 2 4ne sont que des exemples de données à comparer. En variante , la [x]sIpartie peut être déplacée à la comparaison, si cela est jugé plus lisible: [[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f. Le fdans les exemples montrera juste que la pile est propre après ...
1
La page de Rosetta Code sur Dc mentionne 3 saveurs de dcet c'était la 1ère page où j'ai vu dcla if-then-elseconstruction d' OpenBSD . Je pense que nous avons besoin d'un dcensemble de fans avec les 3 versions pour tous les principaux systèmes d'exploitation ... o :-) ... et ma if-then-elseproposition ci-dessus ne fonctionne pas sur l'original dccar il manque la rcommande ... :-(
1
Qu'en est-il de: [[(if)2Q]si(condition)i(else)]x- envelopper le tout dans une macro, et la partie if à l'intérieur d'une autre macro à l'intérieur, afin que vous puissiez vous 2Qéloigner du tout avant d'atteindre la partie else. Donc, si vous voulez faire si 1 == 1 puis imprimer 1 sinon imprimer 2 , ce serait 1[[1P2Q]si1=i2P]x(non testé car je n'ai pas accès à dc ici et maintenant. J'étais également sûr d'avoir fait cette astuce dans une réponse ici avant mais je
n'ai
Ouais, j'ai fait le calcul, ma suggestion est plus courte. Avec le même exemple et la "notation", et en supprimant les espaces, c'est une différence de [/*else*/]sE[[/*then*/]sE]sIlalb=IlExvs [[/*then*/2Q]sIlalb=I/*else*/]x- 6 octets. Tho encore non testé: P
daniero
1
Beau travail, @daniero! Je mettrai à jour le message lorsque j'en aurai le temps, ou vous pouvez le faire si vous le souhaitez.
Joe
5

Vous pouvez enregistrer une entrée avec d

En utilisant d, qui duplique le ToS (haut de la pile), vous pouvez déplacer l'entrée pour une utilisation ultérieure, tout en étant capable de l'utiliser.

Rɪᴋᴇʀ
la source
@NoOneIsHere oh cool !!! Merci!
Rɪᴋᴇʀ
5

Tableaux

Bien qu'ils soient un casse-tête pour les débutants, dcpropose des tableaux. Ils fonctionnent comme ceci:

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

Comme d'habitude, le premier élément a l'index 0. Les tableaux peuvent être utiles lorsque vous travaillez avec des séquences, comme dans la séquence SUDSI , en particulier en combinaison avec des compteurs. Les tableaux peuvent réduire la quantité de mélange de nombres que vous devez faire (et le nombre de compteurs et de comparaisons) si vous souhaitez sélectionner un élément particulier sans détruire votre environnement. Par exemple, si vous souhaitez déplacer une pile de nombres dans un tableau, vous pouvez écrire une fonction récursive qui utilise z(profondeur de pile) ou z 1-comme index, stocke l'élément et vérifie s'il z == 0doit se terminer lui-même.

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

Soyez conscient des points suivants:

  • Les tableaux sont associés aux instances sur des piles nommées. Si vous poussez une nouvelle valeur sur une pile à laquelle un tableau est associé, ce tableau sera également "repoussé" et un "nouveau" tableau prendra sa place. L'ancien tableau ne sera utilisable que lorsque la valeur correspondante sur la pile nommée sera également utilisable (c'est-à-dire au-dessus de sa pile). C'est un concept compliqué qui serait mieux expliqué avec une bonne animation, qui me dépasse.
  • Vous pouvez stocker des éléments dans un tableau nommé sans réellement pousser une valeur dans le registre nommé correspondant. Toutefois, si vous procédez ainsi, vous ne pouvez pas accéder à la pile / au registre portant ce nom pour le reste de la session. dcva planter.
  • Si vous supprimez une valeur d'une pile nommée, toutes les valeurs du tableau correspondant seront perdues - pas d'avertissement, pas de protection, rien. Je viens de partir (ce qui peut aussi être utile).
Joe
la source
Beau travail avec les astuces DC!
Rɪᴋᴇʀ
dcpeut avoir été mis à jour récemment et le comportement du tableau peut avoir légèrement changé en ce qui concerne le plantage. Je ne peux pas confirmer non plus pour le moment, mais je pense que quelque chose était différent la dernière fois que je l'ai utilisé sur Linux.
Joe
1
Si vous essayez de lire un index à partir d'un tableau qui n'a pas été défini, vous obtenez 0 et pas une erreur. Ce qui peut être très utile, mais vaut également la peine d'être pris en compte si vous mettez potentiellement des 0 dans des tableaux ... Vous aurez besoin d'une autre façon de tester que l'index a été touché.
brhfl
5

0 à la nième puissance au lieu des conditions / macros

Parfois, vous pourriez avoir besoin de quelque chose comme conditionnel ternaire:

A == B ? C : D;

Une bonne façon de gérer cela est décrite dans la réponse de @ Joe . Mais nous pouvons faire mieux:

0AB-^E*C+

où E est D - C.

Cela teste l'égalité en élevant 0 à la puissance de la différence des deux valeurs. Il en résulte 1 si égal et 0 sinon. Le reste met simplement le 1 ou 0 à l'échelle des valeurs C ou D. Cela fonctionne car dcdonne 0 0 = 1 et 0 n = 0 pour n! = 1.

Traumatisme numérique
la source
4

Parfois, il est nécessaire de jeter un numéro de la pile. Une façon de le faire est de simplement l'insérer dans une variable inutilisée, c'est-à-dire st. Cependant, dans certaines situations, vous pouvez l'afficher à quelques autres endroits, par exemple la base d'entrée lorsque vous n'avez plus d'entrée numérique ou le spécificateur de précision si vous n'avez plus d'opérations à faire là où la précision ferait une différence. Dans le premier cas, utilisez i. Dans ce dernier cas, utilisez k.

Traumatisme numérique
la source
Si la sortie numérique n'est pas importante, opeut également être utilisée. Et si certaines de ces choses sont sans importance, elles peuvent être utilisées comme stockage ainsi que comme simple suppression - I/ K/ Orappelez-les respectivement, et enregistrez des octets sur sa/ laetc. Valeurs valides AFAIK: i2-16; ktout entier non négatif; otout entier supérieur à 1.
brhfl
4

Calcul de la longueur: Z, Xetz

Zouvre le ToS et pousse le nombre de chiffres (décimal) s'il s'agit d'un nombre ou le nombre de caractères s'il s'agit d'une chaîne. Cela peut être utile pour détecter la longueur d'un résultat (pour la mise en mémoire tampon de la sortie) ou calculer la longueur d'une chaîne. Notez que pour les nombres, Zpousse la longueur combinée de la partie entière et de la partie fraction.

Xouvre le ToS et pousse le nombre de chiffres dans la partie fraction du nombre. Si le ToS était une chaîne, 0est poussé.

Pour trouver le nombre de chiffres dans la partie entière du nombre, on peut utiliser dZrX-. Si vous n'avez pas changé la précision de la valeur par défaut k==0, l'utilisation 1/Zest plus courte, mais supposez que vous devez conserver une précision non nulle particulière après l'opération: Kr0k1/Zrkc'est plutôt une horreur.

zpousse le nombre d'éléments sur la pile. Une de mes commandes préférées, elle ne fait apparaître aucune valeur! Il pourrait être utilisé pour générer une séquence de nombres ou incrémenter un compteur. L'utilisation zdrépétée (par exemple, au début d'une macro) pourrait permettre de tester un calcul sur chaque nombre naturel ou entier dans l'ordre croissant.

Joe
la source
J'ai utilisé zpour ceci et cela auparavant, mais je n'ai jamais
pensé
4

Les chiffres Aà Fpeuvent être utilisés en remplacement des numéros 10 à 15. Cependant, ils doivent toujours être traités efficacement comme des chiffres de base 10 (en supposant que la base d'entrée est 10) lorsqu'ils sont à des endroits différents. En d'autres termes, avec une base d'entrée 10 FFne représenterait pas 255, cela représenterait (15 * 10) + 15ou 165.

En fait cela fonctionne pour tous les chiffres 0à Fdans une base d'entrée 2à 16. Donc, si la base d'entrée est 5, ce 26Eserait soit (2 * 5^2) + (6 * 5) + 1494.

Notez que ce comportement est en vigueur pour les sources GNU non modifiées. Cependant, comme le souligne @SophiaLechner, les distributions basées sur RedHat semblent utiliser bc-1.06-dc_ibase.patch qui modifie ce comportement afin que les chiffres> = ibase soient traités comme ibase - 1, quelle que soit leur valeur réelle. Notez que le TIO dc ne semble pas avoir bc-1.06-dc_ibase.patch (même si son Fedora 28 ¯_ (ツ) _ / ¯).

Traumatisme numérique
la source
Ce n'est pas tout à fait exact - bien que des chiffres uniques au-dessus de la base d'entrée soient interprétés comme vous l'espérez, si le littéral a plusieurs chiffres, ou même un point décimal, les chiffres invalides pour la base sont interprétés comme (base-1). Donc, dans la base d'entrée 10 FFreprésente 99, dans la base d'entrée 5 26Eest le même que 244, c'est-à-dire la base 10 74.
Sophia Lechner
@SophiaLechner Êtes-vous sûr? tio.run/##S0n@/9/QIJ/L0CCTy82tgMs0k8vIzLXg/38A Quelle dcversion utilisez-vous? J'utilise GNU dc 1.4.1 sur ubuntu et GNU dc 1.3 sur MacOS
Digital Trauma
Intéressant. J'utilise 1.3.95 sur Red Hat, et voici votre exemple de programme: [slechner @ XXX] $ dc -e '10o 10i FFp 5i 26Ep' 99 74 [slechner @ XXX] $ dc --version dc (GNU bc 1.06 .95) 1.3.95
Sophia Lechner
Argh ... ne peut pas faire fonctionner le bloc de code en commentaire. Le fait est que les FFpsorties 99en 1.3.95. Pourriez-vous vérifier cela dans votre version MacOS, alors?
Sophia Lechner
1
Chose sûre! Merci pour toutes les recherches.
Sophia Lechner
2

Lors de l'initialisation d'une macro de fonction (que nous utiliserons F) que vous souhaitez exécuter immédiatement, utilisez quelque chose comme dsFxplutôt que sFlFx. La même chose fonctionne pour les variables: dsaplutôt que sala.

Si vous devez faire d'autres choses entre le stockage et le chargement (par exemple, sa[other stuff]la), considérez toujours si ce qui précède est viable: si vous laissez une valeur sur la pile avant les autres opérations, sera-t-elle de retour en haut à la fin de ces opérations?

Joe
la source
2

Je viens de découvrir cela par accident. Une autre façon de générer un zéro: _.

_est un signal à cc que les chiffres suivants sont un nombre négatif. Exemple:

_3 # pushes -3

Mais que se passe-t-il si nous ne le suivons pas avec un numéro?

_ # pushes 0...sometimes

Cela fonctionne lorsque le caractère non vide suivant le trait de soulignement n'est pas un chiffre. Si un chiffre le suit, même après une nouvelle ligne, il est interprété comme un signe négatif.

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
Joe
la source
1

Si le contenu de la pile entière doit être imprimé à la fin d'un programme, une boucle macro récursive peut être utilisée pour y parvenir. Cependant, il est beaucoup plus court d'utiliser simplement la fcommande.

Traumatisme numérique
la source
1

dclit l'entrée une ligne à la fois. Si vous avez besoin de lire plusieurs éléments, le faire une ligne par ligne nécessite soit une ?lecture pour chaque ligne, soit une boucle de macro encombrante. Au lieu de cela, si tous les éléments d'entrée peuvent être placés sur une ligne séparée par des espaces, un seul? lira tous les éléments d'entrée, les poussant chacun sur la pile.

Par exemple, dans seq 10 | dc -e'?f', seqgénère des nombres entiers de 1 à 10, un par ligne. le ?lira juste le premier 1qui sera sorti lors du fvidage de la pile entière. Cependant, dans seq 10 | tr '\n' ' ' | dc -e'?f', les trentiers d'entrée sont séparés par un espace. Dans ce cas, le ?lira tous les entiers de la ligne en une seule fois et fles affichera tous.

Traumatisme numérique
la source
1

Si un opérateur est restreint depuis la source, créez-en un nouveau avec a

Quelque chose qui m'a été utile à quelques reprises maintenant est d'éviter d'utiliser un opérateur spécifique en poussant la valeur ASCII de l'opérateur, en la aconvertissant en chaîne et en la sstockant dans un registre à exécuter plus tard en tant que macro sur. Par exemple, je dois faire la division, mais je suis soit interdit, soit j'essaie d'éviter d'utiliser le personnage /. Je peux, au lieu de cela 47asd, puis à l'avenir, lorsque je devrai diviser 16 par 4 16 4 ldx,.

  • Cela ne fonctionnera que pour les opérateurs à un seul caractère (ne peut pas créer de chaîne) et ne fonctionnera pas pour les commandes comme scelle-ci qui doivent être postfixées par quelque chose.
  • Cela ajoute pas mal d'octets, et ne convient donc que lorsque l'évitement du caractère spécifique est nécessaire ou offre en quelque sorte un bonus de score.
brhfl
la source
1

Éviter les espaces blancs

Éviter les espaces blancs pose de nombreux défis et est généralement facile à utiliser dc. En plus de chaînes, une fois très précis que les espaces devient nécessaire est en poussant plusieurs numéros dans une rangée: 1 2 3. Si cela doit être évité:

  • Exécuter une macro vide entre: 1[]x2[]x3[]x.
  • Si entre parenthèses sont sur la table, stocker un NOP d'une avance macro de temps: 35asnet exécuter ce entre: 1lnx2lnx3lnx.
brhfl
la source
Vous pouvez également virgule des numéros distincts, si vous êtes prêt à accepter des dc: ',' (054) unimplementedavertissements.
Digital Trauma
Je n'y avais pas pensé - cela s'applique probablement à un jeton donné qui ne se résout pas en une commande ... intéressant ...
brhfl