-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconv.lua
More file actions
152 lines (139 loc) · 5.61 KB
/
conv.lua
File metadata and controls
152 lines (139 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/lua
--[[
-- Number handling functions
-- * converts a string of bytes to and from a proper number
-- * WARNING single() and double() can only do normal floats
-- and zeros. Denormals, infinities and NaNs are not recognized.
-- * See 5.0.2/ChunkSpy.lua for IEEE floating-point notes
--]]
convert_from = {} -- tables for number conversion function lookup
convert_to = {}
-----------------------------------------------------------------------
-- Converts an 8-byte little-endian string to a IEEE754 double number
-- * NOTE: see warning about accuracy in the header comments!
-----------------------------------------------------------------------
convert_from["double"] = function(x)
local sign = 1
local mantissa = string.byte(x, 7) % 16
for i = 6, 1, -1 do mantissa = mantissa * 256 + string.byte(x, i) end
if string.byte(x, 8) > 127 then sign = -1 end
local exponent = (string.byte(x, 8) % 128) * 16 +
math.floor(string.byte(x, 7) / 16)
if exponent == 0 then return 0 end
mantissa = (math.ldexp(mantissa, -52) + 1) * sign
return math.ldexp(mantissa, exponent - 1023)
end
-----------------------------------------------------------------------
-- Converts a 4-byte little-endian string to a IEEE754 single number
-- * TODO UNTESTED!!! *
-----------------------------------------------------------------------
convert_from["single"] = function(x)
local sign = 1
local mantissa = string.byte(x, 3) % 128
for i = 2, 1, -1 do mantissa = mantissa * 256 + string.byte(x, i) end
if string.byte(x, 4) > 127 then sign = -1 end
local exponent = (string.byte(x, 4) % 128) * 2 +
math.floor(string.byte(x, 3) / 128)
if exponent == 0 then return 0 end
mantissa = (math.ldexp(mantissa, -23) + 1) * sign
return math.ldexp(mantissa, exponent - 127)
end
-----------------------------------------------------------------------
-- Converts a little-endian integer string to a number
-- * TODO UNTESTED!!! *
-----------------------------------------------------------------------
convert_from["int"] = function(x)
local sum = 0
for i = config.size_lua_Number, 1, -1 do
sum = sum * 256 + string.byte(x, i)
end
-- test for negative number
if string.byte(x, config.size_lua_Number) > 127 then
sum = sum - math.ldexp(1, 8 * config.size_lua_Number)
end
return sum
end
-----------------------------------------------------------------------
-- * WARNING this will fail for large long longs (64-bit numbers)
-- because long longs exceeds the precision of doubles.
-----------------------------------------------------------------------
convert_from["long long"] = convert_from["int"]
-----------------------------------------------------------------------
-- Converts a IEEE754 double number to an 8-byte little-endian string
-- * NOTE: see warning about accuracy in the header comments!
-----------------------------------------------------------------------
convert_to["double"] = function(x)
local sign = 0
if x < 0 then sign = 1; x = -x end
local mantissa, exponent = math.frexp(x)
if x == 0 then -- zero
mantissa, exponent = 0, 0
else
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
exponent = exponent + 1022
end
local v, byte = "" -- convert to bytes
x = mantissa
for i = 1,6 do
x, byte = grab_byte(x); v = v..byte -- 47:0
end
x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
return v
end
-----------------------------------------------------------------------
-- Converts a IEEE754 single number to a 4-byte little-endian string
-- * TODO UNTESTED!!! *
-----------------------------------------------------------------------
convert_to["single"] = function(x)
local sign = 0
if x < 0 then sign = 1; x = -x end
local mantissa, exponent = math.frexp(x)
if x == 0 then -- zero
mantissa = 0; exponent = 0
else
mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 24)
exponent = exponent + 126
end
local v, byte = "" -- convert to bytes
x, byte = grab_byte(mantissa); v = v..byte -- 7:0
x, byte = grab_byte(x); v = v..byte -- 15:8
x, byte = grab_byte(exponent * 128 + x); v = v..byte -- 23:16
x, byte = grab_byte(sign * 128 + x); v = v..byte -- 31:24
return v
end
-----------------------------------------------------------------------
-- Converts a number to a little-endian integer string
-- * TODO UNTESTED!!! *
-----------------------------------------------------------------------
convert_to["int"] = function(x)
local v = ""
x = math.floor(x)
if x >= 0 then
for i = 1, config.size_lua_Number do
v = v..string.char(x % 256); x = math.floor(x / 256)
end
else-- x < 0
x = -x
local carry = 1
for i = 1, config.size_lua_Number do
local c = 255 - (x % 256) + carry
if c == 256 then c = 0; carry = 1 else carry = 0 end
v = v..string.char(c); x = math.floor(x / 256)
end
end
-- optional overflow test; not enabled at the moment
-- if x > 0 then error("number conversion overflow") end
return v
end
-----------------------------------------------------------------------
-- * WARNING this will fail for large long longs (64-bit numbers)
-- because long longs exceeds the precision of doubles.
-----------------------------------------------------------------------
convert_to["long long"] = convert_to["int"]
function get_convert_to()
return convert_to
end
function get_convert_from()
return convert_from
end