2013-01-19 12 views
8

voglio fare una funzione in puro Lua che genera un frazione (23 bit), un esponente (8 bit), e un segno(1 bit) da un numero, in modo che il numero sia approssimativamente uguale a math.ldexp(fraction, exponent - 127) * (sign == 1 and -1 or 1) e quindi comprime i valori generati in 32 bit.Lua - imballaggio numeri a virgola mobile in singola precisione IEEE754

una certa funzione nella libreria matematica attirato la mia attenzione:

La funzione frexp rompe il valore in virgola mobile (v) in una mantissa (m) e un esponente (n), in modo tale che il il valore assoluto di m è maggiore o uguale a 0.5 e minore di 1.0 e v = m * 2^n.

Si noti che math.ldexp è l'operazione inversa.

Tuttavia, non riesco a pensare ad alcun modo per comprimere correttamente i numeri non interi. Poiché la mantissa restituita da questa funzione non è un numero intero, non sono sicuro di poterla usare.

Esiste un modo efficace per fare qualcosa di simile a math.frexp() che restituisce un intero come mantissa? O c'è forse un modo migliore per impacchettare i numeri nel formato a virgola mobile IEEE754 a precisione singola in Lua?

Grazie in anticipo.

Modifica

presento la (si spera) versione definitiva delle funzioni che ho fatto:

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 

ho migliorato il modo di utilizzare il bit implicita e aggiunto il supporto adeguato per valori speciali tali come NaN e infinito. Ho basato la formattazione su quella della sceneggiatura di catwell collegata a.

Grazie per l'ottimo consiglio.

risposta

7

Moltiplicare il significato e ottenere da math.frexp() di 2^24 e sottrarre 24 dall'esponente per compensare. Ora il significato è un numero intero. Si noti che il significato è bit, non 23 (è necessario tenere conto del bit implicito nella codifica IEEE-754).

4

Hai visto this?

Penso che faccia quello che vuoi in un modo leggermente più semplice.

+0

Grazie, l'ho appena controllato. Il metodo che usa è molto simile a quello del mio, ma usa una formattazione più pulita. Tuttavia, ci sono alcuni problemi con esso (non sembra supportare zero o numeri molto piccoli), quindi sto facendo la mia versione basata su di esso. Aggiornerò il mio post quando è fatto. – RPFeltz

Problemi correlati