I am trying to make a mandelbrot fractal renderer for my fx-CG50, it calculates away, but when it needs to actually display something, the screen is just white. I want to debug my program to find out what is wrong. Can anyone help?
Can you post your source code to the topic so we can debug it?

I won't be able to help but other fellow forum members can.
This is the source code.

Code:
#include <fxcg/display.h>
#include <fxcg/keyboard.h>

#define screen_ratio ( 389 / 216 )
#define default_camera_width 3.6018518518518518518518518518519
#define default_camera_height 2
#define default_zoom 1
#define default_iterations = 100

double square_root(double n){
  double lo = 0, hi = n, mid;
  for(int i = 0 ; i < 1000 ; i++){
      mid = (lo+hi)/2;
      if(mid*mid == n) return mid;
      if(mid*mid > n) hi = mid;
      else lo = mid;
  }
  return mid;
}

int main()
{
    Bdisp_EnableColor(1);

    double zoom = 1;
    double camera_position_x = 0;
    double camera_position_y = 0;
    int iterations = 100;

    // int color_frequency_r = 181;
    // int color_frequency_g = 139;
    // int color_frequency_b = 167;

    int screen[389][216];

    int progress = 0;

    ProgressBar(progress, 389 * 216);

    for(int i = 0; i < 389; i++) // calculate the image
    {
        for(int j = 0; j < 216; j++)
        {
            double c_x = i - (default_camera_height / (2 * zoom)) + camera_position_x;
            double c_y = j - (default_camera_width / (2 * zoom)) + camera_position_y;

            double z_x = 0.0;
            double z_y = 0.0;

            bool escaped = false;

            int iter;

            for(iter = 0; iter < iterations; iter++)
            {
                z_x = z_x * z_x - z_y * z_y + c_x;
                z_y = 2 * z_x * z_y + c_y;

                if(square_root(z_x * z_x + z_y * z_y) > 2)
                {
                    escaped = true;
                    break;
                }
            }
            if(escaped)
            {
                // int r = (sin(iter * color_frequency_r) + 1) * 32768;
                // int g = (sin(iter * color_frequency_g) + 1) * 1024;
                // int b = (sin(iter * color_frequency_b) + 1) * 16;

                // screen[i][j] = r + b + g;

                screen[i][j] = COLOR_WHITE;
            } else {
                screen[i][j] = COLOR_BLACK;
            }

            progress++;
            ProgressBar(progress, 389 * 216);

        }
    }

    MsgBoxPop();
    EnableStatusArea(3);

    for(int i = 0; i < 200; i++) // draw the image
    {
        for(int j = 0; j < 200; j++)
        {
            Bdisp_SetPoint_VRAM(i, j, screen[i][j]);
        }
    }

    Bdisp_PutDisp_DD();

    int key;
    while(1)
    {
        GetKey(&key);
    }
    return 0;
}

Code:
#define screen_ratio ( 389 / 216 )

This is equal to 1, you need at least one operand to be a floating-point if you want floating-point division to be used. Also the screen size is 384x216 when programming with the PrizmSDK, I'm not sure where this 389 comes from but if you use direct VRAM access overflows will haunt your dreams.

Code:
#define default_iterations = 100

This probably shouldn't have an equal sign in it.

Code:
double square_root(double n){
  double lo = 0, hi = n, mid;
  for(int i = 0 ; i < 1000 ; i++){
      mid = (lo+hi)/2;
      if(mid*mid == n) return mid;
      if(mid*mid > n) hi = mid;
      else lo = mid;
  }
  return mid;
}

For inputs 0 < n < 1 the square root of n is not in the [0:n] interval, it is larger than n, so this function probably doesn't work, and it will use up all 1000 iterations before finding an incorrect result (equal to n).

Code:
int screen[389][216];

I think I should mention that you have 512 kiB of memory for your data segment + stack, and you're using 336 kB with this pretty gigantic array.

In the end you're only storing 16-bit values, which make this array a VRAM; why not just access the VRAM in the loop?

Alright, so you're computing 389x216 pixel values, all of which can use up to 100 iterations. Let's assume you finish on average in 25. Each iteration requires some floating-point division plus a square root with up to 1000 iterations; for inputs between 0 and 1 all 1000 are used, which is going to be pretty often since you start with coordinates close to the [-1...1] range. The stupid estimate of 389 × 216 × 25 × 1000 suggests you might be running "if(mid*mid == n)" at least 2 billion times.

My personal hypothesis: your program never finishes. ^^

I'd advise to (1) never compute the square root, instead do z_x² + z_y² > 4, (2) reduce the number of iterations and the amount of pixels computed, then (3) check if you get something after a couple of minutes.

The order of magnitude for floating-point operations is 2-3 µs for an addition, 3-4 µs for a multiplication, something in that range (at default overclock levels). You realistically won't get an "instant" result with code like this. The best I could personally program was using 32-bit fixed point with some optimized assembly and it generated the usual view of the full fractal in 300 ms. This time could vary greatly if we looked in dense surfaces, and it's still not even good because 32-bit fixed point fails pretty quickly when you zoom in; 64-bit would be better, but slower. Depending on what you aim to make maybe this can inform your future choices a little bit better. Smile
Thanks for helping me! How do I use 64-Bit fixed point math?
You're welcome. You have to program it yourself, even through fortunately it's not very difficulty.

The basic idea is to say you have a real number x and you represent it in memory with the integer round(x*2³²). This way the top 32 bits are the integer part, the bottom 32 bits are the fractional part.

You create fixed-point numbers by just multiplying by 2³² = 4294967296 :

Code:
#include <stdint.h>
typedef int64_t fixed_t;
#define fix(x) ((x)* 4294967296)
fixed_t x = fix(1);
fixed_t y = fix(1.5);
fixed_t z = fix(1.8)

Don't try to be smart with bit shifts here as it won't work for double values and negative values. Turn on optimizations with -O2 and the compiler will precompute everything for you.

Then addition and subtraction are easy. Think of it like this: you have x·2³² and y·2³², and you want (x+y)·2³²; just add or subtract.

Code:
fixed_t z = x + y;

Multiplication is slightly more involved; indeed if you have x·2³² and y·2³² and you want (x*y)·2³², you need to multiply x and y but also divide by 2³². Because the CPU doesn't have a 64×64→128 bit multiplication we can do one step of naive/Karatsuba multiplication like this:

Code:
fixed_t fmul(fixed_t x, fixed_t y)
{
    int32_t x_top = (x >> 32), y_top = (y >> 32);
    uint32_t x_bot = (x & 0xffffffff), y_top = (y & 0xffffffff);

    uint64_t d = (uint64_t)x_bot * y_bot;
    return x_top * y_bot + y_top * x_bot + (d >> 32);
}
fixed_t z = fmul(x, y);

I don't guarantee it will work verbatim as it's late here and I'm pretty tired, but that's the idea.

You don't need division for the fractal, fortunately.

Then conversion to int or double is as easy as letting the compiler do it:

Code:
#define fix_to_int(x) ((x) / 4294967296)
#define fix_to_double(x) ((double)(x) / 4294967296)

These are the main steps. Note that I have optimized some overflows out of the multiplication, but the fastest way to do it would still be in assembler. C doesn't have a concept of heterogeneous-size multiplications (ie. 32×32→64 bit multiplication of x_bot and y_bot) so it can be made faster.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement