我试图密切关注公式,但不知怎的,我得到的只是一个圆圈。这是在mandelbrot设置的坐标,我明白了很多。
for(x=-50;x<50;x++){
for(y=-50;y<50;y++){
// Canvas pixel coordinates to -2,2
var x2 = x * 0.04;
var y2 = y * 0.04;
var i = 0;
var z = 0;
var c = Math.sqrt( x2*x2 + y2*y2 );
while(true) {
if( i > 20 || z > 4.0 ) {
break;
}
z = z*z + c;
i = i + 1;
}
}
}
的jsfiddle: https://jsfiddle.net/d4fj1n63/
答案 0 :(得分:4)
您需要执行复杂的算术运算。
var x3 = 0, y3 = 0, k = 0;
while (x3*x3 + y3*y3 < 16 && k++ < 20) {
var tmp = x3*x3 - y3*y3 + x2;
y3 = 2*x3*y3 + y2;
x3 = tmp;
}
公式为 z k +1 = z k 2 + c , z 0 = 0或等效 z 1 = c
其中 c 是当前位置,即 c = x2
+ i ⋅y2
。
我有 z = x3
+ i ⋅y3
所以 z 2 =( x3
+ i ⋅y3
) 2 = x3
2 +2⋅ i ⋅x3
⋅y3
+ i 2 ⋅y3
2 。
使用 i 2 = -1,这简化为 z 2 =(x3
2 - y3
2 )+ i ⋅(2⋅x3
⋅y3
)并向我添加{ {1}}即c
和x2
。
请参阅https://jsfiddle.net/d5avqq5w/了解即时演示。
原始代码在y2
步骤中丢弃了角度信息,因为在该点之后未使用z = Math.sqrt( x2*x2 + y2*y2 )
和x2
。因此,得到的颜色 与角度无关,即由同心圆组成。
The page you gave as a reference处理复数的绝对值。但Mandelbrot公式的迭代步骤应该按原样对复数进行操作,而不是复数的任何绝对值,因此遵循该公式是不合适的。
有一个绝对值的有效应用,即在决定是否终止循环时(即检测分歧)。 The other page you referenced只写了
z n 的模数(长度)超过给定值。
没有明确给出阈值。我使用了阈值4,但我通过测试 z 长度的平方是否超过16来避免平方根。那就是y2
in我的代码来自。更常见的是使用2作为阈值(即4为平方测试),但我觉得使用4将更接近你所拥有的代码,即更适合强调比较绝对值和比较其平方之间的区别。使用4代替2可能会导致我们稍后检测到偏差,导致循环退出时计数器变量的值略高。
请注意,Wikipedia也有一些伪代码,您可能将其用作起点,并解释代码中的实值算法如何与本文其余部分中的复值算法相关联
答案 1 :(得分:2)
你犯了一个数学错误.C,Z是复数,但你把它们视为真实的。
我对您的代码进行了最小程度的更正,因此它按预期工作。
var canvas = $('canvas');
var ctx = canvas[0].getContext('2d');
for(x=-50;x<50;x++){
for(y=-50;y<50;y++){
var x2 = x * 0.04;
var y2 = y * 0.04;
var i = 0;
var z = 0;
//c - complex number. so c = x2+i*y2, where i^2 =-1
//var c = Math.sqrt( x2*x2 + y2*y2 );
var xi= x2;
var yi=y2;
while(true) {
if( i > 50 || xi*xi+yi*yi > 4.0 ) {
break;
}
// z - complex number, so on every step we should calculate real and imaginary parts
//z^2 = (x^2-y^2)+i*(2*x*y), i^2 =-1
var tmp = xi*xi - yi*yi+x2;
yi = 2*xi*yi+y2;
xi = tmp;
i = i + 1;
}
var color = parseInt(15/21*i).toString(16);
ctx.fillStyle = '#'+color+color+color;
ctx.fillRect((x+50)*2,(y+50)*2,2,2);
}
}