Skip to content

Instantly share code, notes, and snippets.

@neon-sunset
Last active September 6, 2024 21:08
Show Gist options
  • Save neon-sunset/72fd9db355b2a0717433fc768e03dc43 to your computer and use it in GitHub Desktop.
Save neon-sunset/72fd9db355b2a0717433fc768e03dc43 to your computer and use it in GitHub Desktop.
BenchmarksGame mandelbrot contribution
// The Computer Language Benchmarks Game
// https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
//
// direct transliteration of Greg Buchholz's C program
// contributed by Isaac Gouy, fix by David Turnbull
// dispatching to multiple cores, use SIMD operationn, early break
// depending on previous depth by Patrick Stein,
// direct transliteration of Swift #7 program by Arseniy Zlobintsev
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
const int iterations = 50;
const double depth = 4.0;
var width = int.Parse(args[0]);
var height = width;
var startPoint = (x: -1.5, i: -1.0);
var endPoint = (x: 0.5, i: 1.0);
var lineCount = height;
var lineSize = (width + 7) / 8;
var pixelHeight = Math.Abs(endPoint.x - startPoint.x) / height;
var pixelWidth = Math.Abs(endPoint.i - startPoint.i) / width;
var pixelWidth8 = pixelWidth * 8.0;
var outputSize = lineCount * lineSize;
var pixelBuffer = new byte[outputSize];
var Ci0 = startPoint.i;
var Cr0 = (Vector512.Create((double)0, 1, 2, 3, 4, 5, 6, 7)
* pixelWidth)
+ Vector512.Create(startPoint.x);
var Cr0Array = new Vector512<double>[lineSize];
Parallel.For(0, lineSize, x => {
Cr0Array[x] = Cr0 + Vector512.Create(x * pixelWidth8);
});
Parallel.For(0, lineCount, y => {
var slice = pixelBuffer.AsSpan(y * lineSize, lineSize);
var Ci = Ci0 + (y * pixelHeight);
var pixel = (byte)0;
for (var x = 0; x < slice.Length; x++) {
Mandelbrot(Cr0Array[x], Ci, ref pixel);
slice[x] = pixel;
}
});
Console.WriteLine($"P4\n{width} {height}");
Console.OpenStandardOutput().Write(pixelBuffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Mandelbrot(Vector512<double> Cr, double Ci, ref byte pixel) {
var Zr = Vector512<double>.Zero;
var Zi = Vector512<double>.Zero;
var Tr = Vector512<double>.Zero;
var Ti = Vector512<double>.Zero;
var CiV = Vector512.Create(Ci);
var thresholds = Vector512.Create(depth);
var ramp = Vector512.Create(128, 64, 32, 16, 8, 4, 2, 1);
if (pixel is 0) {
for (var i = 0; i < iterations / 5; i++) {
for (var j = 0; j < 5; j++) {
Zi = 2.0 * Zr * Zi + CiV;
Zr = Tr - Ti + Cr;
Tr = Zr * Zr;
Ti = Zi * Zi;
}
var result = Vector512.LessThanAny(Tr + Ti, thresholds);
if (result is false) return;
}
}
else {
for (var i = 0; i < iterations; i++) {
Zi = 2.0 * Zr * Zi + CiV;
Zr = Tr - Ti + Cr;
Tr = Zr * Zr;
Ti = Zi * Zi;
}
}
var cmpresult = Vector512.LessThan(Tr + Ti, thresholds);
var summask = ramp & cmpresult.AsInt64();
pixel = (byte)Vector512.Sum(summask);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment