Recientemente he estado trabajando en aritmética lógica . Quiero codificar enteros sin signo (Uint) y enteros con signo (Int) como bytes.
A continuación se muestra un fragmento de código que actualmente traduce UInts a bytes y viceversa. Desafortunadamente, tuve algunos problemas al codificar enteros con signo con mi táctica.
La codificación de enteros se realizará mediante este método de desplazamiento y máscara para enteros con y sin signo.
for (let i=0; i<n; i++) buffer.push((value >>> (i*8)) & 0xFF); Entonces, ¿qué tiene de malo mi método readInt y cómo solucionarlo?
const buffer = []; const writeIntN = (value, n) => { for (let i=0; i<n; i++) buffer.push((value >>> (i*8)) & 0xFF); } const readUint = (n, offset) => { let v=0; for (let i=0; i<n; i++) v |= (buffer[offset++] << (i*8)); return v >>> 0; } const readInt = (n, offset) => { return readUint(n, offset) << (8*n) >> (8*n); // error is here } const writeUInt16 = (value) => writeIntN(value, 2); const readUInt16 = (offset) => readUint(2, offset); const writeInt16 = (value) => writeIntN(value, 2); const readInt16 = (offset) => readInt(2, offset); const writeInt8 = (value) => writeIntN(value, 1); const readInt8 = (offset) => readInt(1, offset); writeUInt16(20); writeInt16(-20); writeInt8(-42); console.log(buffer); console.log(readUInt16(0)); console.log(readInt16(2)); console.log(readInt8(4)); // how? Nota : Conozco las operaciones básicas para decodificar entradas firmadas de 8,16 bits, pero ¿cómo obtener esto dentro del bucle for en readUint de manera más eficiente?
Decodificación de enteros con signo de 8 bits: (buffer[offset++] << 24) >> 24
Decodificación de enteros de 16 bits con signo: (((buffer[offset++] << 0) | (buffer[offset++] << 8)) << 16) >> 16
Entonces, ¿qué tiene de malo mi método readInt y cómo solucionarlo?
La solución: cambiar (8*n) a (8*(4-n)) .
const readInt = (n, offset) => { return readUint(n, offset) << (8*(4-n)) >> (8*(4-n)); }O equivalente,
const readInt = (n, offset) => { let v =0; for (let i=4-n; i<4; i++) v |= (buffer[offset++] << (i*8)); return v >> (8*(4-n)); } Los operadores bit a bit de JavaScript utilizan enteros de 32 bits (4 bytes). El operador de desplazamiento a la izquierda ( << ) descarta los bits desplazados a la izquierda. El operador de desplazamiento a la derecha ( >> ) propaga el bit más a la izquierda (signo).
console.log(); writeUInt16(20); writeInt16(-20); writeInt8(-42); console.log(buffer); console.log(readUInt16(0)); console.log(readInt16(2)); console.log(readInt8(4)); [ 20, 0, 236, 255, 214 ] 20 -20 -42 const buffer = []; const writeIntN = (value, n) => { for (let i=0; i<n; i++) buffer.push((value >>> (i*8)) & 0xFF); } const readUint = (n, offset) => { let v=0; for (let i=0; i<n; i++) v |= (buffer[offset++] << (i*8)); return v >>> 0; } const readInt = (n, offset) => { return readUint(n, offset) << (8*(4-n)) >> (8*(4-n)); } const writeUInt32 = (value) => writeIntN(value, 4); const readUInt32 = (offset) => readUint(4, offset); const writeInt32 = (value) => writeIntN(value, 4); const readInt32 = (offset) => readInt(4, offset); const writeUInt16 = (value) => writeIntN(value, 2); const readUInt16 = (offset) => readUint(2, offset); const writeInt16 = (value) => writeIntN(value, 2); const readInt16 = (offset) => readInt(2, offset); const writeUInt8 = (value) => writeIntN(value, 1); const readUInt8 = (offset) => readUint(1, offset); const writeInt8 = (value) => writeIntN(value, 1); const readInt8 = (offset) => readInt(1, offset); writeUInt32(Math.pow(2,32)-1); writeInt32((1<<31)-1); writeInt32(-(1<<31)); writeUInt16((1<<16)-1); writeInt16((1<<15)-1); writeInt16(-(1<<15)); writeUInt8((1<<8)-1); writeInt8((1<<7)-1); writeInt8(-(1<<7)); console.log(buffer); console.log(readUInt32(0)); console.log(readInt32(4)); console.log(readInt32(8)); console.log(readUInt16(12)); console.log(readInt16(14)); console.log(readInt16(16)); console.log(readUInt8(18)); console.log(readInt8(19)); console.log(readInt8(20)); [ 255, 255, 255, 255, 255, 255, 255, 127, 0, 0, 0, 128, 255, 255, 255, 127, 0, 128, 255, 127, 128 ] 4294967295 2147483647 -2147483648 65535 32767 -32768 255 127 -128