Compare commits
No commits in common. "8044dbfc21fa1f9cf334060b7919ab106c990f71" and "c3c5968749a7b74f0365018869cd33e97c3dabd6" have entirely different histories.
8044dbfc21
...
c3c5968749
3 changed files with 11 additions and 256 deletions
28
fixed.js
28
fixed.js
|
@ -4,26 +4,24 @@ let bits = 16;
|
||||||
// max Mandelbrot zx/zy addition range prior to checking distance
|
// max Mandelbrot zx/zy addition range prior to checking distance
|
||||||
let inputRange = 4;
|
let inputRange = 4;
|
||||||
|
|
||||||
let reduction = 0;
|
|
||||||
let roundOffset = (2 ** (reduction - 1)) + 1;
|
|
||||||
|
|
||||||
// Room to hold power up to -12/+4 for 16-bit mandelbrot
|
// Room to hold power up to -12/+4 for 16-bit mandelbrot
|
||||||
let shift = 5;
|
let shift = 4;
|
||||||
let base = 2 ** (bits - shift);
|
let base = 2 ** (bits - shift);
|
||||||
|
|
||||||
|
let reduction = 4;
|
||||||
|
let roundOffset = (2 ** (reduction - 1)) + 1;
|
||||||
let entries = 2 ** (bits - reduction);
|
let entries = 2 ** (bits - reduction);
|
||||||
let bytes = Math.ceil(bits / 8) * entries;
|
let bytes = Math.ceil(bits / 8) * entries;
|
||||||
|
|
||||||
// try to keep all but the last few bits semi-accurate
|
// try to keep all but the last few bits semi-accurate
|
||||||
let epsilonBits = 1;
|
let epsilonBits = 1 ;
|
||||||
let epsilon = 2 ** epsilonBits;
|
let epsilon = 2 ** epsilonBits;
|
||||||
|
|
||||||
export function toFixed(float) {
|
function toFixed(float) {
|
||||||
return Math.round(float * base);
|
return Math.round(float * base);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function toFloat(fixed) {
|
function toFloat(fixed) {
|
||||||
return fixed / base;
|
return fixed / base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,12 +48,12 @@ for (let i = 0; i < entries * 2; i++) {
|
||||||
|
|
||||||
|
|
||||||
// returns fixed point
|
// returns fixed point
|
||||||
export function log2(fixed) {
|
function log2(fixed) {
|
||||||
return enloggen[toIndex(fixed)];
|
return enloggen[toIndex(fixed)];
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns rounded integer
|
// returns rounded integer
|
||||||
export function pow2(fixed) {
|
function pow2(fixed) {
|
||||||
let n = toIndex(fixed);
|
let n = toIndex(fixed);
|
||||||
if (n > empower.length) {
|
if (n > empower.length) {
|
||||||
n = empower.length - 1;
|
n = empower.length - 1;
|
||||||
|
@ -63,7 +61,7 @@ export function pow2(fixed) {
|
||||||
return empower[entries + n];
|
return empower[entries + n];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mul(a, b) {
|
function mul(a, b) {
|
||||||
if (a == 0) return 0;
|
if (a == 0) return 0;
|
||||||
if (b == 0) return 0;
|
if (b == 0) return 0;
|
||||||
let la = log2(a)|0;
|
let la = log2(a)|0;
|
||||||
|
@ -95,7 +93,6 @@ for (let i = 0; i < powEntries; i++) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
// now just try multipling numbers
|
// now just try multipling numbers
|
||||||
let deltas = 0;
|
let deltas = 0;
|
||||||
let deltaAvg = 0;
|
let deltaAvg = 0;
|
||||||
|
@ -148,14 +145,11 @@ deltaCount = 0;
|
||||||
console.log('done');
|
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;
|
let m = 0;
|
||||||
for (let i = 0; i < enloggen.length; i++) {
|
for (let i = 0; i < enloggen.length; i++) {
|
||||||
m = Math.max(m, enloggen[i]);
|
m = Math.max(m, enloggen[i]);
|
||||||
}
|
}
|
||||||
console.log(`max enloggen entry is ${m}`);
|
console.log(`max enloggen entry is ${m}`);
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
console.log(`size of enloggen table: ${entries} entries, ${bytes} bytes`);
|
|
||||||
console.log(`size of empower table: ${entries * 2} entries, ${bytes * 2} bytes`);
|
|
||||||
|
|
36
sim.html
36
sim.html
|
@ -1,36 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Mandelbrot fixed-point test</title>
|
|
||||||
<style type="text/css">
|
|
||||||
/* */
|
|
||||||
</style>
|
|
||||||
<body>
|
|
||||||
<h1>Mandelbrot fixed-point test</h1>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>Float</th>
|
|
||||||
<th>Fixed-point imul</th>
|
|
||||||
<th>Fixed-point log</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td><canvas id="float" width="256" height="256"></canvas></td>
|
|
||||||
<td><canvas id="imul" width="256" height="256"></canvas></td>
|
|
||||||
<td><canvas id="log" width="256" height="256"></canvas></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan=3>
|
|
||||||
<button id="zoom-in">Zoom in</button>
|
|
||||||
<button id="zoom-out">Zoom out</button>
|
|
||||||
<button id="left">Left</button>
|
|
||||||
<button id="right">Right</button>
|
|
||||||
<button id="up">Up</button>
|
|
||||||
<button id="down">Down</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<script async type="module" src="sim.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
203
sim.js
203
sim.js
|
@ -1,203 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 fourLog = toFixedLog(4);
|
|
||||||
|
|
||||||
let max = 256;
|
|
||||||
let width = 256;
|
|
||||||
let height = 256;
|
|
||||||
|
|
||||||
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 = [
|
|
||||||
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(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 = scale() * (y * 2 - height) / (height / 2) + offsetY;
|
|
||||||
for (let x = 0; x < width; x++) {
|
|
||||||
let cx = scale() * (x * 2 - width) / (width / 2) + offsetX;
|
|
||||||
let i = iterfunc(cx, cy);
|
|
||||||
let color = palette[i];
|
|
||||||
rgba[y * width + x] = color;
|
|
||||||
|
|
||||||
if (x % 256 == 255) {
|
|
||||||
ctx.putImageData(imageData, 0, 0);
|
|
||||||
await nap();
|
|
||||||
if (cancelled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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('float done');
|
|
||||||
});
|
|
||||||
|
|
||||||
setup('imul', (cx, cy) => {
|
|
||||||
cx = toFixed16(cx);
|
|
||||||
cy = toFixed16(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 >= four16) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}).then(() => {
|
|
||||||
console.log('imul done');
|
|
||||||
});
|
|
||||||
|
|
||||||
setup('log', (cx, cy) => {
|
|
||||||
cx = toFixedLog(cx);
|
|
||||||
cy = toFixedLog(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 >= fourLog) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}).then(() => {
|
|
||||||
console.log('log done');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
Loading…
Reference in a new issue