Module:Utils: Difference between revisions
Started a (general math) utils module, with log(x, b) and round(x, p) functions so far. Let's hope it works as expected. |
ArrowHead294 (talk | contribs) mNo edit summary |
||
(74 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
-- | local get_args = require("Module:Arguments").getArgs | ||
local yesno = require("Module:Yesno") | |||
return | -- Trim a string (remove leading and trailing, but not interior, whitespace) | ||
function p.trim(s) | |||
return s:match("^%s*(.-)%s*$") | |||
end | |||
-- Wrapper function for template access to [[Module:Yesno]] | |||
function p._yesno(frame) | |||
return yesno(frame.args["input"], frame.args["default"]) | |||
end | |||
-- Check if a table contains x | |||
function p.table_contains(tbl, x) | |||
for i = 1, #tbl do | |||
if x == tbl[i] then | |||
return true | |||
end | |||
end | |||
return false | |||
end | end | ||
-- | -- Return the first index with the given value (or nil if not found) | ||
function p.index_of(array, value) | |||
for i, v in ipairs(array) do | |||
return | if v == value then | ||
return i | |||
end | |||
end | |||
return nil | |||
end | end | ||
return p; | -- Check whether the input is a non-empty string | ||
function p.value_provided(s) | |||
return type(s) == "string" and #s > 0 | |||
end | |||
-- Evaluate input on error use default; cannot be used with {{#invoke:}} | |||
function p.eval_num_arg(input, def_value) | |||
local result = input | |||
if type(input) ~= "number" then | |||
result = def_value | |||
if type(input) == "string" then | |||
-- Check for fraction notation | |||
if input:match("/") == "/" then | |||
local numerator, denominator = input:match("^%s*([0-9]+)[/?]([0-9]+)%s*$") | |||
result = (tonumber(numerator) or def_value) / (tonumber(denominator) or 1) | |||
else | |||
result = tonumber(input) | |||
end | |||
end | |||
end | |||
return result | |||
end | |||
-- Return logarithm base b of x | |||
function p.log(frame) | |||
local args = get_args(frame) | |||
return p._log(args[1], args[2]) | |||
end | |||
local LN_2 = math.log(2) | |||
-- Return logarithm base 2 of x | |||
function p.log2(x) | |||
return math.log(x) / LN_2 | |||
end | |||
function p._log(x, b) | |||
-- x defaults to 0 | |||
x = p.eval_num_arg(x, 0) | |||
-- b defaults to 2 ("octave") | |||
b = p.eval_num_arg(b, 2) | |||
return math.log(x) / math.log(b) | |||
end | |||
-- Return greatest common divisor of a and b | |||
function p.gcd(frame) | |||
local args = get_args(frame) | |||
return p._gcd(args[1], args[2]) | |||
end | |||
function p._gcd(a, b) | |||
if b ~= 0 then | |||
return p._gcd(b, a % b) | |||
else | |||
return math.abs(a) | |||
end | |||
end | |||
-- Return x rounded to places decimal places | |||
function p.round_dec(frame) | |||
local args = get_args(frame) | |||
return p._round_dec(args[1], args[2]) | |||
end | |||
function p._round_dec(x, places) | |||
-- x defaults to 0 | |||
x = p.eval_num_arg(x, 0) | |||
-- places defaults to 0 | |||
places = p.eval_num_arg(places, 0) | |||
return math.floor(x * 10 ^ places + 0.5) / 10 ^ places | |||
end | |||
-- Return x rounded to a precision of prec significant figures | |||
function p.round(frame) | |||
local args = get_args(frame) | |||
return p._round(args[1], args[2]) | |||
end | |||
function p._round(x, prec) | |||
-- x defaults to 0 | |||
x = p.eval_num_arg(x, 0) | |||
-- prec defaults to 6 | |||
prec = p.eval_num_arg(prec, 6) | |||
if x == 0 then | |||
return 0 | |||
else | |||
return p._round_dec(x, prec - math.floor(p._log(math.abs(x), 10)) - 1) | |||
end | |||
end | |||
-- Cached list of primes for is_prime | |||
local primes_cache = { | |||
[0] = false, | |||
[1] = false, | |||
} | |||
-- Returns true if integer n is prime; cannot be used with {{#invoke:}} | |||
function p.is_prime(n) | |||
local cached = primes_cache[n] | |||
if cached ~= nil then | |||
return cached | |||
end | |||
for i = 2, math.sqrt(n) do | |||
if n % i == 0 then | |||
primes_cache[n] = false | |||
return false | |||
end | |||
end | |||
primes_cache[n] = true | |||
return true | |||
end | |||
-- Returns prime factorization of integer n > 1; cannot be used with {{#invoke:}} | |||
-- Note: the order of keys is not specified for Lua tables | |||
function p.prime_factorization_raw(n) | |||
local factors = {} | |||
local m = n | |||
for i = 2, math.sqrt(n) + 1 do | |||
while m % i == 0 do | |||
factors[i] = factors[i] or 0 | |||
factors[i] = factors[i] + 1 | |||
m = m / i | |||
end | |||
if m == 1 then | |||
break | |||
end | |||
end | |||
if m > 1 then | |||
factors[m] = factors[m] or 1 | |||
end | |||
return factors | |||
end | |||
-- Returns prime factorization of integer n > 2 (with wiki markup for exponents) | |||
function p.prime_factorization(frame) | |||
local args = get_args(frame) | |||
return p._prime_factorization(p.eval_num_arg(args[1], 12)) -- default to 12 | |||
end | |||
function p._prime_factorization(n) | |||
if n <= 1 then | |||
return "n/a" | |||
end | |||
local factors, powers = {}, {} | |||
local new_number = n | |||
for i = 2, n do | |||
if p.is_prime(i) then | |||
if new_number % i == 0 then | |||
factors[#factors + 1] = i | |||
powers[#factors] = 0 | |||
while new_number % i == 0 do | |||
powers[#factors] = powers[#factors] + 1 | |||
new_number = new_number / i | |||
end | |||
if powers[#factors] > 1 then | |||
powers[#factors] = factors[#factors] .. "<sup>" .. powers[#factors] .. "</sup>" | |||
else | |||
powers[#factors] = factors[#factors] | |||
end | |||
end | |||
end | |||
if new_number == 1 then | |||
break | |||
end | |||
end | |||
return table.concat(powers, " × ") | |||
end | |||
-- Returns signum(x); cannot be used with {{#invoke:}} | |||
function p.signum(x) | |||
if type(x) ~= "number" then | |||
return 0 | |||
end | |||
if x > 0 then | |||
return 1 | |||
end | |||
if x < 0 then | |||
return -1 | |||
end | |||
return 0 | |||
end | |||
-- Returns the next Young diagram of the same size or nil; cannot be used with {{#invoke:}} | |||
-- Modifies the input table | |||
function p.next_young_diagram(d) | |||
if #d == 0 then | |||
return nil | |||
end | |||
local i_from = nil | |||
local size = 0 | |||
for i = #d, 1, -1 do | |||
if d[i] > 1 then | |||
i_from = i | |||
break | |||
end | |||
size = size + d[i] | |||
end | |||
if i_from == nil then | |||
return nil | |||
end | |||
d[i_from] = d[i_from] - 1 | |||
size = size + 1 | |||
-- repacking the tail | |||
local max_d = d[i_from] | |||
for i = i_from + 1, #d + 1 do | |||
if size >= max_d then | |||
d[i] = max_d | |||
size = size - max_d | |||
elseif size > 0 then | |||
d[i] = size | |||
size = 0 | |||
else | |||
d[i] = nil | |||
end | |||
end | |||
return d | |||
end | |||
-- stylua: ignore | |||
p.primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, | |||
101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, | |||
211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271} | |||
return p |