【问题标题】:Why does the J phrase '(2&*~) 15 7 3 1' produce a table, and why that specific table?为什么 J 短语 '(2&*~) 15 7 3 1' 会产生一个表格,为什么是那个特定的表格?
【发布时间】:2011-11-18 04:13:45
【问题描述】:
(2&*~) 15 7 3 1 

上面是这句话。最后是痕迹和最终结果。我知道这个短语是一个单子,我知道因为 ~ 它有一个左右参数。如果您运行“15 7 3 1(2&*) 15 7 3 1”,则会发生相同的输出。我还知道正确的表格是 2 的 1、3、7、15 的幂,其他条目是它们的基数乘以 2 的幂,但我就是不明白为什么。

在相关说明中,这是 Rosetta Code 网站上来自 ethopian 乘法的短语(实际上,这也是,我在试图弄清楚这一点时已经走了这么远)和 '(1>.<.>

(1>.<.@-:)^:a: 27
27 13 6 3 1

但是 (1>.<.>

关于三个相关问题的最后一个,(这些都与分解Ethopian乘法代码有关),完整代码如下:

double =:  2&*
halve  =:  %&2           NB.  or the primitive  -:
odd    =:  2&|

ethiop =:  +/@(odd@] # (double~ <@#)) (1>.<.@halve)^:a:

这可以简单地替换为:

ethiop =:  +/@(2&|@] # (2&*~ <@#)) (1>.<.@-:)^:a:

而且效果很好!被成功冲昏了头脑,当我想到有一个在命令行上工作的一元替身时,我完全从悬崖上掉下来了:

+: 98
196

并且双精度运算符必须比带有附加常量的双精度运算符快,也许双精度运算符只是移位,所以我认为

ethiop =:  +/@(2&|@] # (+:~ <@#)) (1>.<.@-:)^:a:

会工作......但它没有。

我尝试过大写字母、连词等,但没有任何效果,它总是说“域错误”。我开始认为代码依赖于所谓的 monad 以一种我不明白的方式创建加倍表。

唯一的好处是J动词odd与测试奇数无关。

谁能向我解释这些事情,也许可以用英文解释程序的工作原理?不是算法如何工作,而是如何实现算法。我记得当我在 1970 年玩 IBM 1130 APL 时。这是一个以 8k 字运行的 APL 解释器,不用说,它是有限的。例如,它有一个滚动但没有交易。解释器逐步进出内存,1130 支持代码覆盖,它将您的子例程分成组,当一个组调用另一个组时,它将从磁盘加载新组(是的,8k 中的伪交换)。因此,我使用各种方案编写了 deal 的版本,并且随机地,我们会找到一个可以逐步进入和退出而无需搜索的版本,而那个版本,无论写得多么糟糕,有多少行和多少解释器操作都会运行 10 次和其他任何东西一样快。我不知道自己在做什么,我会不断地添加 ravels 和无意义的作业,并跨行打破陈述或将它们组合起来,直到我得到一个无需查找即可运行的语句。 (正在寻求的 52 交易 52 可能需要 45 秒)。

然后昨晚我计算了 J 中的第 150,000 个斐波那契数。它必须是 64 位版本,并且花了 1 小时 17 分钟。我用了精确的算术,这个数字有 31349 位,它从 1012838344936638038 开始......我意识到 1130 永远不可能计算出这个,这个数字不合适,因为你需要三个,而最大的一个有 32k 16 位字。我想学习可以做到这一点的语言,但是文档中缺少一些我没有得到的东西。

 trace '(2&*) 15 7 3 1' 
 --------------- 4 Conj -------
 2
 &
 *
 2&*
 --------------- 3 Adverb -----
 2&*
 ~
 2&*~
 --------------- 8 Paren ------
 (
 2&*~
 )
 2&*~
 --------------- 0 Monad ------
 2&*~
 15 7 3 1
 491520 229376 98304 32768
   1920    896   384   128
    120     56    24     8
     30     14     6     2
 ==============================
 491520 229376 98304 32768
   1920    896   384   128
    120     56    24     8
     30     14     6     2

斐波那契脚注:

]t150k=:6!:2 'a150k =: $ ":r150k=: {:  (,+/@(_2&{.) )^:150000 (0x 1x)'
4631.62

0 60 60 #: t150k
1 17 11.6167
r150k
10128383449366380384728502706681008427227914006240871521944866167854579423510169
50198752571599303492471943589300904953648270811064370506598260395645679940891823
17307901573781852234222080308236027906733606532470814177610613237408102006595571
1949713927351702...
a150k
31349

