local function from_radix(digits, base) local ip = 0 local fp = 0 local dp = nil for i, v in ipairs(digits) do if v == "." then dp = i break end if type(v) ~= "number" then error("Invalid digit in input") end if v < 0 or v >= base then error("Digit out of range for given base") end end if dp then for i = 1, dp - 1 do ip = ip * base + digits[i] end for i = dp + 1, #digits do fp = fp + digits[i] / (base ^ (i - dp)) end else for i = 1, #digits do ip = ip * base + digits[i] end end return ip + fp end local function to_radix(x, base, frac_digits) if base < 2 then error("Base must be at least 2") end if frac_digits and frac_digits < 0 then error("Number of fractional digits must be non-negative") end local result = {} local ip = math.floor(x) local fp = x - ip repeat table.insert(result, 1, ip % base) ip = math.floor(ip / base) until ip == 0 if frac_digits and frac_digits > 0 then table.insert(result, ".") for _ = 1, frac_digits do fp = fp * base local digit = math.floor(fp) table.insert(result, digit) fp = fp - digit end end return result end local function clock_from_moment(tee) local seconds = math.fmod(tee, 86400) if seconds < 0 then seconds = seconds + 86400 end local hours = math.floor(seconds / 3600) seconds = math.fmod(seconds, 3600) local minutes = math.floor(seconds / 60) seconds = math.fmod(seconds, 60) return {hours, minutes, math.floor(seconds)} end local function time_from_clock(hms) if #hms ~= 3 then error("Clock time must have 3 elements: {hours, minutes, seconds}") end for _, v in ipairs(hms) do if type(v) ~= "number" then error("Clock time elements must be numbers") end end if hms[1] < 0 or hms[1] > 23 then error("Hours must be between 0 and 23") end if hms[2] < 0 or hms[2] > 59 then error("Minutes must be between 0 and 59") end if hms[3] < 0 or hms[3] > 59 then error("Seconds must be between 0 and 59") end return ((hms[1] * 3600) + (hms[2] * 60) + hms[3]) / 86400 end local function table_tostring(t) if type(t) ~= "table" then return tostring(t) end local s = "{" for k, v in pairs(t) do s = s .. "[" .. tostring(k) .. "] = " .. tostring(v) .. ", " end if #s > 1 then s = s:sub(1, #s - 2) end return s .. "}" end local function float_equal(a, b, tolerance) tolerance = tolerance or 1e-9 return math.abs(a - b) < tolerance end local function assert_eq(actual, expected, message) local success = false if type(actual) == type(expected) then if type(actual) == "table" then local actual_count = 0 local expected_count = 0 for _ in pairs(actual) do actual_count = actual_count + 1 end for _ in pairs(expected) do expected_count = expected_count + 1 end if actual_count == expected_count then success = true for k, exp_v in pairs(expected) do local v = actual[k] if type(v) == "number" and type(exp_v) == "number" then if not float_equal(v, exp_v) then success = false break end elseif tostring(v) ~= tostring(exp_v) then success = false break end end end elseif type(actual) == "number" then success = float_equal(actual, expected) else success = actual == expected end end if not success then error( "Assertion failed: " .. message .. "\n" .. "Expected: " .. table_tostring(expected) .. "\n" .. "Got: " .. table_tostring(actual) ) end end local tests = { {function() return from_radix({1, 0, 1, ".", 1, 1}, 2) end, 5.75, "Binary 101.11"}, {function() return to_radix(5.75, 2, 5) end, {1, 0, 1, ".", 1, 1, 0, 0, 0}, "Decimal 5.75 to binary"}, {function() return to_radix(12345, 16) end, {3, 0, 3, 9}, "Decimal 12345 to hex"}, {function() return to_radix(0.3, 2, 10) end, {0, ".", 0, 1, 0, 0, 1, 1, 0, 0, 1, 1}, "Decimal 0.3 to binary"}, {function() return clock_from_moment(3723) end, {1, 2, 3}, "3723 seconds to clock time"}, {function() return clock_from_moment(0) end, {0, 0, 0}, "0 seconds to clock time"}, {function() return clock_from_moment(86400) end, {0, 0, 0}, "86400 seconds to clock time"}, {function() return clock_from_moment(86461) end, {0, 1, 1}, "86461 seconds to clock time"}, {function() return clock_from_moment(123456) end, {10, 17, 36}, "123456 seconds to clock time"}, {function() return time_from_clock({1, 2, 3}) end, 0.043090277777778, "Clock time 1:2:3 to fraction of day"}, {function() return time_from_clock({0, 0, 0}) end, 0, "Clock time 0:0:0 to fraction of day"}, {function() return time_from_clock({12, 0, 0}) end, 0.5, "Clock time 12:0:0 to fraction of day"}, {function() return time_from_clock({23, 59, 59}) end, 0.99998842592593, "Clock time 23:59:59 to fraction of day"}, {function() return time_from_clock({1, 10, 56}) end, 0.049259259259259, "Clock time 1:10:56 to fraction of day"} } local function run_tests() local passed = 0 local total = #tests for i, test in ipairs(tests) do local description = test[3] local actual = test[1]() local expected = test[2] assert_eq(actual, expected, description) print("Test " .. i .. ": " .. description .. " - PASSED") passed = passed + 1 end print("\nPassed " .. passed .. " of " .. total .. " tests.") end run_tests()