Советы по игре в гольф в dc


18

Какие общие советы у вас есть для игры в гольф в DC ?

dc - это утилита калькулятора для UNIX / Linux, предшествующая языку C. Меня интересует, как сделать мои программы постоянного тока (вычисления?) Короче. Я ищу идеи, которые могут быть применены к общему , которые, по крайней мере, немного специфичны для постоянного тока (например, удаление комментариев не является полезным ответом)

Пожалуйста, оставьте один совет за ответ.


7
Вместо этого используйте Marvel.
Волшебная Урна Осьминога

Ответы:


6

Заявления if-then-else

Предположим, мы хотим проверить условие a==b(пусть aи bхранятся в их соответственно именованных регистрах).

редактировать:
[         # 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

Уверен, что это наиболее компактный оператор из возможных (также показанный здесь ).


1
Может быть [[thenaction]P][[elseaction]P][r]sI 2 4 =I x sI f, это начало? Действия для tehn и прочего находятся в стеке, Iмакрос « f» меняет их и вызывается условно. тогда вершина стека будет выполнена, и неиспользуемый макрос будет сброшен в I для очистки стека. 2 4это просто пример данных для сравнения. В качестве альтернативы [x]sIчасть может быть перемещен в сравнении, если рассматривать более читаемым: [[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f. В fпримерах просто будет показано, что стек чист после ...

1
Страница Rosetta кодекса о Dc упоминает 3 ароматов , dcи это было первая страница , где я видел OpenBSD dc«s if-then-elseконструкции. Я думаю, что нам нужен dcкомплект вентиляторов со всеми 3 вариантами для всех основных операционных систем ... o :-) ... и мое if-then-elseпредложение выше не работает на оригинале, dcпотому что в нем отсутствует rкоманда ... :-(

1
Как насчет: [[(if)2Q]si(condition)i(else)]x- обернуть все это в макрос и часть if внутри другого макроса внутри него, чтобы вы могли 2Qвыйти из всего этого, прежде чем достигнуть else-части. Так что, если вы хотите сделать, если 1 == 1, то выведите 1, иначе выведите 2 , это было бы 1[[1P2Q]si1=i2P]x(не проверено, поскольку у меня нет доступа к dc прямо здесь и сейчас. Также я был уверен, что делал этот трюк в ответе здесь раньше но не смог его найти)
daniero

Да, я сделал математику, мое предложение короче. С тем же примером и «нотацией», и удаляя пробелы, это [/*else*/]sE[[/*then*/]sE]sIlalb=IlExпротив [[/*then*/2Q]sIlalb=I/*else*/]xразницы в 6 байтов.
До

1
Хорошая работа, @daniero! Я обновлю пост, когда у меня будет время, или вы можете сделать это, если хотите.
Джо

5

Вы можете сохранить ввод с d

Используя d, который дублирует ToS (верхнюю часть стека), вы можете убрать ввод с пути для дальнейшего использования, при этом все еще имея возможность использовать его.


@ 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-й степени вместо условных / макросов

Иногда вам может понадобиться что - то вроде троичной условно:

A == B ? C : D;

Хороший способ справиться с этим описан в ответе @ Joe . Однако мы можем сделать лучше:

0AB-^E*C+

где E - D - C.

Это проверяет равенство, возводя 0 в степень разности двух значений. Это приводит к 1, если равно и 0 в противном случае. Остальные просто масштабируют 1 или 0 до значений C или D. Это работает, потому что dcдает 0 0 = 1 и 0 n = 0 для n! = 1.


4

Иногда необходимо сбросить число из стека. Один из способов сделать это просто вытолкнуть его в неиспользуемый переменную, то есть st. Однако в некоторых ситуациях вы можете вставить его в несколько других мест, например, во входную базу, когда у вас больше нет числового ввода, или в спецификатор точности, если у вас нет больше операций, которые могут помочь, если точность будет иметь значение. В первом случае используйте i. В последнем случае используйте k.


Если числовой вывод не важен, oего тоже можно использовать. И если какие-либо из этих вещей не важны, они могут использоваться в качестве хранилища, а также просто отбрасывать их I/ K/ Oвызывать их соответственно и сохранять байты сверх sa/ laи т.д. Допустимые значения AFAIK: i2-16; kлюбое неотрицательное целое число; oлюбое целое число больше 1.
brhfl

4

Длина расчета: Z, X, иz

Zвыскакивает ToS и выталкивает количество цифр (десятичное), если это число, или количество символов, если это строка. Это может быть полезно для определения длины результата (для буферизации вывода) или вычисления длины строки. Обратите внимание, что для чисел Zтолкает объединенную длину целочисленной части и дробной части.

Xвыскакивает ToS и толкает количество цифр в дробной части числа. Если ToS был строкой,0 он выдвигается.

Чтобы найти количество цифр в целой части числа, можно использовать dZrX-. Если вы не изменили точность по умолчанию k==0, используется 1/Zкороче, но предположим, что вам нужно поддерживать определенную ненулевую точность после операции:Kr0k1/Zrk это скорее бельмо на глазу.

zтолкает количество предметов в стеке. Одна из моих любимых команд, она не выдает никаких значений! Это может быть использовано для генерации последовательности чисел или увеличения счетчика. zdПовторное использование (скажем, в начале макроса) может позволить протестировать вычисления для каждого натурального или целого числа в порядке возрастания.


Использовали zдля этого и того раньше, но мне никогда не приходило в голову использовать это как хак для счетчика ... Отлично ...
brhfl

4

Digits A на Fможет быть использованы в качестве замены для чисел от 10 до 15. Однако они еще должны быть обработаны эффективно , как основание 10 цифр (предполагается , что входная база 10) , когда в разных местах. Другими словами, при вводе база 10 FFне будет представлять 255, она будет представлять (15 * 10) + 15или 165.

На самом деле это работает для всех цифр , 0чтобы Fв любом входной базы2 в 16. Так что, если база ввода 5, то 26Eбудет (2 * 5^2) + (6 * 5) + 14или 94.

Обратите внимание, что это поведение действует для неизмененных источников GNU. Однако, как указывает @SophiaLechner, в дистрибутивах RedHat, по-видимому, используется bc-1.06-dc_ibase.patch, который меняет это поведение, поэтому цифры> = ibase обрабатываются как ibase - 1, независимо от их фактического значения. Обратите внимание, что TIO, dc похоже, не имеет bc-1.06-dc_ibase.patch (хотя его Fedora 28 ¯_ (ツ) _ / ¯).


Это не совсем верно - хотя отдельные цифры над входной базой интерпретируются, как вы надеетесь, если литерал имеет несколько цифр или даже десятичную точку, недопустимые цифры для базы интерпретируются как (base-1). Таким образом, на входе база 10 FFпредставляет собой 99, на входе базу 5 26Eтакая же, как 244, например, база 10 74.
София Лехнер

@SophiaLechner Вы уверены? tio.run/##S0n@/9/QIJ/L0CCTy82tgMs0k8vIzLXg/38A Какую dcверсию вы используете? Я использую GNU DC 1.4.1 на Ubuntu и GNU DC 1,3 на MacOS
Digital Trauma

Интересный. Я использую 1.3.95 для Red Hat, и вот ваш пример программы: [slechner @ XXX] $ dc -e '10o 10i FFp 5i 26Ep' 99 74 [slechner @ XXX] $ dc - версия dc (GNU bc 1.06 .95) 1.3.95
София Лехнер

Argh ... не может заставить блок кода работать в комментариях. Дело в том, что FFpвыходы 99в 1.3.95. Не могли бы вы проверить это в своей версии MacOS?
София Лехнер

1
Конечно, вещь! Спасибо за все исследования.
София Лехнер

2

При инициализации в функции макро (мы будем использовать F) , который вы хотите запустить сразу же, использовать что - то вроде , dsFxа неsFlFx . То же самое работает для переменных: dsaвместо sala.

Если вам нужно сделать что-то другое между хранением и загрузкой (например, sa[other stuff]la), все равно подумайте, действительно ли вышеприведенное является жизнеспособным: если вы оставите значение в стеке перед другими операциями, оно вернется к началу к концу из этих операций?


2

Просто обнаружил это случайно. Еще один способ сгенерировать ноль:_ .

_является сигналом для постоянного тока о том, что следующие цифры являются отрицательным числом. Пример:

_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читает ввод строки за раз. Если вам нужно прочитать несколько элементов, то для этого нужно выполнить по одной на строку, либо ?для каждой строки нужно прочитать, либо громоздкий макрос-цикл. Вместо этого, если все элементы ввода могут быть помещены в одну строку, разделенную пробелом, то? будет считывать все входные элементы, помещая каждый из них в стек.

К примеру , в seq 10 | dc -e'?f', seqвыводит целые числа 1-10, по одному в строке. ?будет только читать первый , 1который будет выводиться , когда fсбрасывает весь стек. Однако в seq 10 | tr '\n' ' ' | dc -e'?f', trделает входные целые все разделенные пробелом. В этом случае он за один раз ?прочитает все целые числа из строки и fвыведет их все.


1

Если оператор ограничен от источника, создайте новый с a

Что-то, что пригодилось мне пару раз, теперь состоит в том, чтобы избегать использования определенного оператора, выдвигая значение ASCII оператора, используя его aдля преобразования его в строку, и sзаписывая его в регистр для последующего выполнения в качестве макроса на. Например, мне нужно сделать разделение, но я либо запрещен, либо стараюсь избегать использования персонажа /. Я могу вместо этого сделать, 47asdа затем в будущем, когда мне нужно разделить 16 на 4 16 4 ldx,.

  • Это будет работать только для односимвольных операторов (не может создать строку) и не будет работать для таких команд, как s которым нужно что-то постфиксировать.
  • Это добавляет довольно много байтов и, следовательно, подходит только тогда, когда необходимо избегать определенного символа или как-то дает бонус за очки.

1

Как избежать пробелов

Как избежать пробелов, возникает немало проблем, и, как правило, это легко dc. Помимо строк, один очень специфический момент, когда пробел становится необходимым, - это нажатие нескольких чисел в строке:1 2 3 . Если этого следует избегать:

  • Выполнить пустой макрос между: 1[]x2[]x3[]x .
  • Если скобки на столе, хранить NOP макроскопически загодя: 35asnи выполнить его между ними: 1lnx2lnx3lnx.

Вы также можете запятую отдельные номера, если вы готовы мириться с dc: ',' (054) unimplementedпредупреждениями.
Цифровая травма

Я не думал об этом - вероятно, это относится к любому данному токену, который не разрешает команду… интересно…
brhfl
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.