Module:Utils: Difference between revisions
Jump to navigation
Jump to search
In prime_factorization: evaluate the input at the public level |
merge changes from dev |
||
Line 1: | Line 1: | ||
local | local get_args = require("Module:Arguments").getArgs | ||
local p = {} | local p = {} | ||
-- check if a table contains x | -- check if a table contains x | ||
function p.table_contains(tbl, 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 | ||
Line 25: | Line 25: | ||
function p.eval_num_arg(input, def_value) | function p.eval_num_arg(input, def_value) | ||
local result = input | local result = input | ||
if type(input) ~= | if type(input) ~= "number" then | ||
result = def_value | result = def_value | ||
if type(input) == | if type(input) == "string" then | ||
-- check for fraction notation | -- check for fraction notation | ||
if input:match( | if input:match("/") == "/" then | ||
local | local numerator, denominator = input:match("^%s*([0-9]+)[/?]([0-9]+)%s*$") | ||
result = (tonumber(numerator) or def_value) / (tonumber(denominator) or 1) | |||
result = (tonumber( | |||
else | else | ||
input = input:match("^%s*(.-)%s*$") | input = input:match("^%s*(.-)%s*$") | ||
Line 44: | Line 43: | ||
-- return logarithm base b of x | -- return logarithm base b of x | ||
function p.log(frame) | function p.log(frame) | ||
local args = | local args = get_args(frame) | ||
return p._log(args[1], args[2]) | return p._log(args[1], args[2]) | ||
end | 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) | function p._log(x, b) | ||
Line 53: | Line 58: | ||
-- b defaults to 2 ("octave") | -- b defaults to 2 ("octave") | ||
b = p.eval_num_arg(b, 2) | b = p.eval_num_arg(b, 2) | ||
return math.log(x)/math.log(b) | return math.log(x) / math.log(b) | ||
end | end | ||
-- return greatest common divisor of a and b | -- return greatest common divisor of a and b | ||
function p.gcd(frame) | function p.gcd(frame) | ||
local args = | local args = get_args(frame) | ||
return p._gcd(args[1], args[2]) | return p._gcd(args[1], args[2]) | ||
end | end | ||
Line 66: | Line 71: | ||
return p._gcd(b, a % b) | return p._gcd(b, a % b) | ||
else | else | ||
return math.abs (a) | return math.abs(a) | ||
end | end | ||
end | end | ||
Line 72: | Line 77: | ||
-- return x rounded to places decimal places | -- return x rounded to places decimal places | ||
function p.round_dec(frame) | function p.round_dec(frame) | ||
local args = | local args = get_args(frame) | ||
return p._round_dec(args[1], args[2]) | return p._round_dec(args[1], args[2]) | ||
end | end | ||
Line 81: | Line 86: | ||
-- places defaults to 0 | -- places defaults to 0 | ||
places = p.eval_num_arg(places, 0) | places = p.eval_num_arg(places, 0) | ||
return math.floor (x * 10^places + 0.5)/10^places | return math.floor(x * 10 ^ places + 0.5) / 10 ^ places | ||
end | end | ||
-- return x rounded to a precision of prec significant figures | -- return x rounded to a precision of prec significant figures | ||
function p.round(frame) | function p.round(frame) | ||
local args = | local args = get_args(frame) | ||
return p._round(args[1], args[2]) | return p._round(args[1], args[2]) | ||
end | end | ||
function p._round(x, prec) | function p._round(x, prec) | ||
Line 103: | Line 108: | ||
-- cached list of primes for is_prime | -- cached list of primes for is_prime | ||
local | local primes_cache = { | ||
[0] = false, | [0] = false, | ||
[1] = false | [1] = false, | ||
} | } | ||
-- returns true if integer n is prime; cannot be used with {{#invoke:}} | -- returns true if integer n is prime; cannot be used with {{#invoke:}} | ||
function p.is_prime(n) | function p.is_prime(n) | ||
local cached = | local cached = primes_cache[n] | ||
if cached ~= nil then | if cached ~= nil then | ||
return cached | return cached | ||
Line 116: | Line 121: | ||
for i = 2, math.sqrt(n) do | for i = 2, math.sqrt(n) do | ||
if n % i == 0 then | if n % i == 0 then | ||
primes_cache[n] = false | |||
return false | return false | ||
end | end | ||
end | end | ||
primes_cache[n] = true | |||
return true | return true | ||
end | end | ||
Line 147: | Line 152: | ||
-- returns prime factorization of integer n > 2 (with wiki markup for exponents) | -- returns prime factorization of integer n > 2 (with wiki markup for exponents) | ||
function p.prime_factorization(frame) | function p.prime_factorization(frame) | ||
local args = | local args = get_args(frame) | ||
return p._prime_factorization(p.eval_num_arg(args[1], 12)) -- default to 12 | return p._prime_factorization(p.eval_num_arg(args[1], 12)) -- default to 12 | ||
end | end | ||
Line 162: | Line 167: | ||
factors[#factors + 1] = i | factors[#factors + 1] = i | ||
powers[#factors] = 0 | powers[#factors] = 0 | ||
while new_number % i == 0 do | while new_number % i == 0 do | ||
powers[#factors] = powers[#factors] + 1 | powers[#factors] = powers[#factors] + 1 | ||
new_number = new_number / i | new_number = new_number / i | ||
Line 182: | Line 187: | ||
-- returns signum(x); cannot be used with {{#invoke:}} | -- returns signum(x); cannot be used with {{#invoke:}} | ||
function p.signum(x) | function p.signum(x) | ||
if type(x) ~= | if type(x) ~= "number" then | ||
return 0 | return 0 | ||
end | end | ||
if x > 0 then return 1 end | if x > 0 then | ||
if x < 0 then return -1 end | return 1 | ||
end | |||
if x < 0 then | |||
return -1 | |||
end | |||
return 0 | return 0 | ||
end | end | ||
Line 225: | Line 234: | ||
return d | return d | ||
end | 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} | |||
-- get monzo of n/d | -- get monzo of n/d | ||
-- e.g. for 3/2: {[2] = -1, [3] = 1} | -- e.g. for 3/2: {[2] = -1, [3] = 1} | ||
function p.get_monzo(n, d) | function p.get_monzo(n, d) | ||
local n_pf = p.prime_factorization_raw(n) | local n_pf = p.prime_factorization_raw(n) | ||
local d_pf = p.prime_factorization_raw(d) | local d_pf = p.prime_factorization_raw(d) | ||
local result = {} | local result = {} | ||
for i=1,#primes do | for i = 1, #p.primes do | ||
local t = (n_pf[primes[i]] or 0) - (d_pf[primes[i]] or 0) | local t = (n_pf[p.primes[i]] or 0) - (d_pf[p.primes[i]] or 0) | ||
if t ~= 0 then | if t ~= 0 then | ||
result[primes[i]] = t | result[p.primes[i]] = t | ||
end | end | ||
end | end |
Revision as of 20:14, 1 April 2024
Lua error in Module:Variable_arguments at line 63: attempt to call field 'trim' (a nil value).
This module provides several mathematical functions which are likely to be used frequently on the Xenharmonic Wiki.
Namely, the functions in this module can be called from other modules by using require("Module:Utils")
and calling the underscore-prefixed functions.
Functions
trim(s)
- Removes leading and trailing whitespaces (but not interior ones) from a string.
_yesno(frame)
- Allows Module:Yesno, which is not invokable directly, to be accessed by templates through Template:Yesno.
table_contains(tbl, x)
*- Check if table contains x.
index_of(array, index)
*- Return the first index with the given value (or nil if not found).
value_provided(s)
*- Checks if
s
is a non-empty string.
wlink(a, b)
- Provides a link to Wikipedia.
eval_num_arg(input, def_value)
*- Checks if
input
is a number; on error, usedef_value
.
log(x, b)
- Returns the logarithm base
b
ofx
. Parameterb
defaults to base 2 (octave) if it is omitted.
gcd(a, b)
- Returns the greatest common divisor of
a
andb
.
round_dec(x, places)
- Returns
x
rounded to a precision ofplaces
decimal places. Parameterplaces
defaults to 0 if it is omitted.
round(x, prec)
- Returns
x
rounded to a precision ofprec
significant figures. Parameterprec
defaults to 6 if it is omitted.
is_prime(n)
*- Returns
true
if the given integern
is a prime number.
prime_factorization(n)
- Returns the prime factorization of the given integer
n
using the exponential form (in wikitext).
prime_factorization_raw(n)
*- Returns a table encoding the prime factorization of
n
.
signum(x)
*- Returns 1 for positive numbers, −1 for negative ones, and 0 for zero and non-integer inputs.
next_young_diagram(d)
- Returns the next Young diagram of the same size; the first one is
[N]
, the last one isLua error in Module:Variable_arguments at line 93: attempt to call field 'trim' (a nil value).
. After the last one,nil
is returned. The input table is modified.
* These functions are designed to be used by other modules only; they cannot be called with {{#invoke: }}
.
local get_args = require("Module:Arguments").getArgs
local p = {}
-- 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
-- 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
if v == value then
return i
end
end
return nil
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
input = input:match("^%s*(.-)%s*$")
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}
-- get monzo of n/d
-- e.g. for 3/2: {[2] = -1, [3] = 1}
function p.get_monzo(n, d)
local n_pf = p.prime_factorization_raw(n)
local d_pf = p.prime_factorization_raw(d)
local result = {}
for i = 1, #p.primes do
local t = (n_pf[p.primes[i]] or 0) - (d_pf[p.primes[i]] or 0)
if t ~= 0 then
result[p.primes[i]] = t
end
end
return result
end
return p