Welcome to Fractal Forums

Fractal Software => Programming => Topic started by: ker2x on July 13, 2010, 09:40:46 PM




Title: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: ker2x on July 13, 2010, 09:40:46 PM
Fortran handle complex numbers very nicely, i'm porting my code to OpenCL.

I have this fortran code :
IF ((ABS( 1.0 - SQRT(1-(4*c)) ))  < 1.0 ) THEN ...

"c" is a complex number.
It check if the point c is in the main cardioid of a mandelbrot.

i'm having trouble to convert to c (openCL to be exact) with no support for complex numbers.
can you help me to convert to c please ?

i already convert this, but it was much easier (check if c is in the biggest bulb http://en.wikipedia.org/wiki/Mandelbrot_set#The_main_cardioid_and_period_bulbs ) :
Code:
    //IF (ABS(c - CMPLX(-1,0) )) < 0.25) THEN RETURN TRUE
    if( sqrt( ((cr+1.0) * (cr+1.0)) + (ci * ci) ) < 0.25 )
    {
        return true;
    }

thank you


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: Schlega on July 14, 2010, 09:36:54 AM
I'm no programming expert, so there's probably a more elegant way to do it, but something like this should work:
Code:
double tempi = ci*(-4.0);
double tempr = 1.0 - cr*4.0;

double theta = atan2(tempi,tempr)/2.0;
double r = (tempr*tempr + tempi*tempi)^0.25;

tempr = 1.0 - r * cos(theta);
tempi = -r * sin(theta);

if( (tempr * tempr + tempi * tempi) < 1.0){
...
}


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: ker2x on July 14, 2010, 01:41:03 PM
Thank you ! it works perfectly.
I just had to replace double by float and "^" by "pow".

Code:
    float tempi = ci*(-4.0);
    float tempr = 1.0 - cr*4.0;
    float theta = atan2(tempi,tempr)/2.0;
    float r = pow((tempr*tempr + tempi*tempi),0.25);
    tempr = 1.0 - r * cos(theta);
    tempi = -r * sin(theta);
    if( (tempr * tempr + tempi * tempi) < 1.0)
    {
        return true;
    }


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: knighty on July 14, 2010, 02:25:06 PM
Hi,
A faster alternative would be:
Code:
     r2=(1.0-4.0*x)*(1.0-4.0*x)+(4.0*y)*(4.0*y);
     r=sqrt(r2);
     if (r2<2.0*(r+1.0-4.0*x)) return true;
this involves only one square root.
[EDIT]
Actually you can remove the square root. The condition becomes:
(0.5 * r2 - 1.0 + 4.0 * x)*(0.5 * r2 - 1.0 + 4.0 * x) < r2
[/EDIT]

In your OP, you can remove the square root for the main bulb :
Code:
//IF (ABS(c - CMPLX(-1,0) )) < 0.25) THEN RETURN TRUE
    if( (cr+1.0) * (cr+1.0) + ci * ci < 0.0625 )
    {
        return true;
    }


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: ker2x on July 16, 2010, 11:00:17 AM
woops, i forgot to try yesterday. (too busy with this OpenCL random number generator  :angry: )
I'll try this weekend. thx again :)


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: cbuchner1 on July 19, 2010, 03:39:01 PM
I use this code, which does not require any transcendental functions,
such as sqrt().

zr and zi are real and imaginary parts of z.

Code:
            // period-2 bulb test
            if ((((zr+1.0f)*(zr+1.0f)) + zi*zi) >= 0.0625f)
            {
                // cardioid test
                float q = (zr-0.25f)*(zr-0.25f) + zi*zi;
                if (q*(q+(zr-0.25f)) >= 0.25f*zi*zi)
                {
                }
            }


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: ker2x on July 19, 2010, 09:58:39 PM
Both formula patched on my github, thank you again !  ;D


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: cbuchner1 on July 20, 2010, 04:06:31 PM
Some extra checks to exclude the next biggest bulbs (approximately). Values were determined by trial and error.

Code:
                    // test for the smaller bulb left of the period-2 bulb
                    if ((((zr+1.309f)*(zr+1.309f)) + zi*zi) >= 0.00345f)
                        // check for the smaller bulbs on top and bottom of the cardioid
                        if ((((zr+0.125f)*(zr+0.125f)) + (zi-0.744f)*(zi-0.744f)) >= 0.0088f)
                            if ((((zr+0.125f)*(zr+0.125f)) + (zi+0.744f)*(zi+0.744f)) >= 0.0088f)


In the picture below you see the black excluded areas (all 5 exclusion areas combined from my postings in this thread), white are other spots that seem to belong to the M-set after a 256 iteration cutoff.

Now for faster buddhabrots, I'd like to have a random generator that prefers locations near the M-set. Something like a spatial weighting function for bins close to the set, and 0 weight for bins entirely within the set (black zones). The current uniform sampling simply creates too many orbits of short lengths like 1,2,3. That's a waste of GPU capabilities.


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: ker2x on July 20, 2010, 04:56:12 PM
Thank you for the additional exclusion area.

About the random generator, i'm glad enough to have a working RNG running on the GPU and i'll stick with it for now, until i resolved many other more important issues.
But, yes, i coded a separate kernel for the RNG and there is a lot of rooms for improvements. I'll definitively take a look at your idea.

Thank you. Patchs to come soon :)


Title: Re: Need help to convert (ABS( 1.0 - SQRT(1-(4*c)) ) to C
Post by: Rrrola on September 20, 2010, 05:31:16 PM
For some information about the bulbs, see this article by iq http://www.iquilezles.org/www/articles/arquimedes/arquimedes.pdf (http://www.iquilezles.org/www/articles/arquimedes/arquimedes.pdf) (in Spanish, but math is universal)