Convertir una cadena con una representación hexadecimal de un IEEE-754 doble en JavaScript variable numérica

StackOverflow https://stackoverflow.com/questions/1597709

Pregunta

Supongamos que tengo un número hexadecimal "4072508200000000" y quiero que el número de punto flotante que representa (293.03173828125000) en IEEE-754 doble formato para ser puesto en una variable de JavaScript.

Que puedo pensar de una manera que utiliza algunos de enmascaramiento y una llamada a pow(), pero hay una solución más sencilla?

Una solución de cliente que se necesita.

Esto puede ayudar.Es un sitio web que te permite entrar en un hex de codificación de IEEE-754 y obtener un análisis de mantisa y exponente.

http://babbage.cs.qc.edu/IEEE-754/64bit.html

Porque las personas siempre tienden a preguntar "¿por qué?," he aquí por qué:Estoy tratando de llenar una existente, pero incompleta aplicación de Google Procol Buffers (protobuf).

¿Fue útil?

Solución

No sé de una buena manera. Ciertamente se puede hacer de la manera difícil, aquí hay un ejemplo de precisión único totalmente dentro de JavaScript:

js> a = 0x41973333
1100428083
js> (a & 0x7fffff | 0x800000) * 1.0 / Math.pow(2,23) * Math.pow(2,  ((a>>23 & 0xff) - 127))
18.899999618530273

Una implementación de producción debe considerar que la mayoría de los campos tienen valores mágicos, típicamente implementados especificando una interpretación especial para lo que habría sido el más grande o más pequeño. Entonces, detectar NaNsy infinitos. El ejemplo anterior debe ser verificar los negativos. (A y 0x80000000)

ACTUALIZACIÓN: OK, también lo tengo para Double's. No puede extender directamente la técnica anterior porque la representación JS interna es un doble, por lo que, por su definición, puede manejar en el mejor de los casos una cadena de longitud 52, y no puede cambiar en más de 32 en absoluto.

Ok, para hacer el doble que primero te cortas Como una cadena los 8 dígitos bajos o 32 bits; procesarlos con un objeto separado. Después:

js> a = 0x40725082      
1081233538
js> (a & 0xfffff | 0x100000) * 1.0 / Math.pow(2, 52 - 32) * Math.pow(2, ((a >> 52 - 32 & 0x7ff) - 1023))
293.03173828125
js> 

Mantuve el ejemplo anterior porque es de la OP. Un caso más difícil es cuando los 32 bits bajos tienen un valor. Aquí está la conversión de 0x40725082DeadBeef, un doble de precisión completa:

js> a = 0x40725082
1081233538
js> b = 0xdeadbeef
3735928559
js> e = (a >> 52 - 32 & 0x7ff) - 1023
8
js> (a & 0xfffff | 0x100000) * 1.0 / Math.pow(2,52-32) * Math.pow(2, e) +          
     b * 1.0 / Math.pow(2, 52) * Math.pow(2, e)
293.0319506442019
js> 

Hay algunas subexpresiones obvias que puede factorizar, pero lo he dejado de esta manera para que pueda ver cómo se relaciona con el formato.

Otros consejos

Una incorporación rápida a la solución de DigitalRoss, para aquellos que encuentran esta página a través de Google como lo hice yo.

Además de los casos de borde para +/- Infinity y Nan, en los que me encantaría recibir, también debe tener en cuenta el signo del resultado:

s = a >> 31 ? -1 : 1

Entonces puedes incluir s en la multiplicación final para obtener el resultado correcto.

Creo que para una solución pequeña también necesitarás revertir los bits en a y b y cambiarlos.

El nuevo Matrices de escritura El mecanismo le permite hacer esto (y es probablemente un mecanismo ideal para implementar tampones de protocolo):

var buffer = new ArrayBuffer(8);
var bytes = new Uint8Array(buffer);
var doubles = new Float64Array(buffer); // not supported in Chrome

bytes[7] = 0x40; // Load the hex string "40 72 50 82 00 00 00 00" 
bytes[6] = 0x72;
bytes[5] = 0x50;
bytes[4] = 0x82;
bytes[3] = 0x00;
bytes[2] = 0x00;
bytes[1] = 0x00;
bytes[0] = 0x00;

my_double = doubles[0];

document.write(my_double);  // 293.03173828125

Esto asume una máquina pequeña endian.

Lamentablemente, Chrome no tiene Float64Array, aunque tiene Float32Array. El ejemplo anterior funciona en Firefox 4.0.1.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top