0

私は今夜​​家に帰り、マンデルブロ/ジュリアフラクタルジェネレーターを手に入れたいと思っています。これは以前にC++で行ったプロジェクトですが、今回はC#で回転させて、WinFormsアプリにしたり、マルチスレッドを使用して画像を生成したりできるようにします。

ただし、使用を検討したものの、松葉杖になってしまう可能性があることの1つは、組み込みのComplex構造体です。一見すると、見栄えがします。1つの構造体に組み込む必要のあるすべての操作。しかし、よく見ると、構造体がdoubleを使用していることがわかります。ダブルスには15-16有効数字しかありません。彼らの力は彼らの範囲です。複素平面上の(-2、-2)から(2,2)の範囲にのみ関心があるので、範囲には関心がありません。精度はありません。小数は28桁の有効数字です。

したがって、質問。ここに行く方法は何ですか?

  1. 組み込みのComplexタイプを使用します。結局のところ、それは単なる副次的なプロジェクトです。
  2. ダブルスの代わりに小数を使用して、自分のDecimalComplexタイプをロールします。良い「中道」のようです。私が必要とする計算は難しくなく(乗算と加算)、利用可能な精度のほぼ2倍になります。
  3. 壊れたために行きます。BigDecimalを実装し、BigIntegerを活用して小数点以下の桁数を自分で追跡し、それをUberComplex構造体に使用します。IIRCを最後にこれをいじったとき、私は同様のアイデアを使用しましたが、符号なしの64ビット長を使用しました。これにより、セット全体を360dpiでプロットする場合、おおよその領域のサーフェスが必要になるズームレベルになりました。太陽系の。私はおそらくそれよりももっとうまくやれるでしょう。
4

1 に答える 1

0

初めてマンデルブロー生成器を作成する場合は、このComplex型を使用することをお勧めします。時期尚早の最適化は諸悪の根源です。また、マンデルブロのクールさの半分は、わずか数行のコードで驚くべき画像を生成できることです。BigDecimalその目的のために独自の種類の敗北を実装するのに 2 時間を費やします。

ただし、あなたが言及したとは思わない別のオプションがあります。IEEE 浮動小数点の代わりに、固定小数点演算を使用します。足し算はまったく同じで、掛け算もほぼ同じなので、固定小数点演算はマンデルブロ生成に非常に便利(x * y)です(x * y) >> MANTISSABITS

スポイラー警告!これは、私が数年前に書いた不動点マンデルブロー生成器です。小数点以下 28 ビットを使用します。ツールチェーンが をサポートしている場合int128_t、またはアセンブリに落としても構わない場合、または長い間乗算を行うことを気にしない場合は、60 ビットの解像度に簡単に置き換えint32_tて取得できます。int64_t

#include <stdio.h>
#include <stdint.h>
#include "ImageFmtc.h"

/* Represent each component of the complex number
 * as a fixed-point value between -4 and +4. There
 * are 4 bits before the binary point and 28 bits after. */
typedef int32_t REALFIXED;
typedef int32_t IMAGFIXED;

#define MandelWidth   300
#define MandelHeight  300

unsigned char Image[MandelWidth][MandelHeight];


void mandelbrot(REALFIXED centerx, IMAGFIXED centery, REALFIXED windowsize)
{
    int x, y;
    unsigned char *image_ptr = &Image[0][0];

    for (y = 0; y < MandelHeight; ++y) {

    const IMAGFIXED z_imag = (1LL * windowsize * y / MandelHeight) + centery;

    for (x = 0; x < MandelWidth; ++x) {

        const REALFIXED z_real = (1LL * windowsize * x / MandelWidth) + centerx;

        REALFIXED t_real = z_real;
        IMAGFIXED t_imag = z_imag;

        int iter;

        for (iter=0; iter < 255; ++iter) {
        long long r2 = (1uLL * t_real * t_real) >> 28;
        long long i2 = (1uLL * t_imag * t_imag) >> 28;
        long long two_ri = (1uLL * t_real * t_imag) >> 27;
        if (r2 + i2 > (4LL << 28))
            break;
        t_real = (r2 - i2) + z_real;
        t_imag = (two_ri) + z_imag;
        }

        *image_ptr++ = iter & 0xFF;
    }
    }
    return;
}

REALFIXED double2fixed(double x)
{
    return (REALFIXED)(x * (1uLL << 28));
}

int main(int argc, char **argv)
{
    double cx, cy, scale;
    sscanf(argv[1], "%lf", &cx);
    sscanf(argv[2], "%lf", &cy);
    sscanf(argv[3], "%lf", &scale);
    mandelbrot(double2fixed(cx-scale/2), double2fixed(cy-scale/2), double2fixed(scale));
    WritePGM5("mandel.pgm", (unsigned char *)Image, MandelWidth, MandelHeight);
    return 0;
}

太陽系のサイズについて:数値の解像度が 60 ビットであっても、60 ビットの解像度で設定されたマンデルブロのピクセル精度のレンダリングを実際に計算できるとは限りません。乗算の丸め誤差は、ズームインすると、イメージが予想よりもはるかに速くぼやけてぼやけてしまうことを意味します。誰かが計算したと確信していますが、頭の中でそれを知りません。キーワード「エラー伝播」。

于 2012-09-20T23:12:02.083 に答える