【问题讨论】:

  • 这似乎很漫无边际。斐波那契数计算与问题有什么关系?
  • 没什么,我只是觉得很有趣,一个人可以用 J 中的那么多数字计算一个斐波那契数。即使它花了一个多小时。我想我只是在闲逛,对不起。但是,当我解决一个问题时,我发现如果回答者了解我为达到目标所采取的方向,这对他们很有帮助。如果这让您更难理解我的问题,我深表歉意。

标签: functional-programming j tacit-programming


【解决方案1】:

答案记录在Bond (&) 下,其中注明了以下身份以供二元使用:

x m&v y ↔ m&v^:x y

在您的示例中,m 是 2,v 是 *,x 和 y 都是 15 7 3 1 四个数字的列表。

等式右侧的短语包括^:x(“x 次幂”),这与取动词并将其应用 x 次相同。动词是2&amp;*,所以它被应用了十五次。还有七次。而且也是三遍。而且还有一次。这四个应用程序的结果构成了输出的四行。

关注第三个并使用括号强调,这就是正在发生的事情。

   (2&* (2&* (2&* (15 7 3 1))))
  120 56 24 8

与

相同
   (2&*)^:3 (15 7 3 1)
120 56 24 8

与

相同
   (3) 2&* (15 7 3 1)
120 56 24 8

让我们应用到 3 的所有非负整数来查看一个模式:

   (0 1 2 3) 2&* (15 7 3 1)
 15  7  3 1
 30 14  6 2
 60 28 12 4
120 56 24 8

此时与原始表格的相似性可能会使该表格的含义易于理解:

   (15 7 3 1) 2&* (15 7 3 1)
491520 229376 98304 32768
  1920    896   384   128
   120     56    24     8
    30     14     6     2

同样的事情正在发生,只是因为你给出了更高的数字而发生得更频繁。

【讨论】:

    【解决方案2】:

    这只是你的问题的初步尝试,因为到目前为止没有人回答:

    副词的左作用域很长:

    (2&*~) <-> ((2&*)~)
    

    bond返回的函数的二元情况是powered:

    (x m&v y) <-> ((m&v)^:x y)
    

    2&amp;* 每次应用时都会将其参数翻倍,因此 powered 2&amp;* 将其参数乘以 2 的幂。

    (1&gt;.&lt;.@-:)^: 27 定义了一个动词(因为^: 是一个连词),但不运行它。在原始短语中,foo^:a: 是动词,27 是参数。当a: 是^: 的正确参数时,它会一直运行直到收敛。

    Monadic +: 将其论点加倍,但 2&amp;* 和 +: 的二元情况没有任何关系,也不能互换。请注意,double~ 是钩子的左侧,它总是被称为 dyadically。

    唯一的好处是J动词odd与测试奇数无关。

    其实2&amp;| y是1如果y是奇数,0是偶数,所以是对奇数的检验。

    现在,为了尝试用简单的英语解释该算法的作用,让我们逐句看一下,以12 ethiop 27 为例:

    +/@(2&|@] # (2&*~ <@#)) (1>.<.@-:)^:a:
    

    是一个钩子。在 hooks 中,右侧始终是 monad,左侧始终是 dyad。

    (1 >. (<. @ -:)) ^: a:
    

    Monad (&lt;. @ -:) = floor @ half,将其参数减半并向下舍入,然后 1 &gt;. (&lt;. @ -: 返回最小值和 1。 ^:a: 一直持续到收敛并列出结果。因此(1 &gt;. (&lt;. @ -:)) ^: a: 27 是27 重复减半直到达到1,产生27 13 6 3 1

    现在让我们看看钩子的左半部分。 (2&amp;|@] # (2&amp;*~ &lt;@#)) 是一个二元分叉,参数是 ethiop 的左参数和上述钩子的右部分的结果。

    2&amp;|@] 是 1 如果它的正确参数是奇数,0 否则。对于参数27 13 6 3 1,结果是1 1 0 1 1

    (2&amp;*~ &lt;@#) 又是一个钩子。 27 13 6 3 1,并将长度装箱,返回(&lt;5)。然后我们到达2&amp;*~,正如我们所见,它是二元的,所以这是(在~ 切换参数之后)+:^:(&lt;5) 12。

    f^:m,当m 被装箱时,会执行f &lt;: &gt;m 次,产生一个m-length 的结果列表(除非m 为空,在这种情况下它会一直运行直到收敛)。所以这将产生12 * 2 ^ i.5

    那么叉子的中间部分就是#,它带有一个布尔左参数,只是过滤它的右参数,在这种情况下,留下 12 * 2 的 2 的幂,其中 27 是奇数。

       1 1 0 1 1 # 12 24 48 96 192
    12 24 96 192
    

    最后+/ 是sum

       +/12 24 96 192
    324
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-02
      • 1970-01-01
      相关资源
      最近更新 更多