代码之家  ›  专栏  ›  技术社区  ›  Dennis Haarbrink

分形解释

  •  5
  • Dennis Haarbrink  · 技术社区  · 15 年前

    一段时间以来,我一直对分形、分形背后的数学以及分形产生的视觉效果感兴趣。

    我真的搞不懂如何把数学公式映射成一段能画出这幅图的代码。
    Pc(z) = z * z + c
    与以下代码相比如何:

    $outer_adder = ($MaxIm - $MinIm) / $Lines;
    $inner_adder = ($MaxRe - $MinRe) / $Cols;
    for($Im = $MinIm; $Im <= $MaxIm; $Im += $outer_adder)
    {
      $x=0;
      for($Re = $MinRe; $Re <= $MaxRe; $Re += $inner_adder)
      {
        $zr = $Re;
        $zi = $Im;
        for($n = 0; $n < $MaxIter; ++$n)
        {
          $a = $zr * $zr;
          $b = $zi * $zi;
          if($a + $b > 2) break;
          $zi = 2 * $zr * $zi + $Im;
          $zr = $a - $b + $Re;
        }
        $n = ($n >= $MaxIter ? $MaxIter - 1 : $n);
        ImageFilledRectangle($img, $x, $y, $x, $y, $c[$n]);
        ++$x;
      }
      ++$y;
    }
    

    代码并不完整,只是为了简洁起见显示了主要的迭代部分。

    所以问题是:有人能给我解释一下数学和代码的比较吗?

    1 回复  |  直到 15 年前
        1
  •  18
  •   user187291    15 年前

    wikipedia article 决定写下我在这里发现的东西。 就像他们说的,如果你想理解某事,试着向别人解释。;)

    好的,我们要对复数进行运算。复数实际上是一对(实数)数,因此,对于我们php程序员来说,让它成为一个两元素数组。

        /// Construct a complex number from two reals
        function cpl($re, $im) {
            return array($re, $im);
        }
    

    现在我们需要告诉php如何对复数进行算术运算。我们需要加法,乘法和模(“norm”)运算符。(见 http://mathworld.wolfram.com/topics/ComplexNumbers.html 更多细节)。

        /// Add two complex numbers.
        function cadd($p, $q) {
            return cpl(
                $p[0] + $q[0],
                $p[1] + $q[1]);
        }
    
        /// Multiply two complex numbers.
        function cmul($p, $q) {
            return cpl(
                $p[0] * $q[0] - $p[1] * $q[1],
                $p[0] * $q[1] + $p[1] * $q[0]);
        }
    
        /// Return the norm of the complex number.
        function cmod($p) {
            return sqrt($p[0] * $p[0] + $p[1] * $p[1]);
        }
    

    现在我们编写一个函数,如果给定的(复数)点$c属于mandelbrot集,则返回true

    c 如果所有点 z = z^2 + c 躺在半径为2的圆内。

    • 每一步我们计算z=z*z+c。
    • modulus of z >2-也就是说,我们在圆外-点不在集合中
    • 否则重复该步骤。

    为了防止循环不断,限制最大迭代次数。

        function is_in_mandelbrot_set($c, $iterations) {
            $z = cpl(0, 0);
            do {
                if(cmod($z) >= 2)
                    return false;
                $z = cadd(cmul($z, $z), $c);
            } while($iterations--);
            return true;
        }
    

    其余的与数学无关,这是很明显的

        function mandelbrot($img, $w, $h) {
            $color = imagecolorallocate($img, 0xFF, 0, 0);
            $zoom = 50;
            $iters = 30;
    
            for($x = 0; $x < $w; $x++) {
                for($y = 0; $y < $h; $y++) {
    
                    // scale our integer points 
                    // to be small real numbers around 0
    
                    $px = ($x - $w / 2) / $zoom;
                    $py = ($y - $h / 2) / $zoom;
    
                    $c = cpl($px, $py);
    
                    if(is_in_mandelbrot_set($c, $iters))
                        imagesetpixel($img, $x, $y, $color);
                }
            }
    
            return $img;
        }
    
        $w = 200;
        $h = 200;
    
        header("Content-type: image/png");
        imagepng(
            mandelbrot(
                imagecreatetruecolor($w, $h), $w, $h));
    

    结果

    alt text