当前位置: 首页 > 知识库问答 >
问题:

对于复数,如何表示分叉函数

葛学民
2023-03-14

确实存在所谓的超操作序列。它的工作原理就像你构造乘法a*b=a a a... a,加上许多a重复b次。然后是指数化a^b=a*a*a*a*...*a,其中有许多a的乘法重复b次。然后,就有了四舍五入,表示为一个指数塔,就像a^^b==a^a^...^a,重复b次。

我有兴趣如何写这个函数,对于浮点数和复数?

我已经用glsl编写了乘法和求幂函数:

// complex multiplication:
vec2 cmul(in vec2 a, in vec2 b) {
    return vec2(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x);
}

// complex exponent e^a
vec2 cexp(in vec2 a) {
    float ea = exp(a.x);
    float vl = a.y;
    return ea * vec2( cos(vl), sin(vl) );
}

// complex natural logarithm ln(a)
vec2 cln(in vec2 a) {
    float ql = length(a);
    return vec2( log(ql), atan(a.y, a.x));
}

// complex power function a^b
vec2 cpow(in vec2 a, in vec2 b) {
    return cexp(cmul(cln(a), b));   
}

但是我被卡住了!我们如何编写ctet(在vec2a中,在vec2b中)tetration函数,不仅针对浮点数,而且针对整个复平面本身?

共有1个答案

田俊爽
2023-03-14

好吧,让我们仅从实域和整数b开始:

a^^b = a^a^a^a^a...^a  // a is there b times

在C中可以这样计算:

double tetration(double a,int b)    // a^^b = a^a^a^a... b times
    {
    double c;
    if (b<=0) return 0;
    for (c=a;b>1;b--) c=pow(a,c);
    return c;
    }

因为你已经得到了复杂领域的pow,你也可以在那里做同样的事情。。。为了保持这个简单,我现在不会碰它。。。

以下是一些结果:

a\b| 1|   2|            3|    4
-------------------------------
 1 | 1|   1|            1|    1
 2 | 2|   4|           16|65536
 3 | 3|  27|7625597484987|
 4 | 4| 256|             |
 5 | 5|3125|             |

所有这些超运算都与Ackermann函数有关,你可以在这里找到我的C语言迭代实现:

  • 如何将C移植到没有硬件堆栈的架构?

但是,由于增长速度极快,即使是double也将很快超出范围(因此缺少值)。。。

现在如何将b移动到实域?对于这一点,我们对代数方法一无所知,但几何方法是可能的。

简单地“绘制”a^^b作为变量b和常量a的函数,以b的整数值围绕所需的实b进行插值,然后使用整型域b作为控制点。它类似于获得函数的非整数阶导数。

所以(X,Y)将是您的(a^^b,b)。现在使用任何插值来构造实域函数。

线性插值将如下所示:

y0 = a^^(int(b)) 
y1 = a^^(int(b)+1)
a^^b = y0 + (b-int(b))*(y1-y0)

然而,需要高阶插值,插值参数也应该缩放到非线性度量。有关更多信息,请参阅:

  • 如何生成多点线性插值

经过一些详细说明(t^3)和log^2比例证明是足够的(使用我的128位浮点f128类的C示例只需将其重命名为double):

f128 tetration_fi(f128 a,int b)     // a^^b = a^a^a^a... b times
    {
    f128 c;
    if (b==-1) return 0.0;          // first singularity
    if (b== 0) return 1.0;          // second singularity
    if (b< -1) return 0.0;          // uncomputed
    for (c=a;b>1;b--) c=pow(a,c);
    return c;
    }
//---------------------------------------------------------------------------
f128 tetration_ff(f128 a,f128 b)    // a^^b = a^a^a^a... b times
    {
    int bi;
    f128 z0,z1,z2,z3,a0,a1,a2,a3,t,tt,ttt,o=2.0;
    if (b==-1) return 0.0;          // first singularity
    if (b== 0) return 1.0;          // second singularity
    if (b< -1) return 0.0;          // uncomputed
    bi=b.ToInt(); b-=bi;
    if (b.iszero()) return tetration_fi(a,bi);

    z0=tetration_fi(a,bi-1);        // known points around a^^b
    z1=pow(a,z0);
    z2=pow(a,z1);
    z3=pow(a,z2);

    z0=log2(log2(z0+o)+o);          // log^2 scale
    z1=log2(log2(z1+o)+o);
    z2=log2(log2(z2+o)+o);
    z3=log2(log2(z2+o)+o);

    t =0.5*(z2-z0);                 // cubic interpolation coeff.
    tt=0.5*(z3-z1);
    a0=z1;
    a1=t;
    a2=(3.0*(z2-z1))-(2.0*t)-tt;
    a3=t+tt+(2.0*(z1-z2));

    t=b-bi;                         // cubic interpolation
    tt=t*t;
    ttt=tt*t;
    z0=a0+(a1*t)+(a2*t*t)+(a3*t*t*t);

    z0=exp2(exp2(z0)-o)-o;          // linear scale
    return z0;
    }
