Convertire una stringa con una rappresentazione esadecimale di un IEEE-754 doppio in variabile numerica JavaScript

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

Domanda

Supponiamo di avere un numero esadecimale "4072,5082 mille miliardi" e voglio il numero in virgola mobile che rappresenta (293,03173828125000) in IEEE-754 a doppio formato per essere messo in una variabile JavaScript.

mi viene in mente un modo che utilizza una mascheratura e una chiamata a pow (), ma c'è una soluzione più semplice?

E 'necessaria una soluzione client-side.

Questo può aiutare. E 'un sito che consente di immettere una codifica esadecimale di un IEEE-754 e ottenere un'analisi della mantissa ed esponente.

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

Poiché le persone tendono sempre a chiedere "perché ?," Ecco perché:. Sto cercando di compilare un'implementazione esistente ma incompleta di Google Procol buffer (protobuf)

È stato utile?

Soluzione

Non so di un buon modo. Certamente può essere fatto nel modo più difficile, ecco un esempio singola precisione totalmente all'interno di JavaScript:

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

Un'implementazione di produzione dovrebbe prendere in considerazione che la maggior parte dei campi hanno valori magici, tipicamente implementato specificando un'interpretazione speciale per quello che sarebbe stato il più grande o più piccolo. Quindi, individuare NaNs e infiniti. L'esempio di cui sopra dovrebbe essere controllando per negativi. (A & 0x80000000)

Aggiornamento: Ok, ce l'ho per i doppi di, anche. Non è possibile estendere direttamente la tecnica di cui sopra perché la rappresentazione interna JS è un doppio, e quindi dalla sua definizione può gestire al massimo una stringa di bit di lunghezza 52, e non può spostarsi di oltre il 32 affatto.

Ok, a fare il doppio per la prima volta recidere come una stringa le basse 8 cifre o 32 bit; elaborarli con un oggetto separato. Poi:

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> 

Ho mantenuto l'esempio precedente, perché è dalla OP. Un caso più difficile è quando i bassi 32-bit hanno un valore. Qui è la conversione di 0x40725082deadbeef, una full-precisione doppia:

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> 

Ci sono alcuni sottoespressioni evidenti è possibile fattore di fuori, ma mi hanno lasciato in questo modo modo da poter vedere come si riferisce al formato.

Altri suggerimenti

Una rapida Oltre alla soluzione DigitalRoss', per coloro che trovare questa pagina tramite Google come ho fatto io.

A parte i casi limite di +/- Infinity e Nan, che mi piacerebbe ingresso, è inoltre necessario prendere in considerazione il segno del risultato:

s = a >> 31 ? -1 : 1

È possibile quindi includere s nella moltiplicazione finale per ottenere il risultato corretto.

Credo che per una soluzione little-endian avrete anche bisogno di invertire i bit in a e b e scambiarlo.

Il nuovo meccanismo tipizzati Array permette di fare questo (ed è probabilmente un meccanismo ideale per attuazione buffer di protocollo):

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

Questo presuppone un little-endian macchina.

Purtroppo Chrome non ha Float64Array, sebbene abbia Float32Array. L'esempio precedente funziona in Firefox 4.0.1.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top