`
ILoveDOUZHOU
  • 浏览: 81076 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

Ackerman函数以及 Linux环境下的绘图(perl脚本实现)

 
阅读更多

转自于http://blog.chinaunix.net/uid-20602285-id-3078231.html

老师用ackerman函数来测试我们的lisp interpreter是否能应付extremely recursive function,虽然我们都不能,但也说明了一个健壮的interpreter是需要优化recursive function的一个道理。

ackerman函数 wiki 上有介绍:http://en.wikipedia.org/wiki/Ackerman_function

我下面记录的是怎么算出来A(4,2)。(如下表述中,ns就代表A)
ns(0,x) = x + 1
ns(1,x) = ns(0, ns(x-1)) && ns(1,0) = 2. so, ns(1,x) = x + 2
ns(2,x) = ns(1, ns(2,x-1)) = ns(2,x-1)+2 && ns(2,0) = ns(1,1) = 3. so, ns(2,x) = 2x+3
ns(3,x) = ns(2,ns(3,x-1)) = 2*ns(3,x-1)+3 && ns(3,0) = ns(2,1)=5. so, ns(3,x) = 2^(x+3) - 3
ns(4,x) = ns(3, ns(x-1)) = 2^(ns(3,x-1)+3) - 3 && ns(4,0) = ns(3,1) = 13
but if we let g(x) = ns(4,x) + 3
we have g(x) = 2^(g(x-1)) && g(0) = 16 = 2^4
so I think it's the end of this story (unless we use the symbol from knuth, which I just learned from wiki,
but I can manually get ns(4,2) = g(2) -3 = 2^(g(1)) - 3 = 2^(2^(g(0))) - 3 = 2^(2^16)) - 3 = 2^65536 - 3

these links may be helpful:
http://www.wolframalpha.com/input/?i=f%28x%29%3Df%28x-1%29%2B1%2Cf%280%29%3D2
http://www.wolframalpha.com/input/?i=f%28x%29+%3D+f%28x-1%29%2B2%2Cf%280%29%3D3
http://www.wolframalpha.com/input/?i=f%28x%29%3D2*f%28x-1%29%2B3%2Cf%280%29%3D5
http://www.wolframalpha.com/input/?i=f%28x%29%3D2^%28f%28x-1%29%2B3%29-3%2Cf%280%29%3D13
http://www.wolframalpha.com/input/?i=log2%28g%28x%29%29%3Dg%28x-1%29%2Cg%280%29%3D16
http://www.wolframalpha.com/input/?i=2^65536-3

当我算出来(4,2)后,我想尝试下得到ackerman函数的通式,结果后来尝试下后也可以了,需要引入wiki里学到的knuth发明的符号。“向上箭头符号”。↑
懂得这个符号以及扩展符号↑↑后,就可以证明ackerman函数的通式了,最傻瓜的方法是用归纳法证明,首先证明base case (1,1)成立,然后证明(1,x)成立;然后假设对于小于等于m的i或小于等于n的j (i,j)都成立,证明(i,j+1)成立。这样归纳法就完整了。

但是归纳法要求事先知道通式,这个不符合认识的流程。认识的流程应该是探索->猜想->证明。
以上我得出(4,2)的过程就是一个探索的过程。但是从中观察出规律确实很难,我也是在得到wiki的启发后知道的,接下来可以证明一下(4,x),有了knuth的符号,很容易证明;接下来再证明(5,x),也是可以的,无非knuth符号多了一层。最后再猜想,便很自然了。

ackerman函数通式的得出就写到这里。

还有一个有趣的现象,是我一个同学冷潇泠想到的,他建议把函数递归过程中的B打印出来,并且配上递归层数i,形成一些(i,B)对,把这个画在坐标系上会形成无数个抛物线,且每个抛物线都是下个抛物线的前面部分。

这个图也许还不清晰,把抛物线下的点都删掉,便有更清晰的图

这个现象还是蛮有意思的。
我的ackerman函数实现如下:

  1. #include <stdio.h>
  2. #include <stdlib.h>

  3. int g = 0;

  4. int ackerman(int a, int b)
  5. {
  6. if(g++<100000) {
  7. printf("%d %d\n",a,b);
  8. }
  9. else
  10. exit(1);

  11. if(a==0)
  12. return b+1;
  13. else if (b==0)
  14. return ackerman(a-1,1);
  15. else
  16. {
  17. return ackerman(a-1,ackerman(a,b-1));
  18. }

  19. }

  20. int main()
  21. {
  22. int a,b;
  23. scanf("%d %d",&a,&b);
  24. ackerman(a,b);
  25. }
产生数据后分析数据的perl脚本如下:
  1. #!/usr/bin/perl
  2. open(INP,"ackerman4.2.txt");
  3. open(OUT,">localm1");
  4. $a=0;
  5. $b=0;
  6. $c=0;
  7. $i=0;
  8. while(defined($line=<INP>))
  9. {
  10. @col=split(" ",$line);
  11. $a=$col[1]; #the 2nd column. B
  12. if(($a<$b)&&($b>$c))
  13. {
  14. #print OUT "$i ${col[0]} $b \n";
  15. print OUT "$i $b \n";
  16. #print OUT "$i $b \n";
  17. }
  18. $c=$b;
  19. $b=$a; #b = a. b is the temporary max
  20. $i++;
  21. }

  22. close(INP);
  23. close(OUT);
然后用gnuplot
>plot 'localm1'
即可得出图片。
图片效果由于我不熟悉gnuplot便用得最原始的。

最后引用冷潇泠画的一个图,这个图更清晰。也是gnuplot。也可以用excel画。我都只知道理论上可画,但实际上都没经验。


分享到:
评论

相关推荐

    ackerman函数

    这种实现对于理解和学习递归、动态规划以及函数计算的效率有重要的价值。在实际编程中,这样的优化技术也被广泛应用于其他递归函数,特别是那些具有相同子问题的函数,例如斐波那契数列或最短路径计算。

    Ackerman函数的C++实现

    本篇文章将深入探讨Ackerman函数的基本概念、特性以及其在C++中的具体实现。 #### Ackerman函数的概念与特性 Ackerman函数由德国数学家Wilhelm Ackermann于1928年首次提出,是递归函数理论的一个经典案例。它被...

    三元Ackerman函数的非递归实现

    Ackerman 函数是一种著名的递归计算函数,常用于探讨计算复杂性和递归理论。它以数学家 Moses J. Ackerman 的名字命名,其定义为一个三元运算符,通常写作 A(m, n),其中 m 和 n 是非负整数。 Ackerman 函数的计算...

    ackerman函数_ackerman函数_

    Ackerman函数,通常被称作阿克曼函数,是一个非递归定义的多变量阶乘类函数,由美国数学家Maurice Karnaugh在1962年提出,但以计算机科学家Morse和Ackerman的名字命名。这个函数在计算理论和算法设计中常被用作一个...

    ackerman函数的两种非递归算法及源代码

    本文将深入探讨 Ackerman 函数的两种非递归实现方法:数组递推和栈消除递归,并通过源代码分析它们的工作原理。 1. Ackerman 函数定义: Ackerman 函数通常表示为 A(m, n),其中 m 和 n 是非负整数。它的定义如下:...

    Ackerman函数

    算法学习过程中学习的Ackerman函数,C++代码,Main函数

    递归和非递归方式计算Ackerman函数

    Ackerman函数,通常被用来作为一个展示递归深度和复杂性的例子。它是一个多变量的、非线性的递归函数,由数学家Morton Ackerman在20世纪30年代提出。这个函数以其非平凡的递归结构和极端的快速增长而闻名。 首先,...

    阿克曼函数非递归实现

    通过以上分析,我们可以看到,阿克曼函数的非递归实现主要涉及堆栈操作、递归转换以及对计算复杂性的理解。这个话题对于学习数据结构和算法的学生来说,是一个挑战性的实践项目,有助于提升他们的编程技能和对复杂...

    ackermann函数的递归实现和非递归实现

    总结,阿克曼函数的递归和非递归实现都是理解递归、堆栈以及数据结构在计算复杂性中的作用的重要案例。非递归实现通过堆栈有效地避免了递归调用的限制,展示了如何用迭代方法解决原本看似需要递归的问题。

    非递归方法编写阿克曼函数

    数据机构的晦涩难懂我有亲身经历,所以提供一些算法来帮助大家!

    Ackerman递归函数int ack(int m,int n)

    Ackerman递归函数int ack(int m,int n)

    递归子程序计算ackermann函数ACK(m,n)

    Ackermann 函数是一种著名的递归函数,用于展示非平凡的递归行为。它是由荷兰数学家马里乌斯·阿克曼在1928年提出的。该函数定义如下: 1. ACK(0, n) = n + 1 2. ACK(m, 0) = ACK(m-1, 1) 3. ACK(m, n) = ACK(m-1, ...

    阿克曼函数 c程序 递归与非递归算法的综合

    通过比较这两个程序,你可以看到递归和非递归算法在实现上的差异,以及它们在处理复杂递归问题时的不同策略。 理解并分析这两个程序,可以帮助你深入学习C语言编程,特别是递归和栈的概念。同时,这也为理解递归...

    带有move_basegmappingSLAMTEB规划器的GazeboROS上的Ackerman机器人___下载.zip

    `ackerman_ros_robot_gazebo_simulation-master`这个文件夹很可能是项目的源代码仓库,其中可能包含C++或Python的ROS节点代码,配置文件,Gazebo世界模型,以及启动脚本等,这些都支持上述功能的实现。 通过学习和...

    阿克曼函数递归算法

    `ackerman` 函数实现了阿克曼函数的递归定义。它包含三个基本情况: 1. 当 \(n = 0\) 时,返回 \(m + 1\)。 2. 当 \(m = 0\) 且 \(n &gt; 0\) 时,返回 \(A(n-1, 1)\)。 3. 对于其他情况,即 \(n &gt; 0\) 且 \(m &gt; 0\) 时...

    Ackerman非递算法 Ackerman非递算法 Ackerman非递算法

    Ackerman非递算法,全称为阿克曼函数,是计算机科学中一个著名的非递归定义的函数,由美国数学家Maurice Karnaugh在1934年提出,但以计算机科学家Morse和Godel的学生Gunter Ackerman的名字命名。这个函数主要用于...

    196-习题作业-作业五1

    Ackerman 函数是一种非常特殊的数学函数,它在计算复杂度理论和计算机科学中被用作一个例子,展示了非平凡的递归函数行为。这个函数以其创造者 Moses Ackerman 的名字命名,它不是普通的算术或组合函数,而是具有...

    Python递归函数 二分查找算法实现解析

    在本篇文章中,我们将会探讨Python中的递归函数和二分查找算法,以及它们在实际问题中的应用。递归是一种强大的编程技术,它允许函数调用自身。二分查找算法是一种高效的搜索技术,适用于有序列表,通过反复将搜索...

    Ackermann 函数:一个简单的 Matlab 函数来计算 Ackermann 函数。-matlab开发

    由数学家 Willhelm Ackermann 开发的 Ackerman 函数以其极快的增长速度令人印象深刻,并具有更多迷人的功能。 有了这个简单的代码,Ackermann 函数就可以在 Matlab 中轻松使用。

Global site tag (gtag.js) - Google Analytics