Module:Rational: Difference between revisions
merge changes from dev |
ArrowHead294 (talk | contribs) mNo edit summary |
||
(12 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
local p = {} | |||
local seq = require("Module:Sequence") | local seq = require("Module:Sequence") | ||
local utils = require("Module:Utils") | local utils = require("Module:Utils") | ||
-- | -- enter a numerator n and denominator m | ||
-- returns a table of prime factors | |||
-- similar to a monzo, but the indices are prime numbers. | |||
function p.new(n, m) | function p.new(n, m) | ||
m = m or 1 | m = m or 1 | ||
Line 14: | Line 17: | ||
end | end | ||
local sign = utils.signum(n) * utils.signum(m) | local sign = utils.signum(n) * utils.signum(m) | ||
-- ensure n and m are positive | |||
n = n * utils.signum(n) | n = n * utils.signum(n) | ||
m = m * utils.signum(m) | m = m * utils.signum(m) | ||
-- factorize n and m separately | |||
local n_factors = utils.prime_factorization_raw(n) | local n_factors = utils.prime_factorization_raw(n) | ||
local m_factors = utils.prime_factorization_raw(m) | local m_factors = utils.prime_factorization_raw(m) | ||
local factors = n_factors | local factors = n_factors | ||
factors.sign = sign | factors.sign = sign | ||
-- subtract the factors of m from the factors of n | |||
for factor, power in pairs(m_factors) do | for factor, power in pairs(m_factors) do | ||
factors[factor] = factors[factor] or 0 | factors[factor] = factors[factor] or 0 | ||
factors[factor] = factors[factor] - power | factors[factor] = factors[factor] - power | ||
if factors[factor] == 0 then | if factors[factor] == 0 then | ||
factors[factor] = nil | factors[factor] = nil -- clear the zeros | ||
end | end | ||
end | end | ||
Line 327: | Line 333: | ||
-- compute a canonical representation of `a` modulo powers of `b` | -- compute a canonical representation of `a` modulo powers of `b` | ||
-- TODO: describe the exact behavior | |||
-- it seems bugged when the equave is a fraction | |||
function p.modulo_mul(a, b) | function p.modulo_mul(a, b) | ||
if type(a) == "number" then | if type(a) == "number" then | ||
Line 547: | Line 555: | ||
end | end | ||
-- determine whether a rational number represents a harmonic | -- determine whether a rational number represents a harmonic. | ||
-- reduced: check for reduced harmonic instead. | |||
function p.is_harmonic(a, reduced, large) | function p.is_harmonic(a, reduced, large) | ||
if type(a) == "number" then | if type(a) == "number" then | ||
Line 557: | Line 566: | ||
for factor, power in pairs(a) do | for factor, power in pairs(a) do | ||
if type(factor) == "number" then | if type(factor) == "number" then | ||
if power < 0 then | if factor == 2 and reduced then | ||
-- pass (ignore factors of 2 for reduced harmonic check) | |||
elseif power < 0 then | |||
return false | return false | ||
end | end | ||
Line 568: | Line 579: | ||
end | end | ||
-- determine whether a rational number represents a subharmonic | -- determine whether a rational number represents a subharmonic. | ||
-- reduced: check for reduced subharmonic instead. | |||
function p.is_subharmonic(a, reduced, large) | function p.is_subharmonic(a, reduced, large) | ||
if type(a) == "number" then | if type(a) == "number" then | ||
Line 578: | Line 590: | ||
for factor, power in pairs(a) do | for factor, power in pairs(a) do | ||
if type(factor) == "number" then | if type(factor) == "number" then | ||
if power > 0 then | if factor == 2 and reduced then | ||
-- pass (ignore factors of 2 for reduced subharmonic check) | |||
elseif power > 0 then | |||
return false | return false | ||
end | end | ||
Line 648: | Line 662: | ||
local den = p.mul(p.add(k, 1), p.sub(k, 1)) | local den = p.mul(p.add(k, 1), p.sub(k, 1)) | ||
return p.eq(a, p.div(p.pow(k, 2), den)) | return p.eq(a, p.div(p.pow(k, 2), den)) | ||
end | |||
-- check if an integer is prime | |||
function p.is_prime(a) | |||
if type(a) == "number" then | |||
a = p.new(a) | |||
end | |||
-- nan, inf, zero, and negative numbers are not prime | |||
if a.nan or a.inf or a.zero or a.sign < 0 then | |||
return false | |||
end | |||
local flag = false -- flag for having exactly one prime factor | |||
for factor, power in pairs(a) do | |||
if type(factor) == "number" and power then | |||
if flag or power ~= 1 then | |||
return false | |||
else | |||
flag = true | |||
end | |||
end | |||
end | |||
return flag | |||
end | end | ||
Line 655: | Line 693: | ||
a = p.new(a) | a = p.new(a) | ||
end | end | ||
-- nan, inf, zero, and negative numbers are not highly composite | |||
if a.nan or a.inf or a.zero or a.sign == -1 then | |||
-- negative numbers are not highly composite | |||
if a.sign == -1 then | |||
return false | return false | ||
end | end | ||
-- non-integers are not highly composite | -- non-integers are not highly composite | ||
for factor, power in pairs(a) do | for factor, power in pairs(a) do | ||
Line 670: | Line 707: | ||
end | end | ||
end | end | ||
local last_power = 1 / 0 | local last_power = 1 / 0 | ||
local max_prime = p.max_prime(a) | local max_prime = p.max_prime(a) | ||
Line 858: | Line 896: | ||
end | end | ||
-- | -- Check if ratio is within an int limit; that is, neither its numerator nor | ||
-- (a. | -- denominator exceed that limit. | ||
function p. | function p.is_within_int_limit(a, lim) | ||
return p.int_limit(a) <= lim | |||
end | |||
-- Find integer limit of a ratio | |||
-- For a ratio p/q, this is simply max(p, q) | |||
function p.int_limit(a) | |||
if type(a) == "number" then | if type(a) == "number" then | ||
a = p.new(a) | a = p.new(a) | ||
Line 867: | Line 911: | ||
return nil | return nil | ||
end | end | ||
local | local a_copy = p.copy(a) | ||
local num, den = p.as_pair(a_copy) | |||
return math.max(num, den) | |||
return | |||
end | end | ||
Line 893: | Line 931: | ||
local num, den = p.as_pair(a_copy) | local num, den = p.as_pair(a_copy) | ||
return math.max(num, den) | return math.max(num, den) | ||
end | |||
-- find max prime involved in the factorisation | |||
-- (a.k.a. prime limit or harmonic class) of a rational number | |||
function p.max_prime(a) | |||
if type(a) == "number" then | |||
a = p.new(a) | |||
end | |||
if a.nan or a.inf or a.zero then | |||
return nil | |||
end | |||
local max_factor = 0 | |||
for factor, _ in pairs(a) do | |||
if type(factor) == "number" then | |||
if factor > max_factor then | |||
max_factor = factor | |||
end | |||
end | |||
end | |||
return max_factor | |||
end | end | ||
Line 1,366: | Line 1,424: | ||
end | end | ||
-- return a rational number in | -- return a string of a rational number in monzo notation | ||
-- | -- calling Template: Monzo | ||
function p.as_ket(a, frame, skip_many_zeros, only_numbers) | function p.as_ket(a, frame, skip_many_zeros, only_numbers) | ||
if skip_many_zeros == nil then | if skip_many_zeros == nil then | ||
Line 1,376: | Line 1,434: | ||
a = p.new(a) | a = p.new(a) | ||
end | end | ||
-- special | |||
if a.nan then | -- special cases | ||
return " | if a.nan or a.inf or a.zero or a.sign < 0 then | ||
return "n/a" | |||
end | end | ||
-- | |||
-- regular case: positive finite ratio | |||
local s = "" | |||
-- preparing the argument | -- preparing the argument | ||
local max_prime = p.max_prime(a) | local max_prime = p.max_prime(a) | ||
Line 1,490: | Line 1,535: | ||
function p.ket(frame) | function p.ket(frame) | ||
local unparsed = frame.args[1] or "1" | local unparsed = frame.args[1] or "1" | ||
local result = "" | |||
local a = p.parse(unparsed) | local a = p.parse(unparsed) | ||
if a == nil then | if a == nil then | ||
result = '{{error|Invalid rational number: ' .. unparsed .. ".}}" | |||
else | |||
result = p.as_ket(a, frame) | |||
end | end | ||
return | |||
return frame:preprocess(result) | |||
end | end | ||
p.monzo = p.ket | p.monzo = p.ket | ||
return p | return p |