5.2.1 实验
考虑一个实验,评估工作站上执行fibonacci需要多长时间。先估计fib_work 100,尽管上面已经给出递归过程的定义,但有必要给出一个迭代过程的定义以便于评估。考虑下面的函数定义:
fib_work_iter =: monad def 'fib_iter 1 1 , y.'
fib_iter =: monad define
('a' ; 'b' ; 'count') =. y.
if. count = 0
do. b
else. fib_iter (1 + a + b) , a , count - 1
end.
)
使用fib_work_iter可以得到与fib_work相同的统计递归次数结果:
fib_work_iter "0 i. 11
1 1 3 5 9 15 25 41 67 109 177
下面使用fib_work_iter 计算fib_work 100(精确的)。
fib_iter 100x
57887932245395525494200
最终,在工作站上执行一系列fibonacci 函数递归所使用的时间不超过20s。
使用3500 applications/sec作为估计:
0 3500 #: 57887932245395525494200x
16539409212970150141 700
0 100 365 24 60 60 #: 16539409212970150141x
5244612256 77 234 16 49 1
最大结果是 5244612256 个世纪。
解决这一问题的一种可选的实验性方法是对递归的fibonacci定义进行计时,并从成果时间的倍数中寻找模式.
[ experiment =: (4 10 $'fibonacci ') ,. ": 4 1 $ 20 21 22 23
fibonacci 20
fibonacci 21
fibonacci 22
fibonacci 23
t =: time "1 experiment
t
2.75291 4.42869 7.15818 11.5908
(1 }. t) % _1 }. t
1.60873 1.61632 1.61924
请注意赔率大概是一样的,这意味着计算fibonacci的时间应该是指数级的。执行下面的计算,作为对事件的一个估计值:
[ ratio =: (+/ % #) (1 }. t) % _1 }. t
1.61476
0 100 365 24 60 60 rep x: ratio^100
205174677357 86 306 9 14 40
这一试验性质的方法产生了某种比 205174677357 更大的估计值. 同学们应该警惕任意试验性设计中的某些缺陷.
5.3 统计
假设我们有下面这些测试成绩.
[ scores =: 85 79 63 91 85 69 77 64 78 93 72 66 48 76 81 79
85 79 63 91 85 69 77 64 78 93 72 66 48 76 81 79
/:~scores NB. sort the scores
48 63 64 66 69 72 76 77 78 79 79 81 85 85 91 93
在干叶图上可以看到一条轴上有观察的单元数字值(页),还有其它轴上的更多重要的数字值(干). 这些可能是从如下这些分数中计算得来的:
stem =: 10&* @ <. @ %&10
leaf =: 10&|
sl_diagram =: ~.@stem ;"0 stem </. leaf
sl_diagram /:~scores
+--+-----------+
|40|8 |
+--+-----------+
|60|3 4 6 9 |
+--+-----------+
|70|2 6 7 8 9 9|
+--+-----------+
|80|1 5 5 |
+--+-----------+
|90|1 3 |
+--+-----------+
一个更加传统的频率表可以由 fr =: +/"1 @ (=/) 的定义得出. 左边的参数是一个频率的范围,而右边的参数是一个观察值的列表.
4 5 6 7 8 9 fr <. scores%10
1 0 4 6 3 2
这个频率表可以用一个使用了内置统计库的柱形图来展示(图 4).
图 4: 分数频率的柱形图
pd 'new'
pd 'type bar'
pd 'xlabel "40" "50" "60" "70" "80" "90"'
pd 4 5 6 7 8 9 fr <. scores%10
pd 'show'
当掷硬币大量的次数,头朝上的数量比上投掷的总数应该会接近0.5. 然而,但是头朝上和底朝上的次数差的绝对值可能会非常巨大. 这可以使用下面的试验来描述, 结果显示在图 5 和 6 中.
toss =: >: i. n =: 500 NB. 500 coin tosses
heads =: +/\?n$2
ratio =: heads % toss
diff =: |toss - 2*heads
toss =: >: i. n =:10 NB. a small trial
toss;ratio
+--------------------+------------------------------------------------------------+
|1 2 3 4 5 6 7 8 9 10|1 0.5 0.666667 0.75 0.6 0.666667 0.714286 0.625 0.555556 0.5|
+--------------------+------------------------------------------------------------+
toss;diff
+--------------------+-------------------+
|1 2 3 4 5 6 7 8 9 10|1 0 1 2 1 2 3 2 1 0|
+--------------------+-------------------+
图 5: 头朝上的比率
图 6: 头朝上和底朝上的差值
5.4 Groups
我们可以从数论来试验一些基本的想法来证明J的表现力.
12 +. 5 NB. greatest common divisor
1
27 +. 3
3
1 2 3 4 5 6 7 8 9 10 11 12 +. 12
1 2 3 4 1 6 1 4 3 2 1 12
NB. The numbers <: 12 which are coprime with 12
(1 = 1 2 3 4 5 6 7 8 9 10 11 12 +. 12) # 1 2 3 4 5 6 7 8 9 10 11 12
1 5 7 11
NB. The numbers <: 12 which have common factors with 12
(-. 1 = 1 2 3 4 5 6 7 8 9 10 11 12 +. 12) # 1 2 3 4 5 6 7 8 9 10 11 12
2 3 4 6 8 9 10 12
NB. 8 9 19 have common factors but do not divide 12
((-. 1 = 1 2 3 4 5 6 7 8 9 10 11 12 +. 12) # 1 2 3 4 5 6 7 8 9 10 11 12) | 12
0 0 0 0 4 3 2 0
接下来,我们概括这些表达式作为函数totatives和non_totatives。
totatives =: 3 : 0
p =. >: i. y.
(1 = p +. y.) # p
)
non_totatives =: 3 : 0
p =. >: i. y.
(-. 1 = p +. y.) # p
)
totatives 12
1 5 7 11
totatives 28
1 3 5 9 11 13 15 17 19 23 25 27
non_totatives 12
2 3 4 6 8 9 10 12
non_totatives 15
3 5 6 9 10 12 15
divisors =: 3 : 0
p =. non_totatives y.
(0 = p | y.) # p
)
divisors "0 (12 27 100)
2 3 4 6 12 0 0 0
3 9 27 0 0 0 0 0
2 4 5 10 20 25 50 100
totatives 函数中n的数量被称为n的欧拉函数. 我们可以定义totient =: # @ totatives. 另一种隐形的定义是phi =: * -.@%@~.&.q:.
(totient "0) 100 12
40 4
phi 100 12
40 4
欧拉定理指出给定一个整数 $i$ 与$n$互质, 然后 $modulo (n,i^{totient (n))}) = 1$. 这导致了定义:
euler =: 4 : 'x. (y.&| @ ^) totient y.'
2 euler 19
1
2 euler 35
1
3 euler 28
1
3 euler 205
1
3 euler 200005
1
两个 totatives 中 $n$的产物 , $modulo(n)$ 是一个 totative 中 n. 我们可以使用J的表 (/) 副词看到这一点.
totatives 12
1 5 7 11
12 | 1 5 7 11 */ 1 5 7 11
1 5 7 11
5 1 11 7
7 11 1 5
11 7 5 1
我们注意到,我们有一组(封闭,单位元,逆,和关联性)。有一个表副词可以用来展示上述的结果。
table
1 : 0
u.table~ y.
:
(' ';,.x.),.({.;}.)":y.,x.u./y.
)
12&|@* table totatives 12
+--+-----------+
| | 1 5 7 11|
+--+-----------+
| 1| 1 5 7 11|
| 5| 5 1 11 7|
| 7| 7 11 1 5|
|11|11 7 5 1|
+--+-----------+
请注意,12的totatives的另外残基12不形成一个组。
12&|@+ table 0 , totatives 12
+--+------------+
| | 0 1 5 7 11|
+--+------------+
| 0| 0 1 5 7 11|
| 1| 1 2 6 8 0|
| 5| 5 6 10 0 4|
| 7| 7 8 0 2 6|
|11|11 0 4 6 10|
+--+------------+
首先要考虑 totatives的值
p: 6
17
totatives 17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17&|@* table totatives 17
+--+-----------------------------------------------+
| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16|
+--+-----------------------------------------------+
| 1| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16|
| 2| 2 4 6 8 10 12 14 16 1 3 5 7 9 11 13 15|
| 3| 3 6 9 12 15 1 4 7 10 13 16 2 5 8 11 14|
| 4| 4 8 12 16 3 7 11 15 2 6 10 14 1 5 9 13|
| 5| 5 10 15 3 8 13 1 6 11 16 4 9 14 2 7 12|
| 6| 6 12 1 7 13 2 8 14 3 9 15 4 10 16 5 11|
| 7| 7 14 4 11 1 8 15 5 12 2 9 16 6 13 3 10|
| 8| 8 16 7 15 6 14 5 13 4 12 3 11 2 10 1 9|
| 9| 9 1 10 2 11 3 12 4 13 5 14 6 15 7 16 8|
|10|10 3 13 6 16 9 2 12 5 15 8 1 11 4 14 7|
|11|11 5 16 10 4 15 9 3 14 8 2 13 7 1 12 6|
|12|12 7 2 14 9 4 16 11 6 1 13 8 3 15 10 5|
|13|13 9 5 1 14 10 6 2 15 11 7 3 16 12 8 4|
|14|14 11 8 5 2 16 13 10 7 4 1 15 12 9 6 3|
|15|15 13 11 9 7 5 3 1 16 14 12 10 8 6 4 2|
|16|16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1|
+--+-----------------------------------------------+
和
17&|@+ table 0 , totatives 17
+--+--------------------------------------------------+
| | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16|
+--+--------------------------------------------------+
| 0| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16|
| 1| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0|
| 2| 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0 1|
| 3| 3 4 5 6 7 8 9 10 11 12 13 14 15 16 0 1 2|
| 4| 4 5 6 7 8 9 10 11 12 13 14 15 16 0 1 2 3|
| 5| 5 6 7 8 9 10 11 12 13 14 15 16 0 1 2 3 4|
| 6| 6 7 8 9 10 11 12 13 14 15 16 0 1 2 3 4 5|
| 7| 7 8 9 10 11 12 13 14 15 16 0 1 2 3 4 5 6|
| 8| 8 9 10 11 12 13 14 15 16 0 1 2 3 4 5 6 7|
| 9| 9 10 11 12 13 14 15 16 0 1 2 3 4 5 6 7 8|
|10|10 11 12 13 14 15 16 0 1 2 3 4 5 6 7 8 9|
|11|11 12 13 14 15 16 0 1 2 3 4 5 6 7 8 9 10|
|12|12 13 14 15 16 0 1 2 3 4 5 6 7 8 9 10 11|
|13|13 14 15 16 0 1 2 3 4 5 6 7 8 9 10 11 12|
|14|14 15 16 0 1 2 3 4 5 6 7 8 9 10 11 12 13|
|15|15 16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14|
|16|16 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15|
+--+--------------------------------------------------+
最后, 考虑到定义powers 来提高totatives到欧拉力.
powers =: 3 : '(totatives y.) (y.&| @ ^) / i. 1 + totient y.'
powers 12
1 1 1 1 1
1 5 1 5 1
1 7 1 7 1
1 11 1 11 1
powers 17
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 2 4 8 16 15 13 9 1 2 4 8 16 15 13 9 1
1 3 9 10 13 5 15 11 16 14 8 7 4 12 2 6 1
1 4 16 13 1 4 16 13 1 4 16 13 1 4 16 13 1
1 5 8 6 13 14 2 10 16 12 9 11 4 3 15 7 1
1 6 2 12 4 7 8 14 16 11 15 5 13 10 9 3 1
1 7 15 3 4 11 9 12 16 10 2 14 13 6 8 5 1
1 8 13 2 16 9 4 15 1 8 13 2 16 9 4 15 1
1 9 13 15 16 8 4 2 1 9 13 15 16 8 4 2 1
1 10 15 14 4 6 9 5 16 7 2 3 13 11 8 12 1
1 11 2 5 4 10 8 3 16 6 15 12 13 7 9 14 1
1 12 8 11 13 3 2 7 16 5 9 6 4 14 15 10 1
1 13 16 4 1 13 16 4 1 13 16 4 1 13 16 4 1
1 14 9 7 13 12 15 6 16 3 8 10 4 5 2 11 1
1 15 4 9 16 2 13 8 1 15 4 9 16 2 13 8 1
1 16 1 16 1 16 1 16 1 16 1 16 1 16 1 16 1
5.5 多项式
在这部分我们将讨论多项式的表示和操作。多项式由它的系数决定,所以我们将多项式表示成一个升序的列表而不是通常的降序。例如,多项式$x^3+2x+5$被表示为了5 2 0 1.
多项式求值,我们采用如下表示:
peval =: (#. |.) ~
5 2 0 1 peval 3
38
p.用来表示多项式求值。
5 2 0 1 p. 3
38
多项式的加减转化为针对同类项系数的加减:
psum =: , @ (+/ @ ,: & ,:)
pdif =: , @ (-/ @ ,: & ,:)
1 2 psum 1 3 1
2 5 1
3 psum 1 3 1
4 3 1
1 2 pdif 1 3 1
0 _1 _1
下面我们考虑多项式的积和衍生的多项式。如果我们使用乘积表,同类项的系数在表的斜对角线倾斜。倾斜副词/.可以访问这些对角线上的值。
pprod =: +/ /. @ (*/)
1 2 pprod 1 3 1
1 5 7 2
pderiv =: 1: }. ] * i. @ #
pderiv 1 3 3 1
3 6 3
p.. 1 3 3 1 NB. There is a primitive for derivative
3 6 3
为易于表示高抽象级函数,可以考虑使用元素是多项式的矩阵。我们称这个为 boxed table。例如,
[ m =: 2 2 $ 1 2 ; 1 2 1 ; 1 3 3 1 ; 1 4 6 4 1
+-------+---------+
|1 2 |1 2 1 |
+-------+---------+
|1 3 3 1|1 4 6 4 1|
+-------+---------+
[ n =: 2 3 $ 1 2 3 ; 3 2 1 ; 1 0 1 ; 3 3 3 3 ; _1 _2 3; 3 4 5
+-------+-------+-----+
|1 2 3 |3 2 1 |1 0 1|
+-------+-------+-----+
|3 3 3 3|_1 _2 3|3 4 5|
+-------+-------+-----+
下一步,我们将定义一个新版本的psum, pdif和pprod,假设它们的参数是boxed polynomials。
psumb =: psum &. >
pdifb =: pdif &. >
pprodb =: pprod &. >
之后我们可以为了这些元素是多项式的矩阵定义一个矩阵乘积:
pmp =: psumb / . pprodb
m pmp n
+---------------------+---------------+------------------+
|4 13 19 18 9 3 |2 4 3 6 3 |4 12 17 16 5 |
+---------------------+---------------+------------------+
|4 20 45 61 56 36 15 3|2 5 5 8 14 11 3|4 19 43 60 52 25 5|
+---------------------+---------------+------------------+
m pmp m
+--------------------+-----------------------+
|2 9 14 10 5 1 |2 10 20 22 15 6 1 |
+--------------------+-----------------------+
|2 12 30 42 37 21 7 1|2 13 38 66 75 57 28 8 1|
+--------------------+-----------------------+
m pmp^:0 m
+-------+---------+
|1 2 |1 2 1 |
+-------+---------+
|1 3 3 1|1 4 6 4 1|
+-------+---------+
m pmp^:1 m
+--------------------+-----------------------+
|2 9 14 10 5 1 |2 10 20 22 15 6 1 |
+--------------------+-----------------------+
|2 12 30 42 37 21 7 1|2 13 38 66 75 57 28 8 1|
+--------------------+-----------------------+
m pmp^:2 m
+----------------------------------------+----------------------------------------------+
|4 29 88 152 176 148 88 36 9 1 |4 31 106 217 304 309 230 123 45 10 1 |
+----------------------------------------+----------------------------------------------+
|4 35 137 323 521 613 539 353 168 55 11 1|4 37 158 418 772 1055 1094 864 513 222 66 12 1|
+----------------------------------------+----------------------------------------------+
m pmp^:10 x: &. > m
+-------------------------------------------------...
|1024 29952 424704 3899184 26124316 136500501 5803...
+-------------------------------------------------...
|1024 31488 471040 4577232 32551980 180983051 8205...
+-------------------------------------------------...
5.6 证明
Iverson和其它的作者已经使用J语言写了数本关于数学计算的书。其中一个[Ive 1995]在[Gra 1989]使用J语言描述算法和证明。下面的例子是从[Ive 1995]摘录的。
在定理声明中,一个表达式I和另外一个r相等。我们可以在J语言中使用如下方式表示两者关系:
t=: l -: r
这是我必须匹配r,t必须是常函数1所有输入。t有时叫做 同义反复。例如,
l =: +/ @ i. NB. Sum of integers
r =: (] * ] - 1:) % 2:
如果我们定义n= : ],右边是一个恒等函数,我们可以转化最后一个等式:
r =: (n * n - 1:) % 2:
下一步,
t =: l -: r
注意实验上呈现的, 不管输入参数为何,t总是1.
t 1 2 3 4 5 6 7 8 9
1 1 1 1 1 1 1 1 1
定理证明是从l到r的一系列恒等表达式有序组合。
l
+/ @ i. Definition of l
+/ @ |. i. Sum is associative and commutative
(|. is reverse)
((+/ @ i.) + (+/ @ |. @ i.)) % 2: Half sum of equal values
+/ @ (i. + |. @ i.) % 2: Summation distributes over addition
+/ @ (n # n - 1:) % 2: Each term is n -1; there are n terms
(n * n - 1:) % 2: Definition of multiplication
r Definition of r
当然,上述证明每个表达式是都是一个简单的程序,而证明是一系列有序验证可以将一个表达式转化成另一个。
5.7 J可以作为一种数学符号
Iverson讨论了数学符号在数学计算中的作用。在这篇文章他引用了
A. N. Whitehead
通过减轻大脑不必要的工作负担,一种好的数学符号可以把精力集中在更高级的问题上,事实上增加了脑力劳动的强度。
F. Cajori
一些诸如 $a^n$, $\sqrt{n}$, $log$ $n$的数学符号仅适用于正整数,如果应用于浮点数、负数和复数,则可能导致致命错误。
A. de Morgan
数学符号,就像语言一样,并没有严格的限制而得到广泛使用,它的便利性和规定得到了大多数人的认同。
其它著名的引用是与J语言的特性有关:
Friedrich Engels
在科学中,每一种新的术语都会引发革命性的改变
Bertrand Russell
好的符号有一种一种微妙和暗示性的作用,就像一位活生生的老师一般
A. N. Whitehead, 数学的序言作者
这里有一个众所周知的错误,重复已出版的书籍和那些名人的演讲,我们应该富有创新精神并且思考我们可以做什么。事实的情况可能与我们想象的不同,文明的进步提升了数学运算的重要性,但我们却没有深入的思考他们
当然,J语言符号正变得流行,让大脑从繁琐的计算中解放出来,集中精力思考运算背后的事情。它也移除了数学计算的多义性,不要被_3(十减三)和应用程序中的-3混淆。
一种好的数学符号扩展的例子可以在Cajori的外部乘积的引用中(spelled .)找到。+/ . (矩阵乘积)被表达成一种外部的乘积推导出其它有用的外部乘积诸如+./ . 。
很遗憾,J语言并没有被计算机科学广泛接受,在数学上接受就更少了。