122 lines
3.1 KiB
Lua
Executable File

-- floating point module
-- Copyright © 2008 Peter "Corsix" Cawley and Ben "ToxicFrog" Kelly; see COPYING
local fp = {}
local name = (...):gsub('%.[^%.]+$', '')
local struct = require (name)
local common = require (name..".common")
local function reader(data, size_exp, size_fraction)
local fraction, exponent, sign
local endian = common.is_bigendian and ">" or "<"
-- Split the unsigned integer into the 3 IEEE fields
local bits = struct.unpack(endian.."m"..#data, data, true)
local fraction = struct.implode({unpack(bits, 1, size_fraction)}, size_fraction)
local exponent = struct.implode({unpack(bits, size_fraction+1, size_fraction+size_exp)}, size_exp)
local sign = bits[#bits] and -1 or 1
-- special case: exponent is all 1s
if exponent == 2^size_exp-1 then
-- significand is 0? +- infinity
if fraction == 0 then
return sign * math.huge
-- otherwise it's NaN
else
return 0/0
end
end
-- restore the MSB of the significand, unless it's a subnormal number
if exponent ~= 0 then
fraction = fraction + (2 ^ size_fraction)
else
exponent = 1
end
-- remove the exponent bias
exponent = exponent - 2 ^ (size_exp - 1) + 1
-- Decrease the size of the exponent rather than make the fraction (0.5, 1]
exponent = exponent - size_fraction
return sign * math.ldexp(fraction, exponent)
end
local function writer(value, size_exp, size_fraction)
local fraction, exponent, sign
local width = (size_exp + size_fraction + 1)/8
local endian = common.is_bigendian and ">" or "<"
local bias = 2^(size_exp-1)-1
if value < 0
or 1/value == -math.huge then -- handle the case of -0
sign = true
value = -value
else
sign = false
end
-- special case: value is infinite
if value == math.huge then
exponent = bias+1
fraction = 0
-- special case: value is NaN
elseif value ~= value then
exponent = bias+1
fraction = 2^(size_fraction-1)
--special case: value is 0
elseif value == 0 then
exponent = -bias
fraction = 0
else
fraction,exponent = math.frexp(value)
-- subnormal number
if exponent+bias <= 1 then
fraction = fraction * 2^(size_fraction+(exponent+bias)-1)
exponent = -bias
else
-- remove the most significant bit from the fraction and adjust exponent
fraction = fraction - 0.5
exponent = exponent - 1
-- turn the fraction into an integer
fraction = fraction * 2^(size_fraction+1)
end
end
-- add the exponent bias
exponent = exponent + bias
local bits = struct.explode(fraction)
local bits_exp = struct.explode(exponent)
for i=1,size_exp do
bits[size_fraction+i] = bits_exp[i]
end
bits[size_fraction+size_exp+1] = sign
return struct.pack(endian.."m"..width, {bits})
end
-- Create readers and writers for the IEEE sizes
fp.sizes = {
[4] = {1, 8, 23},
[8] = {1, 11, 52},
}
fp.r = {}
fp.w = {}
for width, sizes in pairs(fp.sizes) do
fp.r[width] = function(uint) return reader(uint, sizes[2], sizes[3]) end
fp.w[width] = function(valu) return writer(valu, sizes[2], sizes[3]) end
end
return fp