2013-04-10 4 views
5

Okay, ich bin eine ziemlich nervige Situation, wo ich nicht auf typisierte Arrays wie Float32Array zugreifen kann, aber immer noch eine Javascript-Nummer in Bytes konvertieren muss . Nun, eine Ganzzahl kann ich gut verarbeiten, aber ich habe keine Ahnung, wie man es für einen Gleitkommawert macht.Convert "float" in Bytes in Javascript ohne Float32Array

Ich habe das Problem gelöst, es anders herum zu tun (Bytes in einen Float), aber die Dokumentation zum Konvertieren von Float in Bytes ist ziemlich selten, da die meisten Sprachen nur den Zeiger lesen lassen oder gemeinsame Klassen haben Umgang damit.

Idealerweise würde ich gerne in der Lage sein, Floats in 4-Byte- und 8-Byte-Darstellungen zu konvertieren und auszuwählen, welche zu verwenden ist. Allerdings wäre Code, der einfach eine Zahl nehmen und als 8-Byte ausspucken kann, immer noch großartig, da ich von dort aus wohl selbst auf die 32-Bit-Version kommen kann.

+2

'toString (2)' wird helfen? '(42) .toString (2)' – Mohsen

+1

Sie finden vielleicht auch Verwendung von ['Number.toExponential'] (https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/ toExponential) –

Antwort

7

Okay, also habe ich es herausgefunden, also teile ich meine Lösung für einfache und doppelte Präzision. Jetzt kann ich nicht garantieren, dass sie 100% konform sind, aber sie erfordern keine Schleifen und scheinen gut zu funktionieren:

Einfache Genauigkeit (bei einem Dezimalwert wird eine einzelne 32-Bit große Endian-Ganzzahl mit der Binärzahl ausgegeben Darstellung):

function toFloat32(value) { 
    var bytes = 0; 
    switch (value) { 
     case Number.POSITIVE_INFINITY: bytes = 0x7F800000; break; 
     case Number.NEGATIVE_INFINITY: bytes = 0xFF800000; break; 
     case +0.0: bytes = 0x40000000; break; 
     case -0.0: bytes = 0xC0000000; break; 
     default: 
      if (Number.isNaN(value)) { bytes = 0x7FC00000; break; } 

      if (value <= -0.0) { 
       bytes = 0x80000000; 
       value = -value; 
      } 

      var exponent = Math.floor(Math.log(value)/Math.log(2)); 
      var significand = ((value/Math.pow(2, exponent)) * 0x00800000) | 0; 

      exponent += 127; 
      if (exponent >= 0xFF) { 
       exponent = 0xFF; 
       significand = 0; 
      } else if (exponent < 0) exponent = 0; 

      bytes = bytes | (exponent << 23); 
      bytes = bytes | (significand & ~(-1 << 23)); 
     break; 
    } 
    return bytes; 
}; 

doppelte Genauigkeit (Dezimalwert gibt zwei 32-Bit-Zahlen mit der binären Darstellung in big-endian-Ordnung gegeben):

function toFloat64(value) { 
    if ((byteOffset + 8) > this.byteLength) 
     throw "Invalid byteOffset: Cannot write beyond view boundaries."; 

    var hiWord = 0, loWord = 0; 
    switch (value) { 
     case Number.POSITIVE_INFINITY: hiWord = 0x7FF00000; break; 
     case Number.NEGATIVE_INFINITY: hiWord = 0xFFF00000; break; 
     case +0.0: hiWord = 0x40000000; break; 
     case -0.0: hiWord = 0xC0000000; break; 
     default: 
      if (Number.isNaN(value)) { hiWord = 0x7FF80000; break; } 

      if (value <= -0.0) { 
       hiWord = 0x80000000; 
       value = -value; 
      } 

      var exponent = Math.floor(Math.log(value)/Math.log(2)); 
      var significand = Math.floor((value/Math.pow(2, exponent)) * Math.pow(2, 52)); 

      loWord = significand & 0xFFFFFFFF; 
      significand /= Math.pow(2, 32); 

      exponent += 1023; 
      if (exponent >= 0x7FF) { 
       exponent = 0x7FF; 
       significand = 0; 
      } else if (exponent < 0) exponent = 0; 

      hiWord = hiWord | (exponent << 20); 
      hiWord = hiWord | (significand & ~(-1 << 20)); 
     break; 
    } 

    return [hiWord, loWord]; 
}; 

Apologies für Fehler in Kopieren/Einfügen, auch der code vermeidet jeglichen Umgang mit endianess, tho Es ist ziemlich einfach hinzuzufügen.

Danke an alle, die Vorschläge gepostet haben, aber am Ende habe ich es meistens selbst herausgefunden, weil ich vermeiden wollte, so viel wie möglich mit der Geschwindigkeit zu schleifen; es ist immer noch nicht wirklich blitzschnell, aber es wird tun =)

+0

Da ist * ein kleiner Rundungsfehler hier sieht es so aus. Es ist verdammt nah dran. Gute Arbeit. – Qix

+0

^Ich habe mich geirrt; 64-Bit-Präzision funktioniert wunderbar. – Qix

1

Siehe BinaryParser.encodeFloat here.

+0

Diese Bibliothek verwendet 'mit' (und ich bin mir sicher, ein paar andere Nicht-Nos) und ist somit * nicht *' streng' konform! Vorsicht beim Gebrauch! – Qix