2013-01-19 4 views
8

I eine Funktion in reiner Lua machen möge, die ein Fraktion (23 Bits) erzeugt, einen Exponenten (8 Bits) und ein Zeichen (1 Bit) von einer Zahl, so dass die Zahl ungefähr gleich math.ldexp(fraction, exponent - 127) * (sign == 1 and -1 or 1) ist, und packt dann die generierten Werte in 32 Bits.Lua - Verpackungs IEEE754 einfache Genauigkeit Gleitkommazahlen

eine bestimmte Funktion in der Mathematik-Bibliothek meine Aufmerksamkeit erregte:

Die frexp Funktion bricht den Gleitkommawert (v) in eine Mantisse (m) und einen Exponenten (n), derart, dass die der absolute Wert von m ist größer als oder gleich 0,5 und kleiner als 1,0 und v = m * 2^n.

Beachten Sie, dass math.ldexp die umgekehrte Operation ist.

Allerdings kann ich mir keine Möglichkeit vorstellen, nicht ganzzahlige Zahlen richtig zu packen. Da die von dieser Funktion zurückgegebene Mantisse keine ganze Zahl ist, bin ich mir nicht sicher, ob ich sie benutzen kann.

Gibt es eine effiziente Möglichkeit, etwas Ähnliches wie math.frexp() zu tun, das eine ganze Zahl als Mantisse zurückgibt? Oder gibt es vielleicht eine bessere Möglichkeit, Zahlen in das IEEE754 Gleitkomma-Format mit einfacher Genauigkeit in Lua zu packen?

Vielen Dank im Voraus.

bearbeiten

stelle ich hiermit die (hoffentlich) letzte Version der Funktionen, die ich gemacht:

function PackIEEE754(number) 
    if number == 0 then 
     return string.char(0x00, 0x00, 0x00, 0x00) 
    elseif number ~= number then 
     return string.char(0xFF, 0xFF, 0xFF, 0xFF) 
    else 
     local sign = 0x00 
     if number < 0 then 
      sign = 0x80 
      number = -number 
     end 
     local mantissa, exponent = math.frexp(number) 
     exponent = exponent + 0x7F 
     if exponent <= 0 then 
      mantissa = math.ldexp(mantissa, exponent - 1) 
      exponent = 0 
     elseif exponent > 0 then 
      if exponent >= 0xFF then 
       return string.char(sign + 0x7F, 0x80, 0x00, 0x00) 
      elseif exponent == 1 then 
       exponent = 0 
      else 
       mantissa = mantissa * 2 - 1 
       exponent = exponent - 1 
      end 
     end 
     mantissa = math.floor(math.ldexp(mantissa, 23) + 0.5) 
     return string.char(
       sign + math.floor(exponent/2), 
       (exponent % 2) * 0x80 + math.floor(mantissa/0x10000), 
       math.floor(mantissa/0x100) % 0x100, 
       mantissa % 0x100) 
    end 
end 
function UnpackIEEE754(packed) 
    local b1, b2, b3, b4 = string.byte(packed, 1, 4) 
    local exponent = (b1 % 0x80) * 0x02 + math.floor(b2/0x80) 
    local mantissa = math.ldexp(((b2 % 0x80) * 0x100 + b3) * 0x100 + b4, -23) 
    if exponent == 0xFF then 
     if mantissa > 0 then 
      return 0/0 
     else 
      mantissa = math.huge 
      exponent = 0x7F 
     end 
    elseif exponent > 0 then 
     mantissa = mantissa + 1 
    else 
     exponent = exponent + 1 
    end 
    if b1 >= 0x80 then 
     mantissa = -mantissa 
    end 
    return math.ldexp(mantissa, exponent - 0x7F) 
end 

I verbessert die Art und Weise die implizite Bit zu nutzen und hinzugefügt richtige Unterstützung für spezielle Werte, als NaN und Unendlichkeit. Ich habe die Formatierung auf die des mit catwell verknüpften Skripts gestützt.

Ich danke Ihnen beiden für Ihren guten Rat.

Antwort

7

Multiplizieren Sie den von math.frexp() erhaltenen Signifikanden mit 2^24, und subtrahieren Sie den Exponenten vom Exponenten um 24 zu kompensieren. Jetzt ist der Signifikand eine ganze Zahl. Beachten Sie, dass der Signifikand Bits ist, nicht 23 (Sie müssen das implizite Bit in der IEEE-754-Codierung berücksichtigen).

4

Haben Sie this gesehen?

Ich denke, es macht was Sie wollen auf eine leicht vereinfachte Art und Weise.

+0

Danke, ich habe es gerade überprüft. Die verwendete Methode ist der von mir sehr ähnlich, verwendet aber eine sauberere Formatierung. Es gibt jedoch ein paar Probleme damit (es scheint keine Null oder sehr kleine Zahlen zu unterstützen), also mache ich meine eigene Version darauf basierend. Ich werde meinen Beitrag aktualisieren, wenn es fertig ist. – RPFeltz

Verwandte Themen