From c5a62cfa1d2b3b95dfb8fdeb6afeeacbe2f7ecaf Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 7 Jan 2023 21:19:40 -0800 Subject: [PATCH 1/3] wip --- fixed.js | 13 +++++++----- sim.html | 22 +++++++++++++++++++ sim.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 sim.html create mode 100644 sim.js diff --git a/fixed.js b/fixed.js index 397de0f..b1d671d 100644 --- a/fixed.js +++ b/fixed.js @@ -17,11 +17,11 @@ let bytes = Math.ceil(bits / 8) * entries; let epsilonBits = 1 ; let epsilon = 2 ** epsilonBits; -function toFixed(float) { +export function toFixed(float) { return Math.round(float * base); } -function toFloat(fixed) { +export function toFloat(fixed) { return fixed / base; } @@ -48,12 +48,12 @@ for (let i = 0; i < entries * 2; i++) { // returns fixed point -function log2(fixed) { +export function log2(fixed) { return enloggen[toIndex(fixed)]; } // returns rounded integer -function pow2(fixed) { +export function pow2(fixed) { let n = toIndex(fixed); if (n > empower.length) { n = empower.length - 1; @@ -61,7 +61,7 @@ function pow2(fixed) { return empower[entries + n]; } -function mul(a, b) { +export function mul(a, b) { if (a == 0) return 0; if (b == 0) return 0; let la = log2(a)|0; @@ -93,6 +93,7 @@ for (let i = 0; i < powEntries; i++) { } */ +/* // now just try multipling numbers let deltas = 0; let deltaAvg = 0; @@ -153,3 +154,5 @@ for (let i = 0; i < enloggen.length; i++) { m = Math.max(m, enloggen[i]); } console.log(`max enloggen entry is ${m}`); + +*/ \ No newline at end of file diff --git a/sim.html b/sim.html new file mode 100644 index 0000000..61689cb --- /dev/null +++ b/sim.html @@ -0,0 +1,22 @@ + + + + Mandelbrot fixed-point test + + +

Mandelbrot fixed-point test

+ +

Float

+ + +

Fixed-point imul

+ + +

Fixed-point log

+ + + + + \ No newline at end of file diff --git a/sim.js b/sim.js new file mode 100644 index 0000000..4f819f0 --- /dev/null +++ b/sim.js @@ -0,0 +1,65 @@ +import {toFixed, toFloat, mul} from './fixed.js'; + +let max = 256; +let width = 256; +let height = 256; +let zoom = 1; + +let black = 0xff000000; +let tricolor = [ + 0xffff0000, + 0xff00ff00, + 0xff0000ff, +]; + +let palette = new Uint32Array(256); +palette[0] = black; +for (let i = 0; i < 255; i++) { + palette[i + 1] = tricolor[i % 3]; +} +function nap() { + return new Promise((resolve) => setTimeout(() => resolve())); +} + +async function setup(id, iterfunc) { + let canvas = document.getElementById(id); + let ctx = canvas.getContext('2d'); + let imageData = ctx.createImageData(width, height); + let rgba = new Uint32Array(imageData.data.buffer); + for (let y = 0; y < height; y++) { + let cy = (y * 2 - height) / (height / 2); + for (let x = 0; x < width; x++) { + let cx = (x * 2 - width) / (width / 2); + let i = iterfunc(cx, cy); + let color = palette[i]; + rgba[y * width + x] = color; + rgba[(256 - y) * width + x] = color; + + if (x % 16 == 15) { + ctx.putImageData(imageData, 0, 0); + await nap(); + } + } + } +} + +setup('float', (cx, cy) => { + let zx = 0; + let zy = 0; + let zx_2 = 0; + let zy_2 = 0; + let zx_zy = 0; + for (let i = 1; i < max; i++) { + zx = zx_2 - zy_2 + cx; + zy = zx_zy + zx_zy + cy; + zx_2 = zx * zx; + zy_2 = zy * zy; + zx_zy = zx * zy; + if (zx_2 >= 4 || zy_2 >= 4 || zx_2 + zy_2 >= 4) { + return i; + } + } + return 0; +}).then(() => { + console.log('done'); +}) \ No newline at end of file From a47836a39acd7710276d5abbcf8fbc2a7e8d8e3d Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 7 Jan 2023 22:02:26 -0800 Subject: [PATCH 2/3] mwahahah --- fixed.js | 3 +- sim.html | 30 ++++++--- sim.js | 182 +++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 180 insertions(+), 35 deletions(-) diff --git a/fixed.js b/fixed.js index b1d671d..ec39bee 100644 --- a/fixed.js +++ b/fixed.js @@ -8,7 +8,8 @@ let inputRange = 4; let shift = 4; let base = 2 ** (bits - shift); -let reduction = 4; +//let reduction = 4; +let reduction = 0; let roundOffset = (2 ** (reduction - 1)) + 1; let entries = 2 ** (bits - reduction); let bytes = Math.ceil(bits / 8) * entries; diff --git a/sim.html b/sim.html index 61689cb..a260a0d 100644 --- a/sim.html +++ b/sim.html @@ -8,14 +8,28 @@

Mandelbrot fixed-point test

-

Float

- - -

Fixed-point imul

- - -

Fixed-point log

- + + + + + + + + + + + + + + +
FloatFixed-point imulFixed-point log
+ + + + + + +
diff --git a/sim.js b/sim.js index 4f819f0..1050860 100644 --- a/sim.js +++ b/sim.js @@ -1,9 +1,50 @@ import {toFixed, toFloat, mul} from './fixed.js'; + +function imul(a, b) { + return Math.imul(a, b) >> 12; +} + +function logmul(a, b) { + if ((a | b) == 0) { + return 0; + } + let neg = 0; + if (a < 0) { + a = -a; + neg++; + } + if (b < 0) { + b = -b; + neg++; + } + let product = mul(a, b); + if (neg == 1) { + product = -product; + } + return product; +} + +let four = toFixed(4); + let max = 256; let width = 256; let height = 256; -let zoom = 1; + +let zoom = 0; +let offsetX = 0; +let offsetY = 0; + +function scale() { + return 1 / (2 ** zoom); +} + +let cancelled = false; + +async function cancel() { + cancelled = true; + return await nap(100); +} let black = 0xff000000; let tricolor = [ @@ -17,49 +58,138 @@ palette[0] = black; for (let i = 0; i < 255; i++) { palette[i + 1] = tricolor[i % 3]; } -function nap() { - return new Promise((resolve) => setTimeout(() => resolve())); +function nap(ms=0) { + return new Promise((resolve) => setTimeout(() => resolve(), ms)); } +function attach(id, func) { + document.getElementById(id).addEventListener('click', (_event) => { + cancel().then(() => { + func(); + run(); + }); + }); +} + +attach('zoom-in', () => { + zoom++; +}); + +attach('zoom-out', () => { + if (zoom >= 1) { + zoom--; + } +}); + +attach('left', () => { + offsetX -= scale(); +}); + +attach('right', () => { + offsetX += scale(); +}); + +attach('up', () => { + offsetY -= scale(); +}); + +attach('down', () => { + offsetY += scale(); +}); + async function setup(id, iterfunc) { let canvas = document.getElementById(id); let ctx = canvas.getContext('2d'); let imageData = ctx.createImageData(width, height); let rgba = new Uint32Array(imageData.data.buffer); + + cancelled = false; for (let y = 0; y < height; y++) { - let cy = (y * 2 - height) / (height / 2); + let cy = scale() * (y * 2 - height) / (height / 2) + offsetY; for (let x = 0; x < width; x++) { - let cx = (x * 2 - width) / (width / 2); + let cx = scale() * (x * 2 - width) / (width / 2) + offsetX; let i = iterfunc(cx, cy); let color = palette[i]; rgba[y * width + x] = color; - rgba[(256 - y) * width + x] = color; - if (x % 16 == 15) { + if (x % 256 == 255) { ctx.putImageData(imageData, 0, 0); await nap(); + if (cancelled) { + return; + } } } } } -setup('float', (cx, cy) => { - let zx = 0; - let zy = 0; - let zx_2 = 0; - let zy_2 = 0; - let zx_zy = 0; - for (let i = 1; i < max; i++) { - zx = zx_2 - zy_2 + cx; - zy = zx_zy + zx_zy + cy; - zx_2 = zx * zx; - zy_2 = zy * zy; - zx_zy = zx * zy; - if (zx_2 >= 4 || zy_2 >= 4 || zx_2 + zy_2 >= 4) { - return i; +function run() { + setup('float', (cx, cy) => { + let zx = 0; + let zy = 0; + let zx_2 = 0; + let zy_2 = 0; + let zx_zy = 0; + for (let i = 1; i < max; i++) { + zx = zx_2 - zy_2 + cx; + zy = zx_zy + zx_zy + cy; + zx_2 = zx * zx; + zy_2 = zy * zy; + zx_zy = zx * zy; + if (zx_2 + zy_2 >= 4) { + return i; + } } - } - return 0; -}).then(() => { - console.log('done'); -}) \ No newline at end of file + return 0; + }).then(() => { + console.log('float done'); + }); + + setup('imul', (cx, cy) => { + cx = toFixed(cx); + cy = toFixed(cy); + let zx = 0; + let zy = 0; + let zx_2 = 0; + let zy_2 = 0; + let zx_zy = 0; + for (let i = 1; i < max; i++) { + zx = zx_2 - zy_2 + cx; + zy = zx_zy + zx_zy + cy; + zx_2 = imul(zx, zx); + zy_2 = imul(zy, zy); + zx_zy = imul(zx, zy); + if (zx_2 + zy_2 >= four) { + return i; + } + } + return 0; + }).then(() => { + console.log('imul done'); + }); + + setup('log', (cx, cy) => { + cx = toFixed(cx); + cy = toFixed(cy); + let zx = 0; + let zy = 0; + let zx_2 = 0; + let zy_2 = 0; + let zx_zy = 0; + for (let i = 1; i < max; i++) { + zx = zx_2 - zy_2 + cx; + zy = zx_zy + zx_zy + cy; + zx_2 = logmul(zx, zx); + zy_2 = logmul(zy, zy); + zx_zy = logmul(zx, zy); + if (zx_2 + zy_2 >= four) { + return i; + } + } + return 0; + }).then(() => { + console.log('log done'); + }); +} + +run(); \ No newline at end of file From 8044dbfc21fa1f9cf334060b7919ab106c990f71 Mon Sep 17 00:00:00 2001 From: Brion Vibber Date: Sat, 7 Jan 2023 22:57:18 -0800 Subject: [PATCH 3/3] whee --- fixed.js | 20 +++++++++++--------- sim.js | 24 ++++++++++++++++-------- 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/fixed.js b/fixed.js index ec39bee..2946dd1 100644 --- a/fixed.js +++ b/fixed.js @@ -4,18 +4,19 @@ let bits = 16; // max Mandelbrot zx/zy addition range prior to checking distance let inputRange = 4; -// Room to hold power up to -12/+4 for 16-bit mandelbrot -let shift = 4; -let base = 2 ** (bits - shift); - -//let reduction = 4; let reduction = 0; let roundOffset = (2 ** (reduction - 1)) + 1; + +// Room to hold power up to -12/+4 for 16-bit mandelbrot +let shift = 5; +let base = 2 ** (bits - shift); + + let entries = 2 ** (bits - reduction); let bytes = Math.ceil(bits / 8) * entries; // try to keep all but the last few bits semi-accurate -let epsilonBits = 1 ; +let epsilonBits = 1; let epsilon = 2 ** epsilonBits; export function toFixed(float) { @@ -147,8 +148,6 @@ deltaCount = 0; console.log('done'); -console.log(`size of enloggen table: ${entries} entries, ${bytes} bytes`); -console.log(`size of empower table: ${entries * 2} entries, ${bytes * 2} bytes`); let m = 0; for (let i = 0; i < enloggen.length; i++) { @@ -156,4 +155,7 @@ for (let i = 0; i < enloggen.length; i++) { } console.log(`max enloggen entry is ${m}`); -*/ \ No newline at end of file +*/ + +console.log(`size of enloggen table: ${entries} entries, ${bytes} bytes`); +console.log(`size of empower table: ${entries * 2} entries, ${bytes * 2} bytes`); diff --git a/sim.js b/sim.js index 1050860..bc83348 100644 --- a/sim.js +++ b/sim.js @@ -1,5 +1,13 @@ -import {toFixed, toFloat, mul} from './fixed.js'; +import {toFixed, mul} from './fixed.js'; +let toFixedLog = toFixed; + +function toFixed16(val) { + // 4.12 + return Math.round(val * (2 ** 12)) +} + +let four16 = toFixed16(4); function imul(a, b) { return Math.imul(a, b) >> 12; @@ -25,7 +33,7 @@ function logmul(a, b) { return product; } -let four = toFixed(4); +let fourLog = toFixedLog(4); let max = 256; let width = 256; @@ -146,8 +154,8 @@ function run() { }); setup('imul', (cx, cy) => { - cx = toFixed(cx); - cy = toFixed(cy); + cx = toFixed16(cx); + cy = toFixed16(cy); let zx = 0; let zy = 0; let zx_2 = 0; @@ -159,7 +167,7 @@ function run() { zx_2 = imul(zx, zx); zy_2 = imul(zy, zy); zx_zy = imul(zx, zy); - if (zx_2 + zy_2 >= four) { + if (zx_2 + zy_2 >= four16) { return i; } } @@ -169,8 +177,8 @@ function run() { }); setup('log', (cx, cy) => { - cx = toFixed(cx); - cy = toFixed(cy); + cx = toFixedLog(cx); + cy = toFixedLog(cy); let zx = 0; let zy = 0; let zx_2 = 0; @@ -182,7 +190,7 @@ function run() { zx_2 = logmul(zx, zx); zy_2 = logmul(zy, zy); zx_zy = logmul(zx, zy); - if (zx_2 + zy_2 >= four) { + if (zx_2 + zy_2 >= fourLog) { return i; } }