modlib/math.lua

127 lines
3.1 KiB
Lua
Raw Normal View History

-- Localize globals
local math, math_floor, minetest, modlib_table_reverse, os, string_char, setmetatable, table_insert, table_concat
= math, math.floor, minetest, modlib.table.reverse, os, string.char, setmetatable, table.insert, table.concat
local inf = math.huge
2021-06-17 19:45:08 +02:00
-- Set environment
local _ENV = {}
setfenv(1, _ENV)
2021-12-19 14:59:05 +01:00
-- TODO might be too invasive
2020-04-21 15:04:07 +02:00
-- Make random random
2021-03-04 12:18:26 +01:00
math.randomseed(minetest and minetest.get_us_time() or os.time() + os.clock())
2020-12-19 14:41:03 +01:00
for _ = 1, 100 do math.random() end
negative_nan = 0/0
positive_nan = negative_nan ^ 1
2021-12-19 14:59:05 +01:00
function sign(number)
if number ~= number then return number end -- nan
if number == 0 then return 0 end
if number < 0 then return -1 end
if number > 0 then return 1 end
end
2022-01-17 14:16:42 +01:00
log = setmetatable({}, {
__index = function(self, base)
local div = math.log(base)
local function base_log(number)
return math.log(number) / div
end
self[base] = base_log
return base_log
end,
__call = function(_, number, base)
if not base then
return math.log(number)
end
return math.log(number) / math.log(base)
2022-01-17 11:58:16 +01:00
end
2022-01-17 14:16:42 +01:00
})
2022-01-17 11:58:16 +01:00
2022-01-07 18:31:15 +01:00
-- one-based mod
function onemod(number, modulus)
return ((number - 1) % modulus) + 1
end
2020-12-19 14:41:03 +01:00
function round(number, steps)
steps = steps or 1
2021-08-08 23:29:43 +02:00
return math_floor(number * steps + 0.5) / steps
2020-02-09 01:39:54 +01:00
end
2020-12-19 14:41:03 +01:00
2020-03-23 20:20:43 +01:00
local c0 = ("0"):byte()
local cA = ("A"):byte()
2020-12-19 14:41:03 +01:00
2020-03-23 20:20:43 +01:00
function default_digit_function(digit)
2021-08-08 23:29:43 +02:00
if digit <= 9 then return string_char(c0 + digit) end
return string_char(cA + digit - 10)
2020-03-23 20:20:43 +01:00
end
2020-12-19 14:41:03 +01:00
2020-03-23 20:20:43 +01:00
default_precision = 10
2020-12-19 14:41:03 +01:00
-- See https://github.com/appgurueu/Luon/blob/master/index.js#L724
2020-03-23 20:20:43 +01:00
function tostring(number, base, digit_function, precision)
if number ~= number then
return "nan"
end
if number == inf then
return "inf"
end
if number == -inf then
return "-inf"
end
2020-12-19 14:41:03 +01:00
digit_function = digit_function or default_digit_function
precision = precision or default_precision
local out = {}
if number < 0 then
2021-08-08 23:29:43 +02:00
table_insert(out, "-")
2020-12-19 14:41:03 +01:00
number = -number
end
2021-08-08 23:29:43 +02:00
-- Rounding
2020-12-19 14:41:03 +01:00
number = number + base ^ -precision / 2
local digit
while number >= base do
2021-08-08 23:29:43 +02:00
digit = math_floor(number % base)
table_insert(out, digit_function(digit))
2021-08-08 22:37:47 +02:00
number = (number - digit) / base
2020-12-19 14:41:03 +01:00
end
2021-08-08 23:29:43 +02:00
digit = math_floor(number)
table_insert(out, digit_function(digit))
modlib_table_reverse(out)
2020-12-19 14:41:03 +01:00
number = number % 1
if number ~= 0 and number >= base ^ -precision then
2021-08-08 23:29:43 +02:00
table_insert(out, ".")
2021-08-08 22:37:47 +02:00
while precision >= 0 and number >= base ^ -precision do
2020-12-19 14:41:03 +01:00
number = number * base
2021-08-08 23:29:43 +02:00
digit = math_floor(number % base)
table_insert(out, digit_function(digit))
2020-12-19 14:41:03 +01:00
number = number - digit
precision = precision - 1
end
end
2021-08-08 23:29:43 +02:00
return table_concat(out)
2021-03-04 12:19:08 +01:00
end
-- See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/fround#polyfill
function fround(number)
if number == 0 or number ~= number then
return number
end
local sign = 1
if number < 0 then
sign = -1
number = -number
end
2021-08-08 23:29:43 +02:00
local exp = math_floor(math.log(number, 2))
2021-03-30 18:06:58 +02:00
local powexp = 2 ^ math.max(-126, math.min(exp, 127))
2021-03-04 12:19:08 +01:00
local leading = exp < -127 and 0 or 1
2021-08-08 23:29:43 +02:00
local mantissa = math_floor((leading - number / powexp) * 0x800000 + 0.5)
2021-03-04 12:19:08 +01:00
if mantissa <= -0x800000 then
return sign * inf
2021-03-04 12:19:08 +01:00
end
2021-03-30 18:06:58 +02:00
return sign * powexp * (leading - mantissa / 0x800000)
2021-06-17 19:45:08 +02:00
end
-- Export environment
return _ENV