示例#1
0
        public override bool RenderMultiThreaded(Float128 xmin, Float128 xmax, Float128 ymin, Float128 ymax, Float128 step, int maxIterations)
        {
            Float128 HALF = new Float128(0.5);

            //Parallel.For(0, (int)(((ymax - ymin) / step) + .5M), (yp) =>
            Parallel.For(0, ymax.SubFast(ymin).Div(step).AddFast(HALF).IntValue(), (yp) =>
            {
                if (Abort)
                {
                    return;
                }
                Float128 y = ymin.AddFast(step.Mul(yp));
                int xp     = 0;
                for (Float128 x = xmin; x.SubFast(xmax).Hi < 0; x = x.AddFast(step), xp++)
                {
                    Float128 accumx = x;
                    Float128 accumy = y;
                    int iters       = 0;
                    Float128 sqabs  = new Float128(0);
                    do
                    {
                        Float128 naccumx = accumx.Sqr().SubFast(accumy.Sqr());
                        Float128 naccumy = accumx.Mul(accumy).MulPwrOf2(2);
                        accumx           = naccumx.AddFast(x);
                        accumy           = naccumy.AddFast(y);
                        iters++;
                        sqabs = accumx.Sqr().AddFast(accumy.Sqr());
                    } while (sqabs.SubFast(limit).Hi < 0 && iters < maxIterations);

                    DrawPixel(xp, yp, iters);
                }
            });
            return(!Abort);
        }
示例#2
0
        public override bool RenderSingleThreaded(Float128 xmin, Float128 xmax, Float128 ymin, Float128 ymax, Float128 step, int maxIterations)
        {
            int yp = 0;

            for (Float128 y = ymin; y.SubFast(ymax).Hi < 0 && !Abort; y = y.AddFast(step), yp++)
            {
                if (Abort)
                {
                    return(false);
                }
                int xp = 0;
                for (Float128 x = xmin; x.SubFast(xmax).Hi < 0; x = x.AddFast(step), xp++)
                {
                    Float128 accumx = x;
                    Float128 accumy = y;
                    int      iters  = 0;
                    Float128 sqabs  = new Float128(0);
                    do
                    {
                        Float128 naccumx = accumx.Sqr().SubFast(accumy.Sqr());
                        Float128 naccumy = accumx.Mul(accumx).MulPwrOf2(2);
                        accumx = naccumx.AddFast(x);
                        accumy = naccumy.AddFast(y);
                        iters++;
                        sqabs = accumx.Sqr().AddFast(accumy.Sqr());
                    } while (sqabs.SubFast(limit).Hi < 0 && iters < maxIterations);

                    DrawPixel(xp, yp, iters);
                }
            }
            return(true);
        }
 // Helper to construct a vector from a lambda that takes an index. It's not efficient, but I
 // think it's prettier and more succint than the corresponding for loop.
 // Don't use it on a hot code path (i.e. inside a loop)
 public static Float128FastVector Create(Func <int, Float128> creator)
 {
     double[] dataHi = new double[Vector <double> .Count];
     double[] dataLo = new double[Vector <double> .Count];
     for (int i = 0; i < Vector <double> .Count; i++)
     {
         Float128 float128 = creator(i);
         dataHi[i] = float128.Hi;
         dataLo[i] = float128.Lo;
     }
     return(new Float128FastVector(dataHi, dataLo));
 }
        // Render the fractal on a single thread using raw Vector<double> data types
        // For a well commented version, go see VectorFloatRenderer.RenderSingleThreadedWithADT in VectorFloat.cs
        public override bool RenderSingleThreaded(Float128 xmin, Float128 xmax, Float128 ymin, Float128 ymax, Float128 step, int maxIterations)
        {
            Vector <double>    vmax_iters = new Vector <double>((double)maxIterations);
            Float128FastVector vlimit     = new Float128FastVector(limit);
            Float128FastVector vstep      = new Float128FastVector(step);
            Float128FastVector vinc       = new Float128FastVector(new Float128((double)Vector <double> .Count) * step);
            Float128FastVector vxmax      = new Float128FastVector(xmax);
            Float128FastVector vxmin      = Create(i => xmin + step * new Float128((double)i));

            Float128 y  = ymin;
            int      yp = 0;

            for (Float128FastVector vy = new Float128FastVector(ymin); (y - ymax).Hi < 0 && !Abort; vy += vstep, y += step, yp++)
            {
                if (Abort)
                {
                    return(false);
                }
                int xp = 0;
                for (Float128FastVector vx = vxmin; Float128FastVector.LessThanOrEqualAll(vx, vxmax); vx += vinc, xp += Vector <double> .Count)
                {
                    Float128FastVector accumx = vx;
                    Float128FastVector accumy = vy;

                    Vector <double> viters    = Vector <double> .Zero;
                    Vector <double> increment = Vector <double> .One;
                    do
                    {
                        Float128FastVector naccumx = accumx.Sqr() - accumy.Sqr();
                        Float128FastVector naccumy = (accumx * accumy).MulPwrOf2(2);
                        accumx  = naccumx + vx;
                        accumy  = naccumy + vy;
                        viters += increment;
                        Float128FastVector sqabs = accumx.Sqr() + accumy.Sqr();
                        Vector <double>    vCond = Vector.LessThanOrEqual <double>(sqabs.Hi, vlimit.Hi) &
                                                   Vector.LessThanOrEqual <double>(viters, vmax_iters);
                        increment = increment & vCond;
                    } while (increment != Vector <double> .Zero);

                    viters.ForEach((iter, elemNum) => DrawPixel(xp + elemNum, yp, (int)iter));
                }
            }
            return(true);
        }
        // Render the fractal on multiple threads using raw Vector<double> data types
        // For a well commented version, go see VectorFloatRenderer.RenderSingleThreadedWithADT in VectorFloat.cs
        public override bool RenderMultiThreaded(Float128 xmin, Float128 xmax, Float128 ymin, Float128 ymax, Float128 step, int maxIterations)
        {
            Vector <double>    vmax_iters = new Vector <double>((double)maxIterations);
            Float128FastVector vlimit     = new Float128FastVector(limit);
            Float128FastVector vstep      = new Float128FastVector(step);
            Float128FastVector vinc       = new Float128FastVector(new Float128((double)Vector <double> .Count) * step);
            Float128FastVector vxmax      = new Float128FastVector(xmax);
            Float128FastVector vxmin      = Create(i => xmin + step * new Float128((double)i));

            Parallel.For(0, (((ymax - ymin) / step) + HALF).IntValue(), (yp) =>
            {
                if (Abort)
                {
                    return;
                }

                Float128FastVector vy = new Float128FastVector(ymin + step * new Float128((double)yp));
                int xp = 0;
                for (Float128FastVector vx = vxmin; Float128FastVector.LessThanOrEqualAll(vx, vxmax); vx += vinc, xp += Vector <double> .Count)
                {
                    Float128FastVector accumx = vx;
                    Float128FastVector accumy = vy;

                    Vector <double> viters    = Vector <double> .Zero;
                    Vector <double> increment = Vector <double> .One;
                    do
                    {
                        Float128FastVector naccumx = accumx.Sqr() - accumy.Sqr();
                        Float128FastVector naccumy = (accumx * accumy).MulPwrOf2(2);
                        accumx  = naccumx + vx;
                        accumy  = naccumy + vy;
                        viters += increment;
                        Float128FastVector sqabs = accumx.Sqr() + accumy.Sqr();
                        Vector <double> vCond    = Vector.LessThanOrEqual <double>(sqabs.Hi, vlimit.Hi) &
                                                   Vector.LessThanOrEqual <double>(viters, vmax_iters);
                        increment = increment & vCond;
                    } while (increment != Vector <double> .Zero);

                    viters.ForEach((iter, elemNum) => DrawPixel(xp + elemNum, yp, (int)iter));
                }
            });
            return(!Abort);
        }
        public void Zoom(int zDelta, Point location)
        {
            (Float128 X, Float128 Y)oldDistance = (new Float128(location.X - _bufferWidth / 2.0) * _zoomLevel, new Float128(location.Y - _bufferHeight / 2.0) * _zoomLevel);
            Float128 factor = new Float128(1.2);
            Float128 offset = new Float128(0);

            if (zDelta > 0)
            {
                _zoomLevel /= factor;
                offset      = (new Float128(1.0) - new Float128(1.0) / factor);
            }
            else
            {
                _zoomLevel *= factor;
                offset      = new Float128(1.0) - factor;
            }

            // Correct for the position of the mouse
            _viewR += oldDistance.X * offset;
            _viewI += oldDistance.Y * offset;

            OnParametersChanged();
        }
 public Float128FastVector(Float128 initial)
 {
     Hi = new Vector <double>(initial.Hi);
     Lo = new Vector <double>(initial.Lo);
 }
 public abstract bool RenderSingleThreaded(Float128 xmin, Float128 xmax, Float128 ymin, Float128 ymax, Float128 step, int maxIterations);
示例#9
0
        private static int to_digits(this Float128 dd, char[] s, int precision, int intBase)
        {
            int halfBase = (intBase + 1) >> 1;

            if (dd.Hi == 0.0)
            {
                // Assume dd.lo == 0.
                for (int i = 0; i < s.Length; ++i)
                {
                    s[i] = '0';
                }
                return(0);
            }

            // First determine the (approximate) exponent.
            Float128 temp = dd.Abs();
            int      exp  = (int)Math.Floor(Math.Log(temp.Hi) / Math.Log(intBase));

            Float128 p = new Float128(intBase);

            if (exp < -300)
            {
                temp.MulSelf(p.Pow(150));
                p.PowSelf(-exp - 150);
                temp.MulSelf(p);
            }
            else
            {
                p.PowSelf(-exp);
                temp.MulSelf(p);
            }

            // Fix roundoff errors. (eg. floor(log10(1e9))=floor(8.9999~)=8)
            if (temp.Hi >= intBase)
            {
                exp++;
                temp.Hi /= intBase;
                temp.Lo /= intBase;
            }
            else if (temp.Hi < 1)
            {
                exp--;
                temp.Hi *= intBase;
                temp.Lo *= intBase;
            }

            if (temp.Hi >= intBase || temp.Hi < 1)
            {
                throw new Exception("Can't compute exponent.");
            }

            // Handle one digit more. Used afterwards for rounding.
            int numDigits = precision + 1;

            // Extract the digits.
            for (int i = 0; i < numDigits; i++)
            {
                int val = (int)temp.Hi;
                temp = temp.Sub(val);
                temp = temp.Mul(intBase);

                s[i] = (char)val;
            }

            if (s[0] <= 0)
            {
                throw new Exception("Negative leading digit.");
            }

            // Fix negative digits due to roundoff error in exponent.
            for (int i = numDigits - 1; i > 0; i--)
            {
                if (s[i] >= 32768)
                {
                    s[i - 1]--;
                    s[i] += (char)intBase;
                }
            }

            // Round, handle carry.
            if (s[precision] >= halfBase)
            {
                s[precision - 1]++;

                int i = precision - 1;
                while (i > 0 && s[i] >= intBase)
                {
                    s[i] -= (char)intBase;
                    s[--i]++;
                }
            }
            s[precision] = (char)0;

            // If first digit became too high, shift right.
            if (s[0] >= intBase)
            {
                exp++;
                for (int i = precision; i >= 1;)
                {
                    s[i] = s[--i];
                }
            }

            // Convert to ASCII.
            for (int i = 0; i < precision; i++)
            {
                s[i] = Float128.BASE_36_TABLE[s[i]];
            }

            // If first digit became zero, and exp > 0, shift left.
            if (s[0] == '0' && exp < 32768)
            {
                exp--;
                for (int i = 0; i < precision;)
                {
                    s[i] = s[++i];
                }
            }

            return(exp);
        }
示例#10
0
        /**
         * Format a string in an easily readable format. The number is represented
         * as scientific form on the following conditions: <br>
         * <ol>
         * <li>(for big numbers) When the first digit right of the decimal point
         * would not be within the first minPrecision positions of the string, <br>
         * <li>(for small numbers) When the most significant digit would not be
         * within the first minPrecision positions of the string
         * </ol>
         * <br>
         * Where: <code>minPrecision = floor(105 / log2(intBase) + 1)</code>
         */
        public static string ToString(this Float128 dd, int intBase)
        {
            double digitsPerBit = Math.Log(2) / Math.Log(intBase);
            int    minPrecision = (int)Math.Floor(105.0 * digitsPerBit + 2);

            // Get the precision. (The minimum number of significant digits required
            // for an accurate representation of this number)
            int expHi     = (int)((BitConverter.DoubleToInt64Bits(dd.Hi) & 0x7FF0000000000000L) >> 52);
            int expLo     = dd.Lo == 0 ? expHi - 53 : (int)((BitConverter.DoubleToInt64Bits(dd.Lo) & 0x7FF0000000000000L) >> 52);
            int precision = (int)Math.Ceiling((expHi - expLo + 53) * digitsPerBit);

            precision = Math.Max(minPrecision, precision);

            // Get the raw digit representation.
            char[] chars = new char[precision + 1];
            int    exp   = dd.to_digits(chars, precision, intBase) + 1;

            // Get some properties.
            int left  = Math.Max(0, -exp);
            int right = Math.Max(0, exp);

            if (chars[precision - 1] == 0)
            {
                precision--;
            }
            bool sci = -exp >= minPrecision || exp >= minPrecision;

            // Allocate exactly the right size string.
            StringBuilder outString = new StringBuilder(precision + (sci ? 3 : left) + (exp > 0 ? 1 : 2));

            // Build the string.
            if (dd.Hi < 0)
            {
                outString.Append('-');
            }
            if (sci)
            {
                outString.Append(chars, 0, 1);
                outString.Append('.');
                outString.Append(chars, 1, precision - 1);
                outString.Append('e');
                outString.Append(exp - 1);
            }
            else
            {
                if (exp <= 0)
                {
                    outString.Append('0');
                }
                if (right > 0)
                {
                    outString.Append(chars, 0, right);
                }
                outString.Append('.');
                if (left > 0)
                {
                    if (Float128.ZEROES.Length < left)
                    {
                        //System.err.println(left);
                    }
                    else
                    {
                        outString.Append(Float128.ZEROES, 0, left);
                    }
                }
                outString.Append(chars, right, precision - right);
            }
            return(outString.ToString());
        }
