Created
July 18, 2024 06:41
-
-
Save Yaffle/09239924d8bfc3ecb2bac50c5c96c7a6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let hex = new Uint8Array(0); | |
const td = new TextDecoder(); | |
const te = new TextEncoder(); | |
function packBigInt(blocks, blockSize) { | |
function encode(blocks, length) { | |
const u32 = new Uint32Array(hex.buffer); | |
let k = (length >> 2) - 1;//TODO:!? | |
for (let i = 0; i < blocks.length; i += 1) { | |
let e = blocks[i] | 0; | |
e = (e | (e << 24)) & 0xFF00FF00; | |
e = (e | (e >>> 12)) & 0x0F0F0F0F; | |
const m = ((e + 0x16161616) & 0x20202020); | |
e = ((e + 0x30303030) + (m) + (m >>> 2) - (m >>> 5)) | 0; | |
u32[k] = e; | |
k = (k - 1) | 0; | |
} | |
} | |
blockSize |= 0; | |
if (blockSize % 4 !== 0) { | |
throw new RangeError(); | |
} | |
blockSize >>= 2; | |
if (blockSize > 8) { | |
let s = ''; | |
s += '0x'; | |
const zeros = '0'.repeat(blockSize); | |
for (let i = blocks.length - 1; i >= 0; i -= 1) { | |
const x = blocks[i].toString(16); | |
if (x.length < blockSize) { | |
s += zeros.slice(0, blockSize - x.length); | |
} | |
s += x; | |
} | |
return BigInt(s); | |
} | |
let length = (blocks.length * blockSize + 4) | 0; | |
if (hex.length < length) { | |
hex = new Uint8Array(length + (length % 4 !== 0 ? 4 - length % 4 : 0)); | |
} | |
hex[0] = 48; // '0' | |
hex[1] = 120; // 'x' | |
hex[2] = 48; | |
hex[3] = 48; | |
if (blockSize === 4) { | |
encode(blocks, length); | |
} else { | |
let k = length - 1; | |
for (let i = 0; i < blocks.length; i += 1) { | |
let e = blocks[i] | 0; | |
for (let j = blockSize; j !== 0; j = (j - 1) | 0) { | |
const r = e & 0xF; | |
hex[k] = (((r + 48) | 0) + (r < 10 ? 0 : 39)) | 0; | |
k = (k - 1) | 0; | |
e >>= 4; | |
} | |
} | |
} | |
return BigInt(td.decode(hex.subarray(0, length))); | |
} | |
function unpackBigInt(bigint, blockSize, blocksCount) { | |
function decode(blocks, length) { | |
let k = (length >> 2) - 1; | |
const u32 = new Uint32Array(hex.buffer); | |
for (let i = 0; i < length; i += 4) { | |
let a = u32[i >> 2]; | |
const m = ((a + 0x1F1F1F1F) & 0x80808080); | |
a = ((a - 0x30303030) - (m >>> 2) - (m >>> 4) + (m >>> 7)) | 0; | |
a = (a | (a << 12)) & 0xFF00FF00; | |
a = (a | (a >>> 24)) & 0x0000FFFF; | |
blocks[k] = a; | |
k = (k - 1) | 0; | |
} | |
} | |
blockSize |= 0; | |
blocksCount |= 0; | |
if (blockSize % 4 !== 0) { | |
throw new RangeError(); | |
} | |
blockSize >>= 2; | |
let s = bigint.toString(16); | |
if (s.length % blockSize !== 0) { | |
s = '0'.repeat(blockSize - s.length % blockSize) + s; | |
} | |
if (blockSize > 8) { | |
const blocks = new Array(blocksCount); | |
let k = s.length; | |
for (let i = 0; i < blocks.length; i += 1) { | |
blocks[i] = BigInt('0x' + s.slice(k < blockSize ? 0 : k - blockSize, k)); | |
k -= blockSize; | |
} | |
return blocks; | |
} | |
if (hex.length < s.length) { | |
hex = new Uint8Array(s.length); | |
} | |
te.encodeInto(s, hex); | |
const length = s.length | 0; | |
const blocks = new Array(blocksCount); | |
if (blockSize === 4) { | |
decode(blocks, length); | |
} else { | |
let k = 0; | |
for (let i = blocksCount - 1; i >= 0; i -= 1) { | |
let x = 0; | |
for (let j = blockSize; j !== 0; j = (j - 1) | 0) { | |
let a = hex[k] | 0; | |
a = (a - 48) - (a < 97 ? 0 : 39); | |
x = (x << 4) | a; | |
k = (k + 1) | 0; | |
} | |
blocks[i] = -0 + x; | |
} | |
} | |
return blocks; | |
} | |
const arrayToBigInt2 = packBigInt; | |
const bigIntToArray2 = function (a, b, c) { return unpackBigInt(a, c, b); }; | |
const xxx = new Map(); | |
function smallBigInt(m) { | |
let x = xxx.get(m); | |
if (x == null) { | |
x = BigInt(m); | |
xxx.set(m, x); | |
} | |
return x; | |
} | |
function arrayToBigInt0(array, elementSize) { | |
function internal(start, end) { | |
const k = end - start; | |
if (k >= 2) { | |
const m = Math.ceil(k / 2); | |
return (internal(start + m, end) << smallBigInt(m * elementSize)) | internal(start, start + m); | |
} else if (k === 1) { | |
return BigInt(array[start]); | |
} else { | |
return 0n; | |
} | |
} | |
return internal(0, array.length); | |
} | |
function bigIntToArray0(bigint, size, elementSize) { | |
const array = new Array(size); | |
function internal(bigint, start, end) { | |
const k = end - start; | |
if (k >= 2) { | |
const m = Math.ceil(k / 2); | |
const r = BigInt.asUintN(m * elementSize, bigint); | |
internal(r, start, start + m); | |
const q = bigint >> smallBigInt(m * elementSize); | |
internal(q, start + m, end); | |
} else if (k === 1) { | |
array[start] = bigint; | |
} | |
} | |
internal(bigint, 0, size); | |
return array; | |
} | |
const xxx64 = []; | |
function smallBigInt64(m) { | |
while (m >= xxx64.length) { | |
xxx64.push(BigInt(xxx64.length * 64)); | |
} | |
return xxx64[m]; | |
} | |
function arrayToBigInt(array, elementSize) { | |
if (elementSize !== 16) { | |
return arrayToBigInt0(array, elementSize); | |
} | |
const u16 = new Uint16Array(array.length + (array.length % 4 === 0 ? 0 : 4 - array.length % 4)); | |
for (let i = 0; i < array.length; i++) { | |
u16[i] = array[i]; | |
} | |
const u64 = new BigUint64Array(u16.buffer); | |
function internal(start, end) { | |
const k = end - start; | |
if (k >= 2) { | |
const m = Math.ceil(k / 2); | |
return (internal(start + m, end) << smallBigInt64(m)) | internal(start, start + m); | |
} else if (k === 1) { | |
return u64[start]; | |
} else { | |
return 0n; | |
} | |
} | |
return internal(0, u64.length); | |
} | |
function bigIntToArray(bigint, size, elementSize) { | |
if (elementSize !== 16) { | |
return bigIntToArray0(bigint, size, elementSize); | |
} | |
const u64 = new BigInt64Array(Math.ceil(size / 4)); | |
function internal(bigint, start, end) { | |
const k = end - start; | |
if (k === 2) { | |
u64[start] = bigint; | |
u64[start + 1] = bigint >> 64n; | |
} else if (k >= 2) { | |
const m = Math.ceil(k / 2); | |
const r = BigInt.asIntN(m << 6, bigint); | |
internal(r, start, start + m); | |
const q = bigint >> smallBigInt64(m); | |
internal(q, start + m, end); | |
} else if (k === 1) { | |
u64[start] = bigint; | |
} | |
} | |
internal(bigint, 0, size); | |
return new Uint16Array(u64.buffer); | |
} | |
/* | |
if (elementSize === 4) { | |
for (let i = 0; i < size; i += 1) { | |
array[i] = u16[size - 1 - i]; | |
} | |
} else { | |
let i = size - 1; | |
let k = 0; | |
let bits = 0; | |
let x = 0; | |
let elementBitSize = elementSize << 2; | |
while (k < (length >> 2)) { | |
x = (x << 16) | u16[k]; | |
k = (k + 1) | 0; | |
bits = (bits + 16) | 0; | |
while (bits >= elementBitSize) { | |
bits = (bits - elementBitSize) | 0; | |
array[i] = (x >> bits); | |
i -= 1; | |
x = (x & ~(-1 << bits)); | |
} | |
} | |
} | |
{ | |
let hex = new Uint8Array([1,2,3,4,5,6,7,8].map(e => e + 0x30)); | |
var array = new Array(2); | |
var k = 0; | |
for (var i = 2 - 1; i >= 0; i -= 1) { | |
let x = 0; | |
for (let j = 4; j !== 0; j = (j - 1) | 0) { | |
let a = hex[k] | 0; | |
k = (k + 1) | 0; | |
a = (((a - 48) | 0) - (a < 97 ? 0 : 39)) | 0; | |
x = (x << 4) | a; | |
} | |
array[i] = x; | |
} | |
debugger; | |
const u32 = new Uint32Array(hex.buffer); | |
const u16 = new Uint16Array(hex.buffer); | |
for (let i = 0; i < u32.length; i++) { | |
let a = u32[i]; | |
//a = (a - 48) - (a < 97 ? 0 : 39); | |
const m = ((a + 0x1F1F1F1F) & 0x80808080); | |
a = (a - 0x30303030) - (m >>> 2) - (m >>> 4) + (m >>> 7); | |
a = (a | (a << 12)) & 0xFF00FF00; | |
a = (a | (a >> 24)) & 0x0000FFFF; | |
u16[i] = a; | |
} | |
debugger; | |
console.log(u32, u16); | |
} | |
const te = new TextEncoder(); | |
function bigIntToArray2(bigint, size, elementSize) { | |
size |= 0; | |
elementSize |= 0; | |
if (elementSize % 4 !== 0) { | |
throw new RangeError(); | |
} | |
elementSize >>= 2; | |
let s = bigint.toString(16); | |
if (s.length % 4 !== 0) { | |
s = '0'.repeat(4 - s.length % 4) + s; | |
} | |
if (elementSize > 8) { | |
const array = new Array(size); | |
let k = s.length; | |
for (let i = 0; i < array.length; i += 1) { | |
array[i] = BigInt('0x' + s.slice(k < elementSize ? 0 : k - elementSize, k)); | |
k -= elementSize; | |
} | |
return array; | |
} | |
const hex = te.encode(s); | |
const u32 = new Uint32Array(hex.buffer); | |
const u16 = new Uint16Array(hex.buffer); | |
for (let i = 0; i < u32.length; i++) { | |
let a = u32[i]; | |
//a = (a - 48) - (a < 97 ? 0 : 39); | |
const m = ((a + 0x1F1F1F1F) & 0x80808080); | |
a = (a - 0x30303030) - (m >>> 2) - (m >>> 4) + (m >>> 7); | |
a = (a | (a << 12)) & 0xFF00FF00; | |
a = (a | (a >> 24)) & 0x0000FFFF; | |
u16[i] = a; | |
} | |
const array = [];//new Array(size); | |
let j = 0; | |
let k = u32.length - 1; | |
let bits = 0; | |
let x = 0; | |
let elementBitSize = elementSize << 2; | |
while (k >= 0) { | |
x = (x << 16) | u16[k]; | |
bits += 16; | |
while (bits >= elementBitSize) { | |
const d = bits === elementBitSize ? x : (x >> (bits - elementBitSize)); | |
//array[j] = d; | |
array.push(d); | |
j += 1; | |
x = bits === elementBitSize ? 0 : (x & ~(-1 << (bits - elementBitSize))); | |
bits -= elementBitSize; | |
} | |
k -= 1; | |
} | |
return array; | |
} | |
*/ | |
console.assert(arrayToBigInt2([1, 2, 3], 8).toString(16) === '30201'); | |
console.assert(bigIntToArray2(0x030201n, 3, 8).join(',') === '1,2,3' || bigIntToArray2(0x030201n, 3, 8).join(',') === '1,2,3,0'); | |
console.assert(arrayToBigInt([1, 2, 3], 8).toString(16) === '30201'); | |
console.assert(bigIntToArray(0x030201n, 3, 8).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt2([1, 2, 3], 16).toString(16) === '300020001'); | |
console.assert(bigIntToArray2(0x300020001n, 3, 16).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt([1, 2, 3], 16).toString(16) === '300020001'); | |
console.assert(bigIntToArray(0x300020001n, 3, 16).join(',') === '1,2,3' || bigIntToArray(0x300020001n, 3, 16).join(',') === '1,2,3,0'); | |
console.assert(arrayToBigInt2([1, 2, 3], 20).toString(16) === '30000200001'); | |
console.assert(bigIntToArray2(0x30000200001n, 3, 20).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt([1, 2, 3], 20).toString(16) === '30000200001'); | |
console.assert(bigIntToArray(0x30000200001n, 3, 20).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt2([1, 2, 3], 24).toString(16) === '3000002000001'); | |
console.assert(bigIntToArray2(0x3000002000001n, 3, 24).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt([1, 2, 3], 24).toString(16) === '3000002000001'); | |
console.assert(bigIntToArray(0x3000002000001n, 3, 24).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt2([1, 2, 3], 28).toString(16) === '300000020000001'); | |
console.assert(bigIntToArray2(0x300000020000001n, 3, 28).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt([1, 2, 3], 28).toString(16) === '300000020000001'); | |
console.assert(bigIntToArray(0x300000020000001n, 3, 28).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt2([1, 2, 3], 32).toString(16) === '30000000200000001'); | |
console.assert(bigIntToArray2(0x30000000200000001n, 3, 32).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt([1, 2, 3], 32).toString(16) === '30000000200000001'); | |
console.assert(bigIntToArray(0x30000000200000001n, 3, 32).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt2([1, 2, 3], 48).toString(16) === '3000000000002000000000001'); | |
console.assert(bigIntToArray2(0x3000000000002000000000001n, 3, 48).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt([1, 2, 3], 48).toString(16) === '3000000000002000000000001'); | |
console.assert(bigIntToArray(0x3000000000002000000000001n, 3, 48).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt2([1, 2, 3], 96).toString(16) === '3000000000000000000000002000000000000000000000001'); | |
console.assert(bigIntToArray2(0x3000000000000000000000002000000000000000000000001n, 3, 96).join(',') === '1,2,3'); | |
console.assert(arrayToBigInt([1, 2, 3], 96).toString(16) === '3000000000000000000000002000000000000000000000001'); | |
console.assert(bigIntToArray(0x3000000000000000000000002000000000000000000000001n, 3, 96).join(',') === '1,2,3'); | |
const count = 100000; | |
const size = 2**14; | |
//const count = 2; | |
//const size = 2**29; | |
const maxBigInt = BigInt.asUintN(size, -1n); | |
//TODO: real world example from the multiplication (?) | |
//and forget | |
for (let bits = 16; bits <= 16; bits = bits + 48) { | |
//console.time('bigIntToArray:' + bits); | |
//for (let i = 0; i < count; i++) { | |
//var buffer = bigIntToArray(maxBigInt, Math.ceil(size / bits), bits) | |
//} | |
//console.timeEnd('bigIntToArray:' + bits); | |
console.time('bigIntToArray2:' + bits); | |
for (let i = 0; i < count; i++) { | |
var buffer2 = bigIntToArray2(maxBigInt, Math.ceil(size / bits), bits) | |
} | |
console.timeEnd('bigIntToArray2:' + bits); | |
// bigIntToArray2:16: 1379.4541015625 ms | |
//console.time('arrayToBigInt:' + bits); | |
//for (let i = 0; i < count; i++) { | |
//var a = arrayToBigInt(buffer, bits); | |
//} | |
//console.timeEnd('arrayToBigInt:' + bits); | |
console.time('arrayToBigInt2:' + bits); | |
for (let i = 0; i < count; i++) { | |
var a2 = arrayToBigInt2(buffer2, bits); | |
} | |
console.timeEnd('arrayToBigInt2:' + bits); | |
// arrayToBigInt2:16: 1523.404052734375 ms | |
//console.assert(maxBigInt === a); | |
console.assert(maxBigInt === a2); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment