michael@0: // |jit-test| slow; michael@0: michael@0: // XXXbz I would dearly like to wrap it up into a function to avoid polluting michael@0: // the global scope, but the function ends up heavyweight, and then we lose on michael@0: // the jit. michael@0: load(libdir + "mandelbrot-results.js"); michael@0: //function testMandelbrotAll() { michael@0: // Configuration options that affect which codepaths we follow. michael@0: var doImageData = true; michael@0: var avoidSparseArray = true; michael@0: michael@0: // Control of iteration numbers and sizing. We'll do michael@0: // scaler * colorNames.length iterations or so before deciding that we michael@0: // don't escape. michael@0: const scaler = 5; michael@0: const numRows = 600; michael@0: const numCols = 600; michael@0: michael@0: const colorNames = [ michael@0: "black", michael@0: "green", michael@0: "blue", michael@0: "red", michael@0: "purple", michael@0: "orange", michael@0: "cyan", michael@0: "yellow", michael@0: "magenta", michael@0: "brown", michael@0: "pink", michael@0: "chartreuse", michael@0: "darkorange", michael@0: "crimson", michael@0: "gray", michael@0: "deeppink", michael@0: "firebrick", michael@0: "lavender", michael@0: "lawngreen", michael@0: "lightsalmon", michael@0: "lime", michael@0: "goldenrod" michael@0: ]; michael@0: const threshold = (colorNames.length - 1) * scaler; michael@0: michael@0: // Now set up our colors michael@0: var colors = []; michael@0: // 3-part for loop (iterators buggy, we will add a separate test for them) michael@0: for (var colorNameIdx = 0; colorNameIdx < colorNames.length; ++colorNameIdx) { michael@0: //for (var colorNameIdx in colorNames) { michael@0: colorNameIdx = parseInt(colorNameIdx); michael@0: colors.push([colorNameIdx, colorNameIdx, colorNameIdx, 0]); michael@0: } michael@0: michael@0: // Storage for our point data michael@0: var points; michael@0: michael@0: var scratch = {}; michael@0: var scratchZ = {}; michael@0: function complexMult(a, b) { michael@0: var newr = a.r * b.r - a.i * b.i; michael@0: var newi = a.r * b.i + a.i * b.r; michael@0: scratch.r = newr; michael@0: scratch.i = newi; michael@0: return scratch; michael@0: } michael@0: function complexAdd(a, b) { michael@0: scratch.r = a.r + b.r; michael@0: scratch.i = a.i + b.i; michael@0: return scratch; michael@0: } michael@0: function abs(a) { michael@0: return Math.sqrt(a.r * a.r + a.i * a.i); michael@0: } michael@0: michael@0: function escapeAbsDiff(normZ, absC) { michael@0: var absZ = Math.sqrt(normZ); michael@0: return normZ > absZ + absC; michael@0: } michael@0: michael@0: function escapeNorm2(normZ) { michael@0: return normZ > 4; michael@0: } michael@0: michael@0: function fuzzyColors(i) { michael@0: return Math.floor(i / scaler) + 1; michael@0: } michael@0: michael@0: function moddedColors(i) { michael@0: return (i % (colorNames.length - 1)) + 1; michael@0: } michael@0: michael@0: function computeEscapeSpeedObjects(real, imag) { michael@0: var c = { r: real, i: imag } michael@0: scratchZ.r = scratchZ.i = 0; michael@0: var absC = abs(c); michael@0: for (var i = 0; i < threshold; ++i) { michael@0: scratchZ = complexAdd(c, complexMult(scratchZ, scratchZ)); michael@0: if (escape(scratchZ.r * scratchZ.r + scratchZ.i * scratchZ.i, michael@0: absC)) { michael@0: return colorMap(i); michael@0: } michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: function computeEscapeSpeedOneObject(real, imag) { michael@0: // fold in the fact that we start with 0 michael@0: var r = real; michael@0: var i = imag; michael@0: var absC = abs({r: real, i: imag}); michael@0: for (var j = 0; j < threshold; ++j) { michael@0: var r2 = r * r; michael@0: var i2 = i * i; michael@0: if (escape(r2 + i2, absC)) { michael@0: return colorMap(j); michael@0: } michael@0: i = 2 * r * i + imag; michael@0: r = r2 - i2 + real; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: function computeEscapeSpeedDoubles(real, imag) { michael@0: // fold in the fact that we start with 0 michael@0: var r = real; michael@0: var i = imag; michael@0: var absC = Math.sqrt(real * real + imag * imag); michael@0: for (var j = 0; j < threshold; ++j) { michael@0: var r2 = r * r; michael@0: var i2 = i * i; michael@0: if (escape(r2 + i2, absC)) { michael@0: return colorMap(j); michael@0: } michael@0: i = 2 * r * i + imag; michael@0: r = r2 - i2 + real; michael@0: } michael@0: return 0; michael@0: } michael@0: michael@0: var computeEscapeSpeed = computeEscapeSpeedDoubles; michael@0: var escape = escapeNorm2; michael@0: var colorMap = fuzzyColors; michael@0: michael@0: function addPointOrig(pointArray, n, i, j) { michael@0: if (!points[n]) { michael@0: points[n] = []; michael@0: points[n].push([i, j, 1, 1]); michael@0: } else { michael@0: var point = points[n][points[n].length-1]; michael@0: if (point[0] == i && point[1] == j - point[3]) { michael@0: ++point[3]; michael@0: } else { michael@0: points[n].push([i, j, 1, 1]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: function addPointImagedata(pointArray, n, col, row) { michael@0: var slotIdx = ((row * numCols) + col) * 4; michael@0: pointArray[slotIdx] = colors[n][0]; michael@0: pointArray[slotIdx+1] = colors[n][1]; michael@0: pointArray[slotIdx+2] = colors[n][2]; michael@0: pointArray[slotIdx+3] = colors[n][3]; michael@0: } michael@0: michael@0: function createMandelSet() { michael@0: var realRange = { min: -2.1, max: 1 }; michael@0: var imagRange = { min: -1.5, max: 1.5 }; michael@0: michael@0: var addPoint; michael@0: if (doImageData) { michael@0: addPoint = addPointImagedata; michael@0: points = new Array(4*numCols*numRows); michael@0: if (avoidSparseArray) { michael@0: for (var idx = 0; idx < 4*numCols*numRows; ++idx) { michael@0: points[idx] = 0; michael@0: } michael@0: } michael@0: } else { michael@0: addPoint = addPointOrig; michael@0: points = []; michael@0: } michael@0: var realStep = (realRange.max - realRange.min)/numCols; michael@0: var imagStep = (imagRange.min - imagRange.max)/numRows; michael@0: for (var i = 0, curReal = realRange.min; michael@0: i < numCols; michael@0: ++i, curReal += realStep) { michael@0: for (var j = 0, curImag = imagRange.max; michael@0: j < numRows; michael@0: ++j, curImag += imagStep) { michael@0: var n = computeEscapeSpeed(curReal, curImag); michael@0: addPoint(points, n, i, j) michael@0: } michael@0: } michael@0: var result; michael@0: if (doImageData) { michael@0: if (colorMap == fuzzyColors) { michael@0: result = mandelbrotImageDataFuzzyResult; michael@0: } else { michael@0: result = mandelbrotImageDataModdedResult; michael@0: } michael@0: } else { michael@0: result = mandelbrotNoImageDataResult; michael@0: } michael@0: return points.toSource() == result; michael@0: } michael@0: michael@0: const escapeTests = [ escapeAbsDiff ]; michael@0: const colorMaps = [ fuzzyColors, moddedColors ]; michael@0: const escapeComputations = [ computeEscapeSpeedObjects, michael@0: computeEscapeSpeedOneObject, michael@0: computeEscapeSpeedDoubles ]; michael@0: // Test all possible escape-speed generation codepaths, using the michael@0: // imageData + sparse array avoidance storage. michael@0: doImageData = true; michael@0: avoidSparseArray = true; michael@0: for (var escapeIdx in escapeTests) { michael@0: escape = escapeTests[escapeIdx]; michael@0: for (var colorMapIdx in colorMaps) { michael@0: colorMap = colorMaps[colorMapIdx]; michael@0: for (var escapeComputationIdx in escapeComputations) { michael@0: computeEscapeSpeed = escapeComputations[escapeComputationIdx]; michael@0: assertEq(createMandelSet(), true); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Test all possible storage strategies. Note that we already tested michael@0: // doImageData == true with avoidSparseArray == true. michael@0: escape = escapeAbsDiff; michael@0: colorMap = fuzzyColors; // This part doesn't really matter too much here michael@0: computeEscapeSpeed = computeEscapeSpeedDoubles; michael@0: michael@0: doImageData = true; michael@0: avoidSparseArray = false; michael@0: assertEq(createMandelSet(), true); michael@0: michael@0: escape = escapeNorm2; michael@0: doImageData = false; // avoidSparseArray doesn't matter here michael@0: assertEq(createMandelSet(), true); michael@0: //} michael@0: //testMandelbrotAll();