2013-01-19 24 views
8

Tôi muốn thực hiện một chức năng trong tinh khiết Lua mà tạo ra một phần (23 bit), một (8 bit), và một dấu (1 bit) từ một số, sao cho số đó xấp xỉ bằng math.ldexp(fraction, exponent - 127) * (sign == 1 and -1 or 1) và sau đó gói các giá trị được tạo thành 32 bit.Lua - đóng gói IEEE754 đơn chính xác số dấu chấm động

Một chức năng nhất định trong thư viện toán học làm tôi chú ý:

Chức năng frexp phá vỡ giá trị dấu chấm động (v) vào một mantissa (m) và một số mũ (n), như vậy mà giá trị tuyệt đối của m lớn hơn hoặc bằng 0,5 và nhỏ hơn 1,0, và v = m * 2^n.

Lưu ý rằng math.ldexp là hoạt động nghịch đảo.

Tuy nhiên, tôi không thể nghĩ ra cách nào để đóng gói đúng số nguyên. Khi phần định trị được trả về bởi hàm này không phải là số nguyên, tôi không chắc liệu tôi có thể sử dụng nó không.

Có cách nào hiệu quả để thực hiện điều gì đó tương tự như math.frexp() trả về số nguyên làm phần định trị không? Hoặc là có lẽ một cách tốt hơn để đóng gói số trong định dạng dấu chấm động đơn chính xác IEEE754 trong Lua?

Cảm ơn bạn trước.

Sửa

Tôi xin trình bày (hy vọng) phiên bản cuối cùng của chức năng tôi đã thực hiện:

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 

tôi cải thiện cách sử dụng các bit ngầm và thêm hỗ trợ thích hợp cho các giá trị đặc biệt như vậy như NaN và vô cùng. Tôi dựa trên định dạng của tập lệnh liên quan đến.

Tôi cảm ơn cả hai bạn vì lời khuyên tuyệt vời của bạn.

Trả lời

7

Nhân mức và bạn nhận được từ math.frexp() 2^24 và trừ 24 từ số mũ để bù. Bây giờ significand là một số nguyên. Lưu ý rằng significand là bit, không phải 23 (bạn cần tính toán bit ngầm trong mã hóa IEEE-754).

4

Bạn đã xem this chưa?

Tôi nghĩ rằng nó làm những gì bạn muốn theo một cách đơn giản hơn một chút.

+0

Cảm ơn bạn, tôi vừa kiểm tra nó. Phương pháp nó sử dụng rất giống với phương pháp của tôi, nhưng sử dụng định dạng sạch hơn. Tuy nhiên, có một vài vấn đề với nó (nó dường như không hỗ trợ số không hoặc số rất nhỏ), vì vậy tôi đang làm phiên bản của riêng tôi dựa trên nó. Tôi sẽ cập nhật bài đăng của mình khi hoàn thành. – RPFeltz

Các vấn đề liên quan