示例#11
0
 public void Move(Vector distance)
 {
     _viewR += new Float128(distance.X) * _zoomLevel;
     _viewI += new Float128(distance.Y) * _zoomLevel;
     OnParametersChanged();
 }
示例#12
0
        public unsafe void DoRender()
        {
            if (Closing)
            {
                return;
            }
            int width  = _bufferWidth;
            int height = _bufferHeight;

            // Try and get a spare buffer
            if (!_spareBuffers.TryPop(out int[,] buffer))
            {
                buffer = new int[height, width];
            }
            else if (buffer.GetLength(0) != height || buffer.GetLength(1) != width)
            {
                buffer = new int[height, width];
                _spareBuffers.Clear();
            }

            int maxiter = (int)(-512 * Math.Log10(_zoomLevel.Hi));
            Func <int, (byte R, byte G, byte B)> itersToColor = FractalRendererBase.GetColorProviderV2(maxiter + 1);
            Action <int, int, int> addPixel = (x, y, iters) =>
            {
                if (y >= height || x >= width)
                {
                    return;
                }

                var color = itersToColor(iters);
                buffer[y, x] = (color.R << 16) | (color.G << 8) | color.B;
            };

            int      halfHeight = (int)(Math.Floor(height / 2.0));
            int      halfWidth  = (int)(Math.Floor(width / 2.0));
            Float128 xMin       = new Float128(-halfWidth) * _zoomLevel + _viewR;
            Float128 xMax       = new Float128(halfWidth) * _zoomLevel + _viewR;
            Float128 yMin       = new Float128(-halfHeight) * _zoomLevel + _viewI;
            Float128 yMax       = new Float128(halfHeight) * _zoomLevel + _viewI;
            Float128 step       = _zoomLevel;

            Func <bool> DoRender    = null;
            Action      AbortRender = null;

            if (Options.LanguageCs)
            {
                var cs = Options.Cs;
                if (!cs.PrecisionFloat128)
                {
                    (var render, var abort) = FractalRenderer64.SelectRender(addPixel, () => false, cs.MethodCpuSimd, cs.PrecisionFloat64, cs.ThreadModelMulti);
                    DoRender    = () => render(xMin.Hi, xMax.Hi, yMin.Hi, yMax.Hi, step.Hi, maxiter);
                    AbortRender = () => abort();
                }
                else
                {
                    (var render, var abort) = FractalRenderer128.SelectRender128(addPixel, () => false, cs.MethodCpuSimd, cs.ThreadModelMulti);
                    DoRender    = () => render(xMin, xMax, yMin, yMax, step, maxiter);
                    AbortRender = () => abort();
                }
            }
            else if (Options.LanguageCpp)
            {
                var cpp = Options.Cpp;
                DoRender = () =>
                {
                    fixed(int *fixedBuffer = buffer)
                    {
                        RenderMandelbrotCpp(cpp.MethodGpu, cpp.PrecisionFloat64, cpp.ThreadModelMulti, _zoomLevel.Hi, _viewR.Hi, _viewI.Hi, fixedBuffer, width, height);
                    }

                    return(true);
                };
            }


            _throttledAction.InvokeAction(() =>
            {
                _stopwatch.Reset();
                _stopwatch.Start();
                bool success = DoRender();
                _stopwatch.Stop();

                if (!success)
                {
                    return;
                }

                double fullSetPixels = 4 / _zoomLevel.Hi;
                double meters        = _funDistances.PixelsToMeters(fullSetPixels);

                Title = $"Mandelbrot Rendering Took {_stopwatch.ElapsedMilliseconds}ms ({width}x{height})  Whole Set Size = {Math.Round(meters)} meters (> {_funDistances.PixelsToFunDistance(fullSetPixels)})  Iterations = {maxiter}  Zoom Level = {Math.Round(0.002 / _zoomLevel.Hi, 1)}";

                var temp  = (MandelbrotImage as ArrayBitmapSource)?.Buffer;
                var image = new ArrayBitmapSource(buffer);
                image.Freeze();
                MandelbrotImage = image;
                if (temp != null && temp.GetLength(0) == height && temp.GetLength(1) == width)
                {
                    _spareBuffers.Push(temp);
                }

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(MandelbrotImage)));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
            });
        }