//---------------------------------------------------------------------------

这就是我所比较的:

  • 四分体

我从a^^b中选择了相同的图基a,正如您所看到的,它非常匹配,只有1.0以下的范围稍微偏离。

让我们来看看复域分形

现在,当你想进入复杂域时,你不能像在现实中那样做,因为结果对于插值来说太混乱了。因此,我们只能使用整数b或使用Kneser算法进行计算。

幸运的是,我们有更多的方法来显示分形...例如,我们可以从a^^b中计算整数b,其中只有a是复杂的,并使用结果为输出着色。下面是GLSL示例(基于我的Mandelbrot着色器和你的复杂数学):

片段:

// Fragment
#version 450 core
uniform dvec2 p0=dvec2(0.0,0.0);        // mouse position <-1,+1>
uniform double zoom=1.000;          // zoom [-]
in smooth vec2 p32;
out vec4 col;
//---------------------------------------------------------------------------
// All components are in the range [0…1], including hue.
vec3 rgb2hsv(vec3 c)
    {
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
    }
//---------------------------------------------------------------------------
// All components are in the range [0…1], including hue.
vec3 hsv2rgb(vec3 c)
    {
    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
    }
//---------------------------------------------------------------------------
vec3 spectral_color(float l)        // RGB <0,1> <- lambda l <400,700> [nm]
    {
    float t;  vec3 c=vec3(0.0,0.0,0.0);
         if ((l>=400.0)&&(l<410.0)) { t=(l-400.0)/(410.0-400.0); c.r=    +(0.33*t)-(0.20*t*t); }
    else if ((l>=410.0)&&(l<475.0)) { t=(l-410.0)/(475.0-410.0); c.r=0.14         -(0.13*t*t); }
    else if ((l>=545.0)&&(l<595.0)) { t=(l-545.0)/(595.0-545.0); c.r=    +(1.98*t)-(     t*t); }
    else if ((l>=595.0)&&(l<650.0)) { t=(l-595.0)/(650.0-595.0); c.r=0.98+(0.06*t)-(0.40*t*t); }
    else if ((l>=650.0)&&(l<700.0)) { t=(l-650.0)/(700.0-650.0); c.r=0.65-(0.84*t)+(0.20*t*t); }
         if ((l>=415.0)&&(l<475.0)) { t=(l-415.0)/(475.0-415.0); c.g=             +(0.80*t*t); }
    else if ((l>=475.0)&&(l<590.0)) { t=(l-475.0)/(590.0-475.0); c.g=0.8 +(0.76*t)-(0.80*t*t); }
    else if ((l>=585.0)&&(l<639.0)) { t=(l-585.0)/(639.0-585.0); c.g=0.84-(0.84*t)           ; }
         if ((l>=400.0)&&(l<475.0)) { t=(l-400.0)/(475.0-400.0); c.b=    +(2.20*t)-(1.50*t*t); }
    else if ((l>=475.0)&&(l<560.0)) { t=(l-475.0)/(560.0-475.0); c.b=0.7 -(     t)+(0.30*t*t); }
    return c;
    }
//---------------------------------------------------------------------------
// complex domain math
vec3 color_wheel(vec2 a)    // complex -> polar -> HSV -> RGB
    {
    float an=(atan(-a.y,-a.x)*0.15915494309189533576888376337251)+0.5;
    float  r=length(a); r-=floor(r); r*=0.75; r+=0.25;
    return hsv2rgb(vec3(an,1.0,r));
    }
vec3 color_spectral(vec2 a) // complex -> wavelength -> RGB
    {
    float  r=length(a); r-=floor(r);
    return spectral_color(400.0+(300.0*r));
    }
vec2 cadd(vec2 a,vec2 b)    // a+b
    {
    return a+b;
    }
vec2 csub(vec2 a,vec2 b)    // a-b
    {
    return a-b;
    }
vec2 cmul(vec2 a,vec2 b)    // a*b
    {
    return vec2((a.x*b.x)-(a.y*b.y),(a.x*b.y)+(a.y*b.x));
    }
vec2 cdiv(vec2 a,vec2 b)    // a/b
    {
    float an=atan(-a.y,-a.x)-atan(-b.y,-b.x);
    float  r=length(a)/length(b);
    return r*vec2(cos(an),sin(an));
    }
vec2 csqr(vec2 a)           // a^2
    {
    return cmul(a,a);
    }
vec2 cexp(vec2 a)           // e^a
    {
//  e^(x+y*i)= e^x * e^(y*i) = e^x * ( cos(y) + i*sin(y) )
    return exp(a.x)*vec2(cos(a.y),sin(a.y));
    }
vec2 cln(vec2 a)            // ln(a)
    {
    return vec2(log(length(a)),atan(a.y,a.x));
    }
vec2 cpow(vec2 a,vec2 b)    // a^b
    {
    return cexp(cmul(cln(a),b));
    }
vec2 ctet(vec2 a,int b)     // a^^b
    {
    vec2 c=vec2(1.0,0.0);
    for (;b>0;b--) c=cpow(a,c);
    return c;
    }
//---------------------------------------------------------------------------
void main()
    {
    // poistion (double)
    dvec2 p=dvec2(p32);
    p=(p/zoom)-p0;          // x,y (-1.0, 1.0)
    // position (float)
    vec2 pp=vec2(p);

    // [chose function]

    // complex domain test function 1 (color wheel)
//  vec2 a=cdiv(cmul(csub(cmul(pp,pp),vec2(1.0,0.0)),csqr(csub(pp,vec2(2.0,1.0)))),cadd(csqr(pp),vec2(2.0,2.0)));
    // complex domain test function 2 (color wheel)
//  vec2 a=pp; a=cln(a);
    // exponentiation escape fractal 1 (color wheel)
//  vec2 a=cpow(pp,vec2(100,0));
    // exponentiation escape fractal 2 (color wheel)
//  vec2 a=vec2(1.0,1.0); for (int i=0;i<100;i++) a=cpow(a,pp);
    // exponentiation escape fractal 3 (color wheel)
//  vec2 a=vec2(0.0,0.0),b=vec2(1.0,0.0); float r=0.5,rr=1.0,wt=0.1; for (int i=0;i<20;i++){ a+=rr*cexp(vec2(-b.y,b.x)*wt); b=cmul(b,pp); rr*=r; } a*=(1.0-r);
    // tetration escape fractal (grayscale)
//  vec2 a=ctet(pp,100);
    // pentation escape fractal (grayscale)
    vec2 a=pp; for (int i=0;i<20;i++) a=ctet(a,20); a*=100.0;
                                                   
    // [chose coloring method]

    // grayscale based on escape
    float r=0.2*length(a); r-=floor(r); r=0.25+0.75*r; col=vec4(r,r,r,1.0);
    // RGB based on result
//  col=vec4(a,a.x+a.y,1.0);
    // result -> wavelength+intensity
//  col=vec4(color_wheel(a),1.0);
    // result -> spectral color
//  col=vec4(color_spectral(a),1.0);
    }

和传输预览:

这是我比较的:

  • 电力塔(四分之一)分形

它与我的结果相匹配,只是在x,y

所以我所做的是计算a^^100其中a是片段在屏幕上的复杂域位置

我还留下了一个测试函数(不是分形),用于测试着色方法和复杂数学,第一个来自Wiki,第二个是着色器结果(色轮):

你可以像mandelbrot或其他算法那样做转义测试来显示分形。

这里是zoom=500.0 pos=-0.188418 0.234466i的tetration(我喜欢灰度)的着色选项屏幕截图

最后一句话:

 类似资料:
  • 问题内容: 当“解构”一个元组时,我可以用来表示我不感兴趣的元组元素,例如 使用Python 2.x,如何使用函数参数表达相同的含义?我尝试使用下划线: 我还试图完全忽略该论点: 还有另一种方法可以达到相同目的吗? 问题答案: 这是我对未使用的参数的处理:

  • 表示函数 1. 广义损失函数 基于我们对监督学习的理解可知学习步骤: $(1)$选择问题的表示形式, $(2)$选择损失函数, $(3)$最小化损失函数。 让我们考虑一个稍微通用一点的监督学习公式。在我们已经考虑过的监督学习设置中,我们输入数据$x \in \mathbb{R}^{n}$和目标$y$来自空间$\mathcal{Y}$。在线性回归中,相应的$y \in \mathbb{R}$,即$\

  • 5.1.3 用对象表示复杂数据 程序是对数据进行操作的过程,因此数据表示和操作过程是编程时要考虑的两大问题。 我们已经熟悉用编程语言提供的数据类型来表示数据,例如用字符串表示雇员姓名,用整数表示年龄,用浮点数表示工资等。对于某些稍微复杂一点的数据我们也有适合的数据类 型来表示,例如雇员名单可以用一个字符串数据构成的列表来表示。当数据表示确定之后, 我们接着用各种数据类型所支持的数据操作来处理数据,

  • 我有一个自定义类数据列表,我想根据一个字段和值应该是另一个字段对它们进行分组。以下面的例子为例。 现在我想基于类对这些数据进行分组。预期的输出应该是一个映射,其中包含作为类的键和作为学生姓名列表的值。 我的代码是这样的:

  • 使用基于数组的二叉树实现,而不是旧的基于节点的实现,在速度/空间/总体性能方面有什么好处吗?我知道对基于数组的树进行旋转或任何其他复杂的修改都是可怕的,但是在简单的二叉树实现的情况下,你会说通过数组实现会更好吗?

  • 我试图从一个范围创建一个列表,但当我将它粘贴到另一个列表中时,我得到的是一个类,而不是我期望的列表- 代码: 这输出<代码>范围(0,3),