122 lines
3.1 KiB
Lua
Executable File
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
|