
一般说来,可以用很简明的规则来得到极其巨大的数。而相比之下,TREE函数的规则算不上简单。
表达树的嵌入,至少需要用到一系列操作(删除子顶点数为0或1的顶点)所得的闭包,而其它表达方式(例如直接用嵌入函数来表达)则更加复杂。
为了说明“获得极其巨大的数,它所需的规则能有多么简洁”,这里我列举一些javascript大数高尔夫的结果。这些结果于googology discord讨论群得出。列表见Constructor Lower Bounds。
javascript大数高尔夫:用尽可能少的字符,在javascript语言中,输出尽可能大的数。
这里的javascript语言有一些调整。包括:
即便是9e999也能正常运行。
6~8字,是以9为底的乘方。比以2为底的左移更强一些。
9~19字,用到迭代的乘方。幸运的是,javascript的乘方是右结合的。
至此,天文学、宇宙学、量子物理上已经没有什么可以与之比拟的数了。
20~24字,四级运算。右参数是简单的数。
其中,for(a;b;c)d的输出是最后一次计算的d的输出。
25~30字,四级运算又迭代了。
f本身就可能调用自己,但在计算中,只有x等于0的时候才不会继续调用f。
i和j是全局变量,它们跟踪迭代的层级。如果用Hardy hierarchy来表示,这对应的增长率。
j值每减一,就相当于迭代一次乘方;i值每减一,就相当于迭代一次四级运算。
x是全局变量,现在它用来跟踪“底数”,而非迭代的层级。迭代的层级,用每次调用n(y-1)的时候出现的(局部变量)y值来跟踪。而连续调用n(y)之间,x只是单纯的减小,这就相当于迭代了“连续调用开始之前的那个x”遍n(y-1)所对应的x的增长。
调用n(0),直接得到9,是个常数。
开始调用n(1),那就相当于要“调用n(0),然后把结果乘到上次调用的结果里面”x遍,最终得到。
开始调用n(2),那就要迭代x遍“调用n(1)所得的指数函数”,最终得到9↑↑x。
……
简而言之,这里的局部变量y,代表着这次调用n对应的x的变化相当于——它与fast-growing hierarchy(而非Hardy hierarchy)挂钩。
全局变量x仍然是底数。每次调用n(y-1||x)时的局部变量y仍然代表“x的增长相当于FGH中的什么序数”。然而,这里的序数已经不局限于有限的数,因此需要把无限的序数编码成有限的整数y。
调用n(9),得常数9。
调用n(10),是n(9)之间的乘法,得。
调用n(11),是n(10)的迭代,得9↑↑x。
如此继续,大于9的y值,就相当于FGH中的y-8
——那么,小于9的y值呢?
如果y=1,那么调用n(y-1||x)就是调用n(x),这就是一个超运算了。这样,y=1就相当于FGH中的ω。
调用n(2),是y=1时调用的迭代,相当于FGH中的ω+1,也就是葛立恒函数的增长率。
调用n(3),相当于FGH中的ω+2。
……
调用n(8),相当于FGH中的ω+7。
注意到,“y-9”中的9表示超运算之上、之下的界限,而“n(x=8)”中的8,这个“初始值”,则代表最终我们会到达“FGH中的ω+7”。为了得到更大的数,比如到达“FGH中的ω+97”,这两个值都要更改,开销是2个字,而不像以前那样只需1个字的开销。
这段代码与39字的类似,只不过初始值不需要额外给定了,只需更改“y-99”中的99,就可以获得更大的数。
y=0,得常数9。
y=-1,相当于FGH中的2。
y=-2,相当于FGH中的3。
如此无限往下。
y=99,相当于FGH中的ω。此时调用n(y-99?y+1:~x)就是调用n(~x),而~x等于-1-x。
y=98,相当于FGH中的ω+1。
y=97,相当于FGH中的ω+2。
……
y=1,相当于FGH中的ω+98。比延续39字代码所得的“相当于FGH中的ω+97”更好。
除了“增加界限及初始值需要1或者2个字”以外,这些代码没有什么区别。这里,42、44字的代码分别以“a=9”“a=99”来考虑。
全局变量x仍然是底数。每次调用n(y<0?x-~y:y-a)时的局部变量y仍然代表“x的增长相当于FGH中的什么序数”。
y=0,得常数。
y=a,相当于FGH中的2。
y=a*2,相当于FGH中的3。
如此无限向上,y值必须是a的倍数。
y=-1,相当于FGH中的ω。
y=a-1,相当于FGH中的ω+1。
y=a*2-1,相当于FGH中的ω+2。
如此无限向上,y值除以a的余数必须是a-1。
y=-2,相当于FGH中的ω·2。
y=a-2,相当于FGH中的ω·2+1。
y=a*2-2,相当于FGH中的ω·2+2。
如此无限向上,y值除以a的余数必须是a-2。
……
y=-(a-1),相当于FGH中的ω·(a-1)。
y=1,相当于FGH中的ω·(a-1)+1。
为了保留余数,n(y)+n(y<0?x-~y:y-a)中间必须是加法,而不能是乘法。而y<0时使用x-~y = x+y+1,则会让余数加1(x是a的倍数),进入前一个“ω的多少倍”区域的迭代之中。
全局变量x仍然是底数。每次调用n(y-9?y%2?y+2<<x:y/2:~x)时的局部变量y仍然代表“x的增长相当于FGH中的什么序数”。
y=-1,得常数。y=-2,相当于FGH中的2。y=-4,相当于FGH中的3。y=-8,相当于FGH中的4。……每当y是非零偶数,调用n(y-9?y%2?y+2<<x:y/2:~x)就是调用n(y/2),得到“y值减半的情况下x的增长”的迭代。
y=-3,相当于FGH中的ω。y=-6,相当于FGH中的ω+1。y=-12,相当于FGH中的ω+2。……y=-5,相当于FGH中的ω·2。y=-10,相当于FGH中的ω·2+1。……y=-7,相当于FGH中的ω·3。……每当y是非9的奇数,调用n(y-9?y%2?y+2<<x:y/2:~x)就是调用n(y+2<<x),进入前一个“ω的多少倍”区域的迭代之中。
y=9,相当于FGH中的。调用n(y-9?y%2?y+2<<x:y/2:~x)就是调用n(~x)。由于x值会从开始调用的时候一路减到1,中途每一个n(~x)都要调用一次,这样做足以到达ω·(大概与x相当)的区域。
y=18,相当于FGH中的。y=36,相当于FGH中的。……y=7,相当于FGH中的。y=14,相当于FGH中的。……y=5,相当于FGH中的。……y=3,相当于FGH中的。……y=1,相当于FGH中的。y=2,相当于FGH中的。y=4,相当于FGH中的。y=8,相当于FGH中的。
与52字类似,但y=99就相当于FGH中的。y=8则相当于FGH中的。
可见,只需更改,“y-9”中的界限9就可以增加数值,而“n(x=8)”中的初始值8并不需要更改。
全局变量x仍然是底数。每次调用n(y%2?y<0?y-~x:y-8<<x:y/2)时的局部变量y仍然代表“x的增长相当于FGH中的什么序数”。值得注意的是,n(y%2?y<0?y-~x:y-8<<x:y/2)的调用一定是在乘号前面的n(y)算完以后立即调用,因此x值一定是若干个(至少一个)9相乘,也就是9的次方;x一定是除以8余1的正整数。
y=-1,得常数。y=-2,相当于FGH中的2。y=-4,相当于FGH中的3。y=-8,相当于FGH中的4。……每当y是非零偶数,调用n(y%2?y<0?y-~x:y-8<<x:y/2)就是调用n(y/2),得到“y值减半的情况下x的增长”的迭代。
y=7,相当于FGH中的ω。y=14,相当于FGH中的ω+1。y=28,相当于FGH中的ω+2。……y=15,相当于FGH中的ω·2。……y=23,相当于FGH中的ω·3。……每当y是正奇数,调用n(y%2?y<0?y-~x:y-8<<x:y/2)就是调用n(y-8<<x),进入前一个“ω的多少倍”区域的迭代之中。这些正奇数y值保持“除以8的余数”不变。那样就处在同一个“的多少倍”区域的迭代之中。
y=-3,相当于FGH中的。y=-6,相当于FGH中的。y=-12,相当于FGH中的。……y=5,相当于FGH中的。y=10,相当于FGH中的。……y=13,相当于FGH中的。……y=21,相当于FGH中的。……y=-5,相当于FGH中的。y=-10,相当于FGH中的。……y=3,相当于FGH中的。……y=11,相当于FGH中的。……y=-7,相当于FGH中的。……y=1,相当于FGH中的。……y=9,相当于FGH中的。每当y是非-1的负奇数,调用n(y%2?y<0?y-~x:y-8<<x:y/2)就是调用n(y-~x)。由于前述性质,此时的x总是除以8余1的正整数,那样y-~x = y+1+x除以8的余数就要比y大2。余数7、5、3、1分别相当于“的0、1、2、3倍”区域的迭代。
与54字类似,但y值变成了相反数。y=1,得常数。y=3,相当于FGH中的。y=5,相当于FGH中的。y=7,相当于FGH中的。而y=9的情况,n(y%2?y>0?y+~x:y+8<<x:y/2)仍按照n(y+~x)来运行,因此相当于FGH中的。
与54字类似,只不过“除以8的余数”的概念改成了“除以98的余数”。因此y=8相当于FGH中的。
全局变量x仍然是底数。每次调用n(y%++s?-s:y/s--*s**x,n(y),s=1)的外层n时的局部变量y仍然代表“x的增长相当于FGH中的什么序数”。s则临时辅助。当y%++s?-s:y/s--*s**x计算完毕后,调用n(y)(y值没有变化,只是x值有变化。这基本上相当于“迭代x次”的含义了),做x的增长,然后把s变成1,再开始这个外层n函数的运行。
y%++s?-s:y/s--*s**x的含义:y提出一个s+1的因子,然后乘上s的很多次方。如果提不出这个因子,那就得-s,然后s值增加1。
考虑到“-s”结果会造成s的变化,那么,从s=1出发,利用n(y)进行多次迭代,其含义为:先试着从y提出因子2,如果不能,就再试着提出因子3,如果不能,就再试着提出因子4,……,直到能提出某个因子为止,再往里调用n(y),就全都是同一个s了。这个因子应该是个素数。如果y能提出一个合数因子,那y也能提出此合数的最小素因子。
由此得到各个y值所编码的增长率。
调用n(-1),x没有变化。
调用n(-2),x先增加0,再增加1,再增加2,……,最后增加x-1。总结果是x变成了。
调用n(-4),相当于平方的迭代,基本上是二重指数。
调用n(-8),相当于FGH中的3。调用n(-16),相当于FGH中的4。……这些y值只有因子2。
对于偶数y,提出因子2,然后乘1的很多次方,这就是简单的除以2。
调用n(-3),相当于FGH中的ω。n(-5)、n(-17)、n(-257)、n(-65537)也如此。调用n(-6),相当于FGH中的ω+1。调用n(-12),相当于FGH中的ω+2。……调用n(-9),相当于FGH中的ω·2。n(-15)、n(-25)、n(-51)等也如此。调用n(-18),相当于FGH中的ω·2+1。调用n(-36),相当于FGH中的ω·2+2。……调用n(-27),相当于FGH中的ω·3。……调用n(-81),相当于FGH中的ω·4。这些y值只有因子2与费马素数因子。
对于费马素数的乘积y,提出最小素因子,然后乘以2的很多次方,进入前一个“ω的多少倍”区域的迭代之中。
为了说明y值编码,这里引入一个概念:k阶数。它对大于1的整数定义。
于是,像刚才那样,2的次方都是1阶数。2阶素数就是费马素数。最小的3阶素数是7,最小的4阶素数是23,最小的5阶素数是47,最小的6阶素数是283,……,可以参考A061092、A082449。
如果一个正整数y,分解质因数得到 ,其中是i阶数,那么-y所代表的序数是,
即所有i阶素因子的指数之和,作为的右乘系数,然后这些ω的单项式按次数降序排列并相加。
初始的n(x=s=99),会依次运行n(-198)、n(-197)、……、n(-2)、n(-1),其中涉及的最大序数是n(-141)对应的。
n函数与57字的完全相同,但它还要涉及一些正数y值。
调用n(1),它将避开所有s值,这样它就会总是得到-s——有多少x可以迭代,就得到多少个-s。这些-s会扫过很高阶数(差不多有x阶,少不了多少),因此ω指数也比x少不了多少。于是这就相当于FGH中的。
其它正数y编码的序数,与负数的情况相同,只是在这一大串ω-多项式左边还要加个。
初始的n(x=8,s=7),依次运行n(1)、n(7)、n(49)、n(343)、n(2401)、n(16807)、n(117649)、n(823543),其中涉及的最大序数是n(823543)对应的。
现在,疑难数论问题出现了。当内层的n函数计算完毕,x值是计算结果,s值回到1,然后就要再次计算n(x)——这里的x是个很大的数。那么,这个x(内层n函数的计算结果)的阶是多少呢?能否认为x的阶“比x小不了多少”?
如果答案是肯定的,那么每一层n函数就几乎相当于FGH中的。
它利用到Primitive sequence,此结构支持的HH增长率可达。
b是底数,而字符串a代表primitive sequence本身(但左右反过来了)。每次“减小”a,都要给b加1。
“a=a.slice(1).replace(a[0]-1,'$&$`$&'.repeat(++b))”是“减小”a所做的事情。首先slice(1)去除最左边的数字,然后从左往右找到等于(那个数字-1)的数字(a[0]-1的部分),用“$&”表示。用“$`”表示刚才查找的过程中扫过的数字串。现在a.slice(1)的最左边是“$`$&”,把它改成“$`$&$`$&$&$`$&……$&$`$&$&$`$&”(b+1个“$&$`$&”)。
数字串0代表Hardy hierarchy的增长率1。数字串10代表HH增长率ω。数字串210代表HH增长率。数字串3210代表HH增长率。也就是FGH增长率。数字串43210代表HH增长率。也就是FGH增长率。……每增加一种新的数字,增长率就在ω-指数塔上增加一层。
它利用到Goodstein函数,其HH增长率为。
b是Goodstein数列递推过程中的底数。
B(y)把y写成以b为底的遗传记法,然后把所有出现的b都变成b+1。B(y,x)计算B(y)之中项的系数。“+B(y/b|0,x+1)”意味着对付多项式的下一个项,而“**B(x)”则意味着对付指数中可能出现的b。
i则分为两部分。在界限(9、99、9e9)之前,普通的左移,以获得指数塔高度;在界限之后,就作为Goodstein数列的初值开始递推。Goodstein数列的初值得达到b↑↑n才能得到的最终结果。
这一部分的javascript高尔夫,看似没有达到最优化的程度。只做简单介绍。
它利用到Difference sequence number(左右反向)。其HH增长率达到φ(ω,0)。
与77~84字代码相比,它增加了对NaN的利用,其HH增长率达到φ(ω,0)·ω。
HH增长率分别在。
86~89字代码的延伸,HH增长率为φ(ω,ω)。
这一部分的javascript高尔夫,似乎也没有达到最优化的程度。只做简单介绍。
它利用到Bashicu矩阵第1版(列(a,0)编码成2a+2,列(a,1)编码成2a+3,左右反向)。这是个不良序的系统,(0,0)(1,1)(2,1)(3,1)(2,0)(1,1)(2,1)(3,1)附近是它出现无限循环的地方。我们只能从下方接近,却不能超越它。
96字代码,大概输出。97字代码,大概输出。98字代码,大概输出。99字代码,大概输出。100字代码,大概在略高于的层次。
程序的运行分为两部分。
首先初始化a,它变成[[…[[0]]…]](对于不同代码,分别有1+9、1+99、1+9e9、……对括号。以后这个0会变成null)。然后反复给a施以P函数的变换,输出变成null所需的步数。
这个P函数,简而言之,展开计算“把middle-growing hierarchy应用到序数上”所得的记号。理论上,这一理念可以达到增长率,同时也是的增长率极限;实际上,它也达到了这个增长率。详解见Golf a number bigger than TREE(3)。
此处的P函数加入了初始化阶段(b≤9)和实际将a变换(b>9)的判断。而每次j增加1,就意味着应用了一遍。总的来看,大概输出。
它利用的是Bashicu矩阵(左右反向)。其增长率介于的极限与二阶算术的极限之间。
Bashicu矩阵的数值记法,是链接介绍页中的记法。而现在这3段程序所使用的,则是距离记法——用某元素的值表达它与它的父元素之间的列距离。
双层数组a代表Bashicu矩阵。a内每一个数组代表Bashicu矩阵的一列;内数组从左往右,代表Bashicu矩阵的一列之中从上往下。内数组中的数值代表“从这个元素起,往正右方数多少列,刚好到达它的父元素”。同行元素之间可能存在“父元素”的二元关系。父元素的父元素的……父元素(重复0次或更多)则是祖先元素。Bashicu矩阵中,如果某个元素x是另一元素y的父元素,那么x上方元素就必须是y上方元素的祖先元素;在它的展开过程中,这个条件也要一直维持。
全局变量i、r、c,局部变量e,它们的引入都为了展开矩阵a。
如果i>r,进入r=(c=a.shift(i=0)).pop(),a的最左列给c,然后c的最下元素给r。现在i≤r。
如果i≤r,进入a=[Object.assign(a[r-1].map(e=>e>i?e+r:e),i++||c),...a],也就是展开过程。r本是定值,表示a.shift之前,根列(a的最左列的最下元的父元素所在列)的列标(最左列的列标是0,向右依次增加)。由于在展开过程中,a的左边一直在增添列,实际上a[r-1]扫过了a.shift之前,根列和它左边的所有列。在展开过程中,i代表已经展开出了多少列,也代表目前的根列在第i+r-1列。
其中,每一个i值,对应于展开一列的计算。a[r-1]要复制过来,然后它每一行的“父元素关系”也要复制过来。其中,
而最初i等于0的情况,a[r-1]是根列,每一行元素都e>i,但c中出现的元素都原原本本地赋给新列,只有c中没有的原最下元(及其下方的元素)按照e>i行事,其父元素链接到了根列相应行元素的父元素。
当i=r相应的展开完成后,i变成r+1,接下来进入r=(c=a.shift(i=0)).pop()之中。
如果最左列为空(数值记法中的(0,0,0,…0,0)),那么r=(c=a.shift(i=0)).pop()就将结束for循环。程序输出上次展开时最左列(数值记法中,它一定是(1,0,0,…0,0))与根列(数值记法中,它一定是(0,0,0,…0,0))的距离。
逻辑是同样的。
更新:如果允许使用浮点数,那么“假燃烧数”(燃烧数的一个下界)可以得到更优越的结果。
利用的是这样一个函数:。如果x是非负整数,那么1/m(x)的增长率与燃烧数相同,都是,但具体的数值不同。
利用的是这样一族函数:。如果x是非负整数,那么的增长率达到了。
关于此函数的性质,可参考
即使不知如何进一步扩展,也可以考虑把以往的迭代类代码用上来。
