2

Okay, here's a weird one that I'm having problems with (compiled with gcc btw)

Below is source for a Mandelbrot fractal generator for command prompt. I've done this before and I wanted to speed test myself to see how fast I could produce the code required to actually generate a Mandelbrot fractal in the command prompt. Every so often I do this to kinda test myself out for fun

Anyways I've run into a new problem and I can't quite figure out what the issue is. When the fractal renders no matter how many iterations or what escapeValue I set it will ALWAYS appear as an oval! Its NOT supposed to do that.

For all you mandelbrot/cpp geeks out there can you help me identify why I'm not getting more of a 'mandelbrot' shape?

#include <stdio.h>
#include <math.h>

#define DOSWidth 80
#define DOSHeight 25

int iterations = 1024;
float escapeValue = 3.0f;

struct ivar {
    ivar(float _x, float _i) {
        x = _x;
        i = _i;
    }
    void log() {printf("(%g%c%gi)", x, (i<0)?'-':'+', fabs(i));}
    float magnitude() {return sqrtf(x*x+i*i);}
    ivar square() {return ivar(x, i)*ivar(x, i);}

    ivar operator + (ivar v) {return ivar(x+v.x, i+v.i);};
    ivar operator - (ivar v) {return ivar(x-v.x, i-v.i);};
    ivar operator * (ivar v) {return ivar(x*v.x-(i*v.i), x*v.i+i*v.x);};

    float x, i;
};

struct rect {
    rect(float _x, float _y, float _width, float _height) {
        x = _x;y = _y;width = _width;height = _height;
    }

    void setCenter(float cx, float cy) {
        x = cx-width/2.0f;
        y = cy-width/2.0f;
    }

    void log() {printf("(%f, %f, %f, %f)", x, y, width, height);}

    float x, y;
    float width, height;
};

int main() {
    rect region = rect(0, 0, 2.5f, 2.0f);
    region.setCenter(0, 0);
    float xSize = region.width / (float)DOSWidth;
    float ySize = region.height / (float)DOSHeight;
    for(int y=0;y<DOSHeight;y++) {
        for(int x=0;x<DOSWidth;x++) {
            ivar pos = ivar(x*xSize+region.x, y*ySize+region.y);
            bool escapes = false;
            for(int i=0;i<iterations;i++) {
                if(pos.magnitude() > escapeValue) {
                    escapes = true;
                    break;
                }
                pos = pos.square();
            }
            if(escapes)printf(" ");
            else printf("X");
        }
    }
}

Thanks if you got this far, appreciate your help!

Parad0x13
  • 2,007
  • 3
  • 23
  • 38

2 Answers2

3

You're just recursively squaring pos until its magnitude exceeds the limit. That won't produce a fractal; it will produce a unit circle.

You need to add the (x,y) coordinates to the squared value after every iteration. See Wikipedia.

EDIT: A couple small changes and voila.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Ah, your absolutely right! I was wondering why such a weird and consistent problem was happening! I forgot to actually iterate the Z(n)+C part of the equation lol. Thanks for your input, perhaps such a simple issue evaded me due to lack of sleep : D You rock – Parad0x13 Dec 25 '12 at 10:17
  • It's not as much practice, but `std::complex` cuts development time to ~10 mins: https://ideone.com/Zn7QVn – Potatoswatter Dec 25 '12 at 10:26
  • Hah, your right! But I wanted to develop it manually for the masochism. If your interested here's a pastebin of the source supporting zooming functionality and iteration manipulation too http://pastebin.com/K1f5Xruc – Parad0x13 Dec 25 '12 at 10:48
  • You sir, rock. Rock hardcore – Parad0x13 Dec 25 '12 at 23:58
  • @Parad0x13 This is what I ended up with, if you're interested. 20 screens at 80x32 within the ideone time limit. https://ideone.com/jBo5tX – Potatoswatter Dec 28 '12 at 16:03
  • That's an interesting approach to generating a Mandelbrot, forgive me for perhaps over analyzing your code but although you do use nice convenience libraries (complex, algorithm) the code isn't really easily readable. I know this was just supposed to be a 'cool look what I can do on a minimal system' but I feel you have potential to express your code much more intelligibly. Perhaps I'll rewrite your code to explain what I mean but just out of curiosity, was c or cpp your first language? – Parad0x13 Dec 28 '12 at 23:56
  • @Parad0x13 C was my first language, many many years ago. C++ is now my first language. For this I focused on speedups more than clarity. I don't think it's library calls that obscure the code though; they only help exposition. `std::begin` and `std::end` from C++11 would help but I chose to make it C++03 instead. Other than that, it's only missing comments. You could factor out a `class` or two, but that's just wasted effort if they're not reused, and it turns the code to spaghetti. – Potatoswatter Dec 29 '12 at 02:09
  • Aww, but factoring out classes is what makes good coding practices. The reason I ask if C was your first language was because usually people who start with C tend not to adopt the laws of OOP and I must admit I was one of them. Turns out factoring out classes and naming your variables carefully goes a very long way to making code intelligible and dynamic. I like the way you attack the problem but it was a little difficult to see EXACTLY what was happening right away since the code could use some refactoring for deobfuscation. – Parad0x13 Dec 29 '12 at 23:41
  • @Parad0x13 C++ is a multi-paradigm language; there are many things to refactor a mechanism or concept into. Reflexively selecting OOP misses out on language features which aren't OOP, or can add unnecessary complexity. For example, your `log` member function should probably be a non-member `operator<<`, and the constructors in `ivar` and `rect` are unnecessary since they could be aggregates. – Potatoswatter Dec 30 '12 at 04:47
  • I see your point, and I could have used complex to handle ivars but in this particular project I wanted to write it myself. I should have mentioned that I planned on possibly expanding this software to produce Julia sets and possibly dynamic fractals from command line input which would benefit from extreme factorization of methods. I also wanted the log convenience methods for future debugging as my experience doing things like this before showed it will help later on possibly : ) I don't think any complexity is unnecessary, as long as it deobfuscates the code – Parad0x13 Dec 30 '12 at 09:54
  • And I strongly feel as though if you have to comment your code you have failed as a programmer. I only think commenting is necessary if you cannot possibly represent the information in code. You should never have to comment as to what a variable does, or the logic flow of your operations or clarify what a method does with comments. Every method should do only one thing and one thing really well, that is the core of factorization and is what makes OOP so powerful. That's how I approach all my projects the big and small like this one and is why you see seemingly needless factorization – Parad0x13 Dec 30 '12 at 09:59
0

Your escapedvalue is too low it should be 4.00f.

Micromega
  • 12,486
  • 7
  • 35
  • 72
  • Even at 4.0f it still produces the oval. I've set the escape value to ridiculous values such as 9999.0f or 1.0f and got the same result. This is weird because an escape value of 3.0f-6.0f should produce reasonably good results – Parad0x13 Dec 25 '12 at 10:05
  • Oh, I didn't know that. I use 4.0f. Sorry, i can't help not good in c++. – Micromega Dec 25 '12 at 10:09