直流打高尔夫球的技巧


18

您对DC打高尔夫球有哪些一般提示?

dc是早于C语言的UNIX / Linux计算器实用程序。我对如何缩短我的直流程序(计算?)感兴趣。我正在寻找可应用于通用想法,这些想法至少特定于dc(例如,删除注释不是有帮助的答案)

请为每个答案发布一个提示。


7
请改用Marvel。
魔术章鱼缸

Answers:


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和else的动作在堆栈中,“ If”宏交换它们并有条件地进行校准。然后将执行堆栈的顶部,并将未使用的宏放入I中以清理堆栈。2 4只是要比较的示例数据。或者[x]sI,如果认为可读性更高,可以将零件移至比较中[[thenaction]P][[elseaction]P] 4 4 [r]sI =I x sI f。将f在例子只是应当出示达堆栈干净之后...

1
罗塞塔守则的有关DC页提到的3种味道dc,那就是在那里我看到OpenBSD的第一页dcif-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=IlExvs [[/*then*/2Q]sIlalb=I/*else*/]x-6个字节的差异。仍然未经测试::P
daniero '16

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到n次方,而不是条件/宏

有时你可能需要像三元条件:

A == B ? C : D;

@Joe的答案描述了一种解决此问题的好方法。但是,我们可以做得更好:

0AB-^E*C+

其中E是D-C。

这通过将0增大两个值之差的幂来测试是否相等。如果相等,则结果为1,否则为0。其余的仅将1或0缩放为C或D值。之所以起作用,是因为对于n!= 1 dc给出0 0 = 1和0 n = 0。


4

有时有必要从堆栈中丢弃一个数字。一种实现方法是简单地将其弹出未使用的变量,即st。但是,在某些情况下,您可以将其弹出到其他两个地方,例如,当您不再有数字输入时将其输入基数,或者如果您没有更多操作要进行精度会有所不同的情况,则将其弹出至精度说明符。在前一种情况下,请使用i。在后一种情况下,请使用k


如果数字输出不重要,o也可以使用。如果这些事情是不重要的,它们可以被用来作为存储以及单纯丢弃- I/ K/ O分别调用它们,并保存在字节sa/ la等有效值据我所知:i2-16; k任何非负整数;o任何整数大于1
brhfl

4

长度计算:ZX,和z

Z弹出ToS并输入数字(十进制)(如果是数字)或字符数(如果是字符串)。这对于检测结果的长度(用于缓冲输出)或计算字符串的长度很有用。请注意,对于数字,请Z推送整数部分和小数部分的组合长度。

X弹出ToS并在数字的小数部分中压入位数。如果ToS是字符串,则将其0推送。

要查找数字整数部分的位数,可以使用dZrX-。如果您尚未从default更改精度k==0,则使用1/Zshort会更短,但是假设您需要在操作后保持特定的非零精度:Kr0k1/Zrk真是令人讨厌。

z推送堆栈中的项目数。我最喜欢的命令之一,它实际上不会弹出任何值!它可用于生成数字序列或增加计数器。zd反复使用(例如,在宏的开头)可以让人们测试每个自然数或整数的升序计算


z以前曾经用过这种方式,但是我从来没有想过用它来作为柜台的工具……
很棒

4

位数 AF可以替代用于数字10〜15。然而,它们仍必须有效地视为基部10位(假定输入基为10)在不同的地方时。换句话说,输入基数10 FF不会代表255,它将代表(15 * 10) + 15或165。

事实上,这适用于所有数字0F任何输入基地216。因此,如果输入底数为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/38Adc您正在运行 哪个版本?我在ubuntu上使用GNU dc 1.4.1,在MacOS上使用GNU dc 1.3
Digital Trauma

有趣。我在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
Sophia Lechner

糟糕...无法在注释中使用代码块。关键是1.3.95 中的FFp输出99。那您能在MacOS版本中检查一下吗?
索菲亚·莱希纳

1
当然可以!感谢您所做的所有研究。
索菲亚莱希纳'18

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

现在,对我来说有用的事情是避免使用特定的运算符,方法a是将运算符的ASCII值压入,将其转换为字符串,然后s将此值存储在寄存器中以稍后作为宏执行上。例如,我需要进行除法,但是要么被禁止使用,要么试图避免使用该字符/。我可以改为做47asd,然后在将来需要将16除以4时得到16 4 ldx

  • 这仅适用于单字符运算符(无法构建字符串),不适用于s需要后缀某些内容的命令。
  • 这增加了相当多的字节,因此仅在避免必须使用特定字符或以某种方式提供分数奖励时才适用。

1

避免空格

避免空白会带来很多挑战,并且通常很容易做到dc。除了字符串之外,必须在空格中输入空格是在一个特定的时间,当连续推送多个数字时:1 2 3。如果必须避免这种情况:

  • 在之间执行一个空宏:1[]x2[]x3[]x
  • 如果括号是假表,存储的时间提前宏观的NOP:35asn并执行介于两者之间:1lnx2lnx3lnx

如果愿意忍受dc: ',' (054) unimplemented警告,也可以用逗号分隔数字。
Digital Trauma

我没有想到这一点-大概适用于任何无法解析为命令的给定令牌……有趣的是
brhfl
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.