<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
	<id>https://ja.xen.wiki/index.php?action=history&amp;feed=atom&amp;title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%3ARational</id>
	<title>モジュール:Rational - 版の履歴</title>
	<link rel="self" type="application/atom+xml" href="https://ja.xen.wiki/index.php?action=history&amp;feed=atom&amp;title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%3ARational"/>
	<link rel="alternate" type="text/html" href="https://ja.xen.wiki/index.php?title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB:Rational&amp;action=history"/>
	<updated>2026-07-09T15:40:34Z</updated>
	<subtitle>このウィキのこのページに関する変更履歴</subtitle>
	<generator>MediaWiki 1.43.6</generator>
	<entry>
		<id>https://ja.xen.wiki/index.php?title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB:Rational&amp;diff=1300&amp;oldid=prev</id>
		<title>Dummy index: 最新版をコピー</title>
		<link rel="alternate" type="text/html" href="https://ja.xen.wiki/index.php?title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB:Rational&amp;diff=1300&amp;oldid=prev"/>
		<updated>2025-11-16T05:42:13Z</updated>

		<summary type="html">&lt;p&gt;最新版をコピー&lt;/p&gt;
&lt;a href=&quot;https://ja.xen.wiki/index.php?title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB:Rational&amp;amp;diff=1300&amp;amp;oldid=151&quot;&gt;差分を表示&lt;/a&gt;</summary>
		<author><name>Dummy index</name></author>
	</entry>
	<entry>
		<id>https://ja.xen.wiki/index.php?title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB:Rational&amp;diff=151&amp;oldid=prev</id>
		<title>R-4981: ページの作成:「local seq = require(&quot;Module:Sequence&quot;) local utils = require(&quot;Module:Utils&quot;) local p = {}  -- enter a numerator n and denominator m -- returns a table of prime factors --…」</title>
		<link rel="alternate" type="text/html" href="https://ja.xen.wiki/index.php?title=%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB:Rational&amp;diff=151&amp;oldid=prev"/>
		<updated>2024-07-04T01:14:31Z</updated>

		<summary type="html">&lt;p&gt;ページの作成:「local seq = require(&amp;quot;Module:Sequence&amp;quot;) local utils = require(&amp;quot;Module:Utils&amp;quot;) local p = {}  -- enter a numerator n and denominator m -- returns a table of prime factors --…」&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新規ページ&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local seq = require(&amp;quot;Module:Sequence&amp;quot;)&lt;br /&gt;
local utils = require(&amp;quot;Module:Utils&amp;quot;)&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
-- enter a numerator n and denominator m&lt;br /&gt;
-- returns a table of prime factors&lt;br /&gt;
-- similar to a monzo, but the indices are prime numbers. &lt;br /&gt;
function p.new(n, m)&lt;br /&gt;
	m = m or 1&lt;br /&gt;
	if n == 0 and m == 0 then&lt;br /&gt;
		return { nan = true }&lt;br /&gt;
	elseif n == 0 then&lt;br /&gt;
		return { zero = true, sign = utils.signum(m) }&lt;br /&gt;
	elseif m == 0 then&lt;br /&gt;
		return { inf = true, sign = utils.signum(n) }&lt;br /&gt;
	end&lt;br /&gt;
	local sign = utils.signum(n) * utils.signum(m)&lt;br /&gt;
	-- ensure n and m are positive&lt;br /&gt;
	n = n * utils.signum(n)&lt;br /&gt;
	m = m * utils.signum(m)&lt;br /&gt;
	-- factorize n and m separately&lt;br /&gt;
	local n_factors = utils.prime_factorization_raw(n)&lt;br /&gt;
	local m_factors = utils.prime_factorization_raw(m)&lt;br /&gt;
	local factors = n_factors&lt;br /&gt;
	factors.sign = sign&lt;br /&gt;
	-- subtract the factors of m from the factors of n&lt;br /&gt;
	for factor, power in pairs(m_factors) do&lt;br /&gt;
		factors[factor] = factors[factor] or 0&lt;br /&gt;
		factors[factor] = factors[factor] - power&lt;br /&gt;
		if factors[factor] == 0 then&lt;br /&gt;
			factors[factor] = nil -- clear the zeros&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return factors&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- copy a rational number&lt;br /&gt;
function p.copy(a)&lt;br /&gt;
	local b = {}&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		b[factor] = power&lt;br /&gt;
	end&lt;br /&gt;
	return b&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- create a rational number from continued fraction array&lt;br /&gt;
function p.from_continued_fraction(data)&lt;br /&gt;
	local val = p.new(1, 0)&lt;br /&gt;
	for i = #data, 1, -1 do&lt;br /&gt;
		val = p.add(data[i], p.inv(val))&lt;br /&gt;
	end&lt;br /&gt;
	return val&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- create a rational number from a string of whitespace-separated integers&lt;br /&gt;
function p.from_ket(s)&lt;br /&gt;
	local factor = 1&lt;br /&gt;
	local a = { sign = 1 }&lt;br /&gt;
	for i in s:gmatch(&amp;quot;%S+&amp;quot;) do&lt;br /&gt;
		local power = tonumber(i)&lt;br /&gt;
		if power == nil then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- find the next prime&lt;br /&gt;
		factor = factor + 1&lt;br /&gt;
		while not utils.is_prime(factor) do&lt;br /&gt;
			factor = factor + 1&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		if power ~= 0 then&lt;br /&gt;
			a[factor] = power&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return a&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- list convergents to `x` with a given stop condition&lt;br /&gt;
-- `stop` is either a number or a function of rational numbers&lt;br /&gt;
function p.convergents(x, stop)&lt;br /&gt;
	local convergents = {}&lt;br /&gt;
	local data = {}&lt;br /&gt;
	local i = 0&lt;br /&gt;
	while true do&lt;br /&gt;
		local n = math.floor(x)&lt;br /&gt;
		table.insert(data, n)&lt;br /&gt;
		local frac = p.from_continued_fraction(data)&lt;br /&gt;
		if type(stop) == &amp;quot;function&amp;quot; and stop(frac) then&lt;br /&gt;
			break&lt;br /&gt;
		elseif type(stop) == &amp;quot;number&amp;quot; and i &amp;gt;= stop then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		table.insert(convergents, frac)&lt;br /&gt;
		x = x - n&lt;br /&gt;
		if x == 0 then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		x = 1 / x&lt;br /&gt;
		i = i + 1&lt;br /&gt;
	end&lt;br /&gt;
	return convergents&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is a convergent or a semiconvergent to `x`&lt;br /&gt;
-- TODO: document how this works&lt;br /&gt;
function p.converges(a, x)&lt;br /&gt;
	local _, m_a = p.as_pair(a)&lt;br /&gt;
	local convergents = p.convergents(x, function(b)&lt;br /&gt;
		local _, m_b = p.as_pair(b)&lt;br /&gt;
		return m_b &amp;gt;= m_a * 10000&lt;br /&gt;
	end)&lt;br /&gt;
	for _, b in ipairs(convergents) do&lt;br /&gt;
		if p.eq(a, b) then&lt;br /&gt;
			return &amp;quot;convergent&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for i = 2, #convergents - 1 do&lt;br /&gt;
		local n_delta, m_delta = p.as_pair(convergents[i])&lt;br /&gt;
		local n_c, m_c = p.as_pair(convergents[i - 1])&lt;br /&gt;
		while true do&lt;br /&gt;
			n_c = n_c + n_delta&lt;br /&gt;
			m_c = m_c + m_delta&lt;br /&gt;
			local c = p.new(n_c, m_c)&lt;br /&gt;
			if p.as_table(c)[2] &amp;gt;= p.as_table(convergents[i + 1])[2] then&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			if p.eq(a, c) then&lt;br /&gt;
				return &amp;quot;semiconvergent&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- attempt to identify the ratio as a simple S-expression&lt;br /&gt;
-- returns a table of matched expressions&lt;br /&gt;
function p.find_S_expression(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or a.sign &amp;lt; 0 then&lt;br /&gt;
		return {}&lt;br /&gt;
	end&lt;br /&gt;
	if p.eq(a, 1) then&lt;br /&gt;
		return {}&lt;br /&gt;
	end&lt;br /&gt;
	local max_prime = p.max_prime(a)&lt;br /&gt;
	if seq.square_superparticulars[max_prime] == nil then&lt;br /&gt;
		return {}&lt;br /&gt;
	end&lt;br /&gt;
	local expressions = {}&lt;br /&gt;
	local superparticular_indices = {}&lt;br /&gt;
	local superparticular_ratios = {}&lt;br /&gt;
	for _, k_array in pairs(seq.square_superparticulars) do&lt;br /&gt;
		for _, k in ipairs(k_array) do&lt;br /&gt;
			if k &amp;lt;= 1000 then&lt;br /&gt;
				table.insert(superparticular_indices, k)&lt;br /&gt;
&lt;br /&gt;
				local Sk_num = p.pow(p.new(k), 2)&lt;br /&gt;
				local Sk_den = p.mul(k - 1, k + 1)&lt;br /&gt;
				local Sk = p.div(Sk_num, Sk_den)&lt;br /&gt;
				superparticular_ratios[k] = Sk&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- is it Sk?&lt;br /&gt;
	for _, k in ipairs(superparticular_indices) do&lt;br /&gt;
		if p.eq(a, superparticular_ratios[k]) then&lt;br /&gt;
			table.insert(expressions, &amp;quot;S&amp;quot; .. k)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- is it Sk*S(k+1) or Sk/S(k+1) or Sk^2*S(k+1) or Sk*S(k+1)^2?&lt;br /&gt;
	for _, k in ipairs(superparticular_indices) do&lt;br /&gt;
		local r1 = superparticular_ratios[k]&lt;br /&gt;
		local r2 = superparticular_ratios[k + 1]&lt;br /&gt;
		if r1 and r2 then&lt;br /&gt;
			if p.eq(a, p.mul(r1, r2)) then&lt;br /&gt;
				table.insert(expressions, &amp;quot;S&amp;quot; .. k .. &amp;quot; × S&amp;quot; .. (k + 1))&lt;br /&gt;
			end&lt;br /&gt;
			if p.eq(a, p.div(r1, r2)) then&lt;br /&gt;
				table.insert(expressions, &amp;quot;S&amp;quot; .. k .. &amp;quot; / S&amp;quot; .. (k + 1))&lt;br /&gt;
			end&lt;br /&gt;
			if p.eq(a, p.mul(p.pow(r1, 2), r2)) then&lt;br /&gt;
				table.insert(expressions, &amp;quot;S&amp;quot; .. k .. &amp;quot;&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt; × S&amp;quot; .. (k + 1))&lt;br /&gt;
			end&lt;br /&gt;
			if p.eq(a, p.mul(r1, p.pow(r2, 2))) then&lt;br /&gt;
				table.insert(expressions, &amp;quot;S&amp;quot; .. k .. &amp;quot; * S&amp;quot; .. (k + 1) .. &amp;quot;&amp;lt;sup&amp;gt;2&amp;lt;/sup&amp;gt;&amp;quot;)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- is it Sk/S(k+2)?&lt;br /&gt;
	for _, k in ipairs(superparticular_indices) do&lt;br /&gt;
		local r1 = superparticular_ratios[k]&lt;br /&gt;
		local r2 = superparticular_ratios[k + 2]&lt;br /&gt;
		if r1 and r2 then&lt;br /&gt;
			if p.eq(a, p.div(r1, r2)) then&lt;br /&gt;
				table.insert(expressions, &amp;quot;S&amp;quot; .. k .. &amp;quot; / S&amp;quot; .. (k + 2))&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- is it S(k-1)*Sk*S(k+1)?&lt;br /&gt;
	for _, k in ipairs(superparticular_indices) do&lt;br /&gt;
		local r1 = superparticular_ratios[k - 1]&lt;br /&gt;
		local r2 = superparticular_ratios[k]&lt;br /&gt;
		local r3 = superparticular_ratios[k + 1]&lt;br /&gt;
		if r1 and r2 and r3 then&lt;br /&gt;
			if p.eq(a, p.mul(r1, p.mul(r2, r3))) then&lt;br /&gt;
				table.insert(expressions, &amp;quot;S&amp;quot; .. (k - 1) .. &amp;quot; × S&amp;quot; .. k .. &amp;quot; × S&amp;quot; .. (k + 1))&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return expressions&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- multiply two rational numbers; integers are also allowed&lt;br /&gt;
function p.mul(a, b)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if type(b) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		b = p.new(b)&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: NaN&lt;br /&gt;
	if a.nan or b.nan then&lt;br /&gt;
		return { nan = true }&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: infinities&lt;br /&gt;
	if (a.inf and not b.zero) or (b.inf and not a.zero) then&lt;br /&gt;
		return { inf = true, sign = a.sign * b.sign }&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: infinity * zero&lt;br /&gt;
	if (a.inf and b.zero) or (b.inf and a.zero) then&lt;br /&gt;
		return { nan = true }&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: zeros&lt;br /&gt;
	if a.zero or b.zero then&lt;br /&gt;
		return { zero = true, sign = a.sign * b.sign }&lt;br /&gt;
	end&lt;br /&gt;
	-- regular case: both not NaN, not infinities, not zeros&lt;br /&gt;
	local c = p.copy(a)&lt;br /&gt;
	for factor, power in pairs(b) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			c[factor] = c[factor] or 0&lt;br /&gt;
			c[factor] = c[factor] + power&lt;br /&gt;
			if c[factor] == 0 then&lt;br /&gt;
				c[factor] = nil&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	c.sign = a.sign * b.sign&lt;br /&gt;
	return c&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- compute 1/a for a rational number a; integers are also allowed&lt;br /&gt;
function p.inv(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: NaN&lt;br /&gt;
	if a.nan then&lt;br /&gt;
		return { nan = true }&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: infinity&lt;br /&gt;
	if a.inf then&lt;br /&gt;
		return { zero = true, sign = a.sign }&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: zero&lt;br /&gt;
	if a.zero then&lt;br /&gt;
		return { inf = true, sign = a.sign }&lt;br /&gt;
	end&lt;br /&gt;
	-- regular case: not NaN, not infinity, not zero&lt;br /&gt;
	local b = {}&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			b[factor] = -power&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	b.sign = a.sign&lt;br /&gt;
	return b&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- divide a rational number a by b; integers are also allowed&lt;br /&gt;
function p.div(a, b)&lt;br /&gt;
	return p.mul(a, p.inv(b))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- compute a^b; b must be an integer&lt;br /&gt;
function p.pow(a, b)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if type(b) ~= &amp;quot;number&amp;quot; then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan then&lt;br /&gt;
		return { nan = true }&lt;br /&gt;
	end&lt;br /&gt;
	if a.inf then&lt;br /&gt;
		if b == 0 then&lt;br /&gt;
			return { nan = true }&lt;br /&gt;
		elseif b &amp;gt; 0 then&lt;br /&gt;
			return { inf = true, sign = math.pow(a.sign, b) }&lt;br /&gt;
		else&lt;br /&gt;
			return { zero = true, sign = math.pow(a.sign, b) }&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if a.zero then&lt;br /&gt;
		if b == 0 then&lt;br /&gt;
			return p.new(1)&lt;br /&gt;
		elseif b &amp;gt; 0 then&lt;br /&gt;
			return { zero = true, sign = math.pow(a.sign, b) }&lt;br /&gt;
		else&lt;br /&gt;
			return { inf = true, sign = math.pow(a.sign, b) }&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local c = p.new(1)&lt;br /&gt;
	for _ = 1, math.abs(b) do&lt;br /&gt;
		if b &amp;gt; 0 then&lt;br /&gt;
			c = p.mul(c, a)&lt;br /&gt;
		else&lt;br /&gt;
			c = p.div(c, a)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return c&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- compute a canonical representation of `a` modulo powers of `b`&lt;br /&gt;
function p.modulo_mul(a, b)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if type(b) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		b = p.new(b)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or b.nan or a.inf or b.inf or a.zero or b.zero then&lt;br /&gt;
		return p.copy(a)&lt;br /&gt;
	end&lt;br /&gt;
	local neg_power = -math.huge&lt;br /&gt;
	local pos_power = math.huge&lt;br /&gt;
	for factor, power in pairs(b) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if (power &amp;gt; 0 and (a[factor] or 0) &amp;gt;= 0) or (power &amp;lt; 0 and (a[factor] or 0) &amp;lt;= 0) then&lt;br /&gt;
				pos_power = math.min(pos_power, math.floor((a[factor] or 0) / power))&lt;br /&gt;
			else&lt;br /&gt;
				neg_power = math.max(neg_power, -math.ceil(math.abs(a[factor] or 0) / math.abs(power)))&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local power = 0&lt;br /&gt;
	if neg_power ~= neg_power + 1 and neg_power &amp;lt; 0 then&lt;br /&gt;
		power = neg_power&lt;br /&gt;
	end&lt;br /&gt;
	if pos_power ~= pos_power + 1 and pos_power &amp;gt; 0 then&lt;br /&gt;
		power = pos_power&lt;br /&gt;
	end&lt;br /&gt;
	return p.div(a, p.pow(b, power))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- add two rational numbers; integers are also allowed&lt;br /&gt;
function p.add(a, b)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if type(b) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		b = p.new(b)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- special case: NaN&lt;br /&gt;
	if a.nan or b.nan then&lt;br /&gt;
		return { nan = true }&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: infinities&lt;br /&gt;
	if a.inf and b.inf then&lt;br /&gt;
		if a.sign == b.sign then&lt;br /&gt;
			return { inf = true, sign = a.sign }&lt;br /&gt;
		else&lt;br /&gt;
			return { nan = true }&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if a.inf then&lt;br /&gt;
		return { inf = true, sign = a.sign }&lt;br /&gt;
	end&lt;br /&gt;
	if b.inf then&lt;br /&gt;
		return { inf = true, sign = b.sign }&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: one is zero&lt;br /&gt;
	if a.zero then&lt;br /&gt;
		return p.copy(b)&lt;br /&gt;
	end&lt;br /&gt;
	if b.zero then&lt;br /&gt;
		return p.copy(a)&lt;br /&gt;
	end&lt;br /&gt;
	-- regular case: both not NaN, not infinities, not zeros&lt;br /&gt;
	local gcd = { sign = 1 }&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if math.min(power, b[factor] or 0) &amp;gt; 0 then&lt;br /&gt;
				gcd[factor] = math.min(power, b[factor])&lt;br /&gt;
			end&lt;br /&gt;
			if math.max(power, b[factor] or 0) &amp;lt; 0 then&lt;br /&gt;
				gcd[factor] = math.max(power, b[factor])&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	a = p.div(a, gcd)&lt;br /&gt;
	b = p.div(b, gcd)&lt;br /&gt;
&lt;br /&gt;
	local n_a, m_a = p.as_pair(a)&lt;br /&gt;
	local n_b, m_b = p.as_pair(b)&lt;br /&gt;
&lt;br /&gt;
	local n = n_a * m_b + n_b * m_a&lt;br /&gt;
	local m = m_a * m_b&lt;br /&gt;
&lt;br /&gt;
	return p.mul(p.new(n, m), gcd)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- substract a rational number from another; integers are also allowed&lt;br /&gt;
function p.sub(a, b)&lt;br /&gt;
	return p.add(a, p.mul(b, -1))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- absolute value of a rational number; integers are also allowed&lt;br /&gt;
function p.abs(a)&lt;br /&gt;
	if a.nan then&lt;br /&gt;
		return { nan = true }&lt;br /&gt;
	end&lt;br /&gt;
	local b = p.copy(a)&lt;br /&gt;
	b.sign = 1&lt;br /&gt;
	return b&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is less than another; integers are also allowed&lt;br /&gt;
function p.lt(a, b)&lt;br /&gt;
	local c = p.sub(a, b)&lt;br /&gt;
	if c.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	else&lt;br /&gt;
		return c.sign == -1&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is less or equal to the other; integers are also allowed&lt;br /&gt;
function p.leq(a, b)&lt;br /&gt;
	local c = p.sub(a, b)&lt;br /&gt;
	if c.zero then&lt;br /&gt;
		return true&lt;br /&gt;
	else&lt;br /&gt;
		return c.sign == -1&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is greater than another; integers are also allowed&lt;br /&gt;
function p.gt(a, b)&lt;br /&gt;
	local c = p.sub(a, b)&lt;br /&gt;
	if c.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	else&lt;br /&gt;
		return c.sign == 1&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is greater or equal to the other; integers are also allowed&lt;br /&gt;
function p.geq(a, b)&lt;br /&gt;
	local c = p.sub(a, b)&lt;br /&gt;
	if c.zero then&lt;br /&gt;
		return true&lt;br /&gt;
	else&lt;br /&gt;
		return c.sign == 1&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is equal to another; integers are also allowed&lt;br /&gt;
function p.eq(a, b)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if type(b) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		b = p.new(b)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or b.nan then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	if a.inf and b.inf then&lt;br /&gt;
		return a.sign == b.sign&lt;br /&gt;
	end&lt;br /&gt;
	if a.inf or b.inf then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	if a.zero and b.zero then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	if a.zero or b.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if b[factor] ~= power then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	for factor, power in pairs(b) do&lt;br /&gt;
		if a[factor] ~= power then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is integer&lt;br /&gt;
function p.is_int(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	if a.inf then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;lt; 0 then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number lies within [1; equave)&lt;br /&gt;
function p.is_reduced(a, equave, large)&lt;br /&gt;
	equave = equave or 2&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or a.sign &amp;lt; 0 then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	if large then&lt;br /&gt;
		-- an approximation&lt;br /&gt;
		local cents = p.cents(a)&lt;br /&gt;
		local cents_max = p.cents(equave)&lt;br /&gt;
		return cents &amp;gt;= 0 and cents &amp;lt; cents_max&lt;br /&gt;
	else&lt;br /&gt;
		return p.geq(a, 1) and p.lt(a, equave)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number represents a harmonic&lt;br /&gt;
function p.is_harmonic(a, reduced, large)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or a.sign &amp;lt; 0 then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;lt; 0 then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if reduced then&lt;br /&gt;
		return p.is_reduced(a, 2, large)&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number represents a subharmonic&lt;br /&gt;
function p.is_subharmonic(a, reduced, large)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or a.sign &amp;lt; 0 then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;gt; 0 then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if reduced then&lt;br /&gt;
		return p.is_reduced(a, 2, large)&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is an integer power of another rational number&lt;br /&gt;
function p.is_power(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	if p.eq(a, 1) or p.eq(a, -1) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local total_power = nil&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if total_power then&lt;br /&gt;
				total_power = utils._gcd(total_power, math.abs(power))&lt;br /&gt;
			else&lt;br /&gt;
				total_power = math.abs(power)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return total_power &amp;gt; 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is superparticular&lt;br /&gt;
function p.is_superparticular(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	local n, m = p.as_pair(a)&lt;br /&gt;
	return n - m == 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether a rational number is a square superparticular&lt;br /&gt;
function p.is_square_superparticular(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or a.sign &amp;lt; 0 then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	-- check the numerator&lt;br /&gt;
	local k = { sign = 1 }&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;gt; 0 and power % 2 ~= 0 then&lt;br /&gt;
				return false&lt;br /&gt;
			elseif power &amp;gt; 0 then&lt;br /&gt;
				k[factor] = math.floor(power / 2 + 0.5)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- check the denominator&lt;br /&gt;
	local den = p.mul(p.add(k, 1), p.sub(k, 1))&lt;br /&gt;
	return p.eq(a, p.div(p.pow(k, 2), den))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- check if an integer is highly composite&lt;br /&gt;
function p.is_highly_composite(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	-- negative numbers are not highly composite&lt;br /&gt;
	if a.sign == -1 then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	-- non-integers are not highly composite&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;lt; 0 then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local last_power = 1 / 0&lt;br /&gt;
	local max_prime = p.max_prime(a)&lt;br /&gt;
	for i = 2, max_prime do&lt;br /&gt;
		if utils.is_prime(i) then&lt;br /&gt;
			-- factors must be the first N primes&lt;br /&gt;
			if a[i] == nil then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
			-- powers must form a non-increasing sequence&lt;br /&gt;
			if a[i] &amp;gt; last_power then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
			last_power = a[i]&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- last_power may be &amp;gt;1 only for 1, 4, 36&lt;br /&gt;
	if last_power &amp;gt; 1 then&lt;br /&gt;
		return p.eq(a, 1) or p.eq(a, 4) or p.eq(a, 36)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- now we actually check whether it is highly composite&lt;br /&gt;
	local n, _ = p.as_pair(a)&lt;br /&gt;
&lt;br /&gt;
	-- precision is very important here&lt;br /&gt;
	local log2_n = 0&lt;br /&gt;
	local t = 1&lt;br /&gt;
	while t * 2 &amp;lt;= n do&lt;br /&gt;
		log2_n = log2_n + 1&lt;br /&gt;
		t = t * 2&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local divisors = p.divisors(a)&lt;br /&gt;
	local diagram_size = log2_n&lt;br /&gt;
	local diagram = { log2_n }&lt;br /&gt;
	local primes = { 2 }&lt;br /&gt;
&lt;br /&gt;
	local function eval_diagram(d)&lt;br /&gt;
		while #d &amp;gt; #primes do&lt;br /&gt;
			local i = primes[#primes] + 1&lt;br /&gt;
			while not utils.is_prime(i) do&lt;br /&gt;
				i = i + 1&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(primes, i)&lt;br /&gt;
		end&lt;br /&gt;
		local m = 1&lt;br /&gt;
		for i = 1, #d do&lt;br /&gt;
			for _ = 1, d[i] do&lt;br /&gt;
				m = m * primes[i]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return m&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- iterate factorisations of some composite integers &amp;lt;n&lt;br /&gt;
	while diagram do&lt;br /&gt;
		while eval_diagram(diagram) &amp;gt;= n do&lt;br /&gt;
			-- reduce diagram size, preserve diagram width&lt;br /&gt;
			if diagram_size &amp;lt;= #diagram then&lt;br /&gt;
				diagram = nil&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			diagram_size = diagram_size - 1&lt;br /&gt;
			diagram[1] = diagram_size - #diagram + 1&lt;br /&gt;
			for i = 2, #diagram do&lt;br /&gt;
				diagram[i] = 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if diagram == nil then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		local diagram_divisors = 1&lt;br /&gt;
		for i = 1, #diagram do&lt;br /&gt;
			diagram_divisors = diagram_divisors * (diagram[i] + 1)&lt;br /&gt;
		end&lt;br /&gt;
		if diagram_divisors &amp;gt;= divisors then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
		diagram = utils.next_young_diagram(diagram)&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- check if an integer is superabundant&lt;br /&gt;
function p.is_superabundant(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	-- negative numbers are not superabundant&lt;br /&gt;
	if a.sign == -1 then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	-- non-integers are not superabundant&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;lt; 0 then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local last_power = 1 / 0&lt;br /&gt;
	local max_prime = p.max_prime(a)&lt;br /&gt;
	local divisor_sum = p.new(1)&lt;br /&gt;
	for i = 2, max_prime do&lt;br /&gt;
		if utils.is_prime(i) then&lt;br /&gt;
			-- factors must be the first N primes&lt;br /&gt;
			if a[i] == nil then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
			-- powers must form a non-increasing sequence&lt;br /&gt;
			if a[i] &amp;gt; last_power then&lt;br /&gt;
				return false&lt;br /&gt;
			end&lt;br /&gt;
			last_power = a[i]&lt;br /&gt;
			divisor_sum = p.mul(divisor_sum, p.div(p.sub(p.pow(i, a[i] + 1), 1), i - 1))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- last_power may be &amp;gt;1 only for 1, 4, 36&lt;br /&gt;
	if last_power &amp;gt; 1 then&lt;br /&gt;
		return p.eq(a, 1) or p.eq(a, 4) or p.eq(a, 36)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- now we actually check whether it is superabundant&lt;br /&gt;
	local n, _ = p.as_pair(a)&lt;br /&gt;
&lt;br /&gt;
	-- precision is very important here&lt;br /&gt;
	local log2_n = 0&lt;br /&gt;
	local t = 1&lt;br /&gt;
	while t * 2 &amp;lt;= n do&lt;br /&gt;
		log2_n = log2_n + 1&lt;br /&gt;
		t = t * 2&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local SA_ratio = p.div(divisor_sum, a)&lt;br /&gt;
	local diagram_size = log2_n&lt;br /&gt;
	local diagram = { log2_n }&lt;br /&gt;
	local primes = { 2 }&lt;br /&gt;
&lt;br /&gt;
	local function eval_diagram(d)&lt;br /&gt;
		while #d &amp;gt; #primes do&lt;br /&gt;
			local i = primes[#primes] + 1&lt;br /&gt;
			while not utils.is_prime(i) do&lt;br /&gt;
				i = i + 1&lt;br /&gt;
			end&lt;br /&gt;
			table.insert(primes, i)&lt;br /&gt;
		end&lt;br /&gt;
		local m = 1&lt;br /&gt;
		for i = 1, #d do&lt;br /&gt;
			for _ = 1, d[i] do&lt;br /&gt;
				m = m * primes[i]&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return m&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- iterate factorisations of some composite integers &amp;lt;n&lt;br /&gt;
	while diagram do&lt;br /&gt;
		while eval_diagram(diagram) &amp;gt;= n do&lt;br /&gt;
			-- reduce diagram size, preserve diagram width&lt;br /&gt;
			if diagram_size &amp;lt;= #diagram then&lt;br /&gt;
				diagram = nil&lt;br /&gt;
				break&lt;br /&gt;
			end&lt;br /&gt;
			diagram_size = diagram_size - 1&lt;br /&gt;
			diagram[1] = diagram_size - #diagram + 1&lt;br /&gt;
			for i = 2, #diagram do&lt;br /&gt;
				diagram[i] = 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if diagram == nil then&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
		local diagram_divisor_sum = 1&lt;br /&gt;
		for i = 1, #diagram do&lt;br /&gt;
			diagram_divisor_sum =&lt;br /&gt;
				p.mul(diagram_divisor_sum, p.div(p.sub(p.pow(primes[i], diagram[i] + 1), 1), primes[i] - 1))&lt;br /&gt;
		end&lt;br /&gt;
		local diagram_SA_ratio = p.div(diagram_divisor_sum, eval_diagram(diagram))&lt;br /&gt;
		if p.geq(diagram_SA_ratio, SA_ratio) then&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
		diagram = utils.next_young_diagram(diagram)&lt;br /&gt;
	end&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- find max prime involved in the factorisation&lt;br /&gt;
-- (a.k.a. prime limit or harmonic class) of a rational number&lt;br /&gt;
function p.max_prime(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local max_factor = 0&lt;br /&gt;
	for factor, _ in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if factor &amp;gt; max_factor then&lt;br /&gt;
				max_factor = factor&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return max_factor&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Find odd limit of a ratio&lt;br /&gt;
-- For a ratio p/q, this is simply max(p, q) where powers of 2 are ignored&lt;br /&gt;
function p.odd_limit(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local a_copy = p.copy(a)&lt;br /&gt;
	if a_copy[2] ~= nil then&lt;br /&gt;
		a_copy[2] = 0&lt;br /&gt;
	end&lt;br /&gt;
	local num, den = p.as_pair(a_copy)&lt;br /&gt;
	return math.max(num, den)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- convert a rational number to its size in octaves&lt;br /&gt;
-- equal to log2 of the rational number&lt;br /&gt;
function p.log(a, base)&lt;br /&gt;
	base = base or 2&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.inf and a.sign &amp;gt; 0 then&lt;br /&gt;
		return 1 / 0&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	if a.zero then&lt;br /&gt;
		return -1 / 0&lt;br /&gt;
	end&lt;br /&gt;
	if a.sign &amp;lt; 0 then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local logarithm = 0&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			logarithm = logarithm + power * utils._log(factor, base)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return logarithm&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- convert a rational number to its size in cents&lt;br /&gt;
function p.cents(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.sign &amp;lt; 0 then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	if a.inf and a.sign &amp;gt; 0 then&lt;br /&gt;
		return 1 / 0&lt;br /&gt;
	end&lt;br /&gt;
	if a.zero then&lt;br /&gt;
		return -1 / 0&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local c = 0&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			c = c + power * utils.log2(factor)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return c * 1200&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- convert a rational number (interpreted as an interval) into Hz&lt;br /&gt;
function p.hz(a, base)&lt;br /&gt;
	base = base or 440&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.sign &amp;lt; 0 then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	if a.zero then&lt;br /&gt;
		return 0&lt;br /&gt;
	end&lt;br /&gt;
	local log_hz = math.log(base)&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			log_hz = log_hz + power * math.log(factor)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return math.exp(log_hz)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- FJS: x = a * 2^n : x &amp;gt;= 1, x &amp;lt; 2&lt;br /&gt;
local function red(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local b = p.copy(a)&lt;br /&gt;
&lt;br /&gt;
	-- start with an approximation&lt;br /&gt;
	local log2 = p.log(b)&lt;br /&gt;
	b = p.div(b, p.pow(2, math.floor(log2)))&lt;br /&gt;
&lt;br /&gt;
	while p.lt(b, 1) do&lt;br /&gt;
		b = p.mul(b, 2)&lt;br /&gt;
	end&lt;br /&gt;
	while p.geq(b, 2) do&lt;br /&gt;
		b = p.div(b, 2)&lt;br /&gt;
	end&lt;br /&gt;
	return b&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- FJS: x = a * 2^n : x &amp;gt;= 1/sqrt(2), x &amp;lt; sqrt(2)&lt;br /&gt;
local function reb(a)&lt;br /&gt;
	local b = red(a)&lt;br /&gt;
	if p.geq(p.mul(b, b), 2) then&lt;br /&gt;
		b = p.div(b, 2)&lt;br /&gt;
	end&lt;br /&gt;
	return b&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- FJS: master algorithm&lt;br /&gt;
local function FJS_master(prime)&lt;br /&gt;
	prime = red(prime)&lt;br /&gt;
	local tolerance = p.new(65, 63)&lt;br /&gt;
	local fifth = p.new(3, 2)&lt;br /&gt;
	local k = 0&lt;br /&gt;
	while true do&lt;br /&gt;
		local a = red(p.pow(fifth, k))&lt;br /&gt;
		if math.abs(p.cents(p.div(prime, a))) &amp;lt; p.cents(tolerance) then&lt;br /&gt;
			return k&lt;br /&gt;
		end&lt;br /&gt;
		if k == 0 then&lt;br /&gt;
			k = 1&lt;br /&gt;
		elseif k &amp;gt; 0 then&lt;br /&gt;
			k = -k&lt;br /&gt;
		else&lt;br /&gt;
			k = -k + 1&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- FJS: formal comma&lt;br /&gt;
local function formal_comma(prime)&lt;br /&gt;
	local fifth_shift = FJS_master(prime)&lt;br /&gt;
	return reb(p.div(prime, p.pow(3, fifth_shift)))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- FJS representation of a rational number&lt;br /&gt;
-- might be a bit incorrect&lt;br /&gt;
-- TODO: confirm correctness&lt;br /&gt;
function p.as_FJS(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local b = p.copy(a)&lt;br /&gt;
	local otonal = {}&lt;br /&gt;
	local utonal = {}&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; and factor &amp;gt; 3 then&lt;br /&gt;
			local comma = formal_comma(factor)&lt;br /&gt;
			b = p.div(b, p.pow(comma, power))&lt;br /&gt;
			if power &amp;gt; 0 then&lt;br /&gt;
				for _ = 1, power do&lt;br /&gt;
					table.insert(otonal, factor)&lt;br /&gt;
				end&lt;br /&gt;
			else&lt;br /&gt;
				for _ = 1, -power do&lt;br /&gt;
					table.insert(utonal, factor)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(otonal)&lt;br /&gt;
	table.sort(utonal)&lt;br /&gt;
&lt;br /&gt;
	local fifths = b[3] or 0&lt;br /&gt;
&lt;br /&gt;
	local o = math.floor((fifths * 2 + 3) / 7)&lt;br /&gt;
	local num = fifths * 11 + (b[2] or 0) * 7&lt;br /&gt;
	if num &amp;gt;= 0 then&lt;br /&gt;
		num = num + 1&lt;br /&gt;
	else&lt;br /&gt;
		num = num - 1&lt;br /&gt;
		o = -o&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local num_mod = (num - utils.signum(num)) % 7&lt;br /&gt;
	local letter = &amp;quot;&amp;quot;&lt;br /&gt;
	if (num_mod == 0 or num_mod == 3 or num_mod == 4) and o == 0 then&lt;br /&gt;
		letter = &amp;quot;P&amp;quot;&lt;br /&gt;
	elseif o == 1 then&lt;br /&gt;
		letter = &amp;quot;M&amp;quot;&lt;br /&gt;
	elseif o == -1 then&lt;br /&gt;
		letter = &amp;quot;m&amp;quot;&lt;br /&gt;
	else&lt;br /&gt;
		if o &amp;gt;= 0 then&lt;br /&gt;
			o = o - 1&lt;br /&gt;
		else&lt;br /&gt;
			o = o + 1&lt;br /&gt;
		end&lt;br /&gt;
		if o &amp;gt; 0 then&lt;br /&gt;
			while o &amp;gt; 0 do&lt;br /&gt;
				letter = letter .. &amp;quot;A&amp;quot;&lt;br /&gt;
				o = o - 2&lt;br /&gt;
			end&lt;br /&gt;
		else&lt;br /&gt;
			while o &amp;lt; 0 do&lt;br /&gt;
				letter = letter .. &amp;quot;d&amp;quot;&lt;br /&gt;
				o = o + 2&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if #letter &amp;gt;= 5 then&lt;br /&gt;
			letter = #letter .. letter:sub(1, 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local FJS = letter .. num&lt;br /&gt;
	if #otonal &amp;gt; 0 then&lt;br /&gt;
		FJS = FJS .. &amp;quot;^{&amp;quot; .. table.concat(otonal, &amp;quot;,&amp;quot;) .. &amp;quot;}&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if #utonal &amp;gt; 0 then&lt;br /&gt;
		FJS = FJS .. &amp;quot;_{&amp;quot; .. table.concat(utonal, &amp;quot;,&amp;quot;) .. &amp;quot;}&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	return FJS&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine log2 product complexity&lt;br /&gt;
function p.tenney_height(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local h = 0&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			h = h + math.abs(power) * utils.log2(factor)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine log2 max complexity&lt;br /&gt;
function p.weil_height(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local h1 = p.tenney_height(a)&lt;br /&gt;
	local h2 = 0&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			h2 = h2 + power * utils.log2(factor)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	h2 = math.abs(h2)&lt;br /&gt;
	return h1 + h2&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine sopfr complexity&lt;br /&gt;
function p.wilson_height(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local h = 0&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			h = h + math.abs(power) * factor&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return h&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine product complexity&lt;br /&gt;
function p.benedetti_height(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local n, m = p.as_pair(a)&lt;br /&gt;
	if (math.log(n) + math.log(m)) / math.log(10) &amp;lt;= 15 then&lt;br /&gt;
		return n * m&lt;br /&gt;
	else&lt;br /&gt;
		-- it is going to be an overflow&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine the number of rational divisors&lt;br /&gt;
function p.divisors(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return 0&lt;br /&gt;
	end&lt;br /&gt;
	local d = 1&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			d = d * (math.abs(power) + 1)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return d&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- determine whether the rational number is +- p/q, where p, q are primes OR 1&lt;br /&gt;
function p.is_prime_ratio(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	local n_factors = 0&lt;br /&gt;
	local m_factors = 0&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;gt; 0 then&lt;br /&gt;
				n_factors = n_factors + 1&lt;br /&gt;
			else&lt;br /&gt;
				m_factors = m_factors + 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return n_factors &amp;lt;= 1 and m_factors &amp;lt;= 1&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- return prime factorisation of a rational number&lt;br /&gt;
function p.factorisation(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or p.eq(a, 1) or p.eq(a, -1) then&lt;br /&gt;
		return &amp;quot;n/a&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local s = &amp;quot;&amp;quot;&lt;br /&gt;
	if a.sign &amp;lt; 0 then&lt;br /&gt;
		s = s .. &amp;quot;-&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local factors = {}&lt;br /&gt;
	for factor, _ in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			table.insert(factors, factor)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(factors)&lt;br /&gt;
	for i, factor in ipairs(factors) do&lt;br /&gt;
		if i &amp;gt; 1 then&lt;br /&gt;
			s = s .. &amp;quot; × &amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
		s = s .. factor&lt;br /&gt;
		if a[factor] ~= 1 then&lt;br /&gt;
			s = s .. &amp;quot;&amp;lt;sup&amp;gt;&amp;quot; .. a[factor] .. &amp;quot;&amp;lt;/sup&amp;gt;&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- return the subgroup generated by primes from a rational number&amp;#039;s prime factorisation&lt;br /&gt;
function p.subgroup(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if p.eq(a, 1) then&lt;br /&gt;
		return &amp;quot;1&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or p.eq(a, -1) then&lt;br /&gt;
		return &amp;quot;n/a&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local s = &amp;quot;&amp;quot;&lt;br /&gt;
	local factors = {}&lt;br /&gt;
	for factor, _ in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			table.insert(factors, factor)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(factors)&lt;br /&gt;
	for i, factor in ipairs(factors) do&lt;br /&gt;
		if i &amp;gt; 1 then&lt;br /&gt;
			s = s .. &amp;quot;.&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
		s = s .. factor&lt;br /&gt;
	end&lt;br /&gt;
	if a.sign &amp;lt; 0 then&lt;br /&gt;
		s = &amp;quot;-1.&amp;quot; .. s&lt;br /&gt;
	end&lt;br /&gt;
	return s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- unpack rational as two return values (n, m)&lt;br /&gt;
function p.as_pair(a)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: NaN&lt;br /&gt;
	if a.nan then&lt;br /&gt;
		return 0, 0&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: infinity&lt;br /&gt;
	if a.inf then&lt;br /&gt;
		return a.sign, 0&lt;br /&gt;
	end&lt;br /&gt;
	-- special case: zero&lt;br /&gt;
	if a.zero then&lt;br /&gt;
		return 0, a.sign&lt;br /&gt;
	end&lt;br /&gt;
	-- regular case: not NaN, not infinity, not zero&lt;br /&gt;
	local n = 1&lt;br /&gt;
	local m = 1&lt;br /&gt;
	for factor, power in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			if power &amp;gt; 0 then&lt;br /&gt;
				n = n * (factor ^ power)&lt;br /&gt;
			else&lt;br /&gt;
				m = m * (factor ^ -power)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	n = n * a.sign&lt;br /&gt;
	return n, m&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- return a string ratio representation&lt;br /&gt;
function p.as_ratio(a, separator)&lt;br /&gt;
	separator = separator or &amp;quot;/&amp;quot;&lt;br /&gt;
	local n, m = p.as_pair(a)&lt;br /&gt;
	return (&amp;quot;%d%s%d&amp;quot;):format(n, separator, m)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- return the {n, m} pair as a Lua table&lt;br /&gt;
function p.as_table(a)&lt;br /&gt;
	return { p.as_pair(a) }&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- return n / m as a float approximation&lt;br /&gt;
function p.as_float(a)&lt;br /&gt;
	local n, m = p.as_pair(a)&lt;br /&gt;
	return n / m&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- return a rational number in subgroup ket notation&lt;br /&gt;
function p.as_subgroup_ket(a, frame)&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	if a.nan or a.inf or a.zero or a.sign &amp;lt; 0 then&lt;br /&gt;
		return &amp;quot;n/a&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	local factors = {}&lt;br /&gt;
	for factor, _ in pairs(a) do&lt;br /&gt;
		if type(factor) == &amp;quot;number&amp;quot; then&lt;br /&gt;
			table.insert(factors, factor)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort(factors)&lt;br /&gt;
	local subgroup = &amp;quot;1&amp;quot;&lt;br /&gt;
	if not p.eq(a, 1) then&lt;br /&gt;
		subgroup = table.concat(factors, &amp;quot;.&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local powers = {}&lt;br /&gt;
	for _, factor in ipairs(factors) do&lt;br /&gt;
		table.insert(powers, a[factor])&lt;br /&gt;
	end&lt;br /&gt;
	local template_arg = &amp;quot;0&amp;quot;&lt;br /&gt;
	if not p.eq(a, 1) then&lt;br /&gt;
		template_arg = table.concat(powers, &amp;quot; &amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return subgroup .. &amp;quot; &amp;quot; .. frame:expandTemplate({&lt;br /&gt;
		title = &amp;quot;Monzo&amp;quot;,&lt;br /&gt;
		args = { template_arg },&lt;br /&gt;
	})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- return a string of a rational number in monzo notation&lt;br /&gt;
-- calling Template: Monzo&lt;br /&gt;
function p.as_ket(a, frame, skip_many_zeros, only_numbers)&lt;br /&gt;
	if skip_many_zeros == nil then&lt;br /&gt;
		skip_many_zeros = true&lt;br /&gt;
	end&lt;br /&gt;
	only_numbers = only_numbers or false&lt;br /&gt;
	if type(a) == &amp;quot;number&amp;quot; then&lt;br /&gt;
		a = p.new(a)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- special cases&lt;br /&gt;
	if a.nan or a.inf or a.zero or a.sign &amp;lt; 0 then&lt;br /&gt;
		return &amp;quot;n/a&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- regular case: positive finite ratio&lt;br /&gt;
	local s = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	-- preparing the argument&lt;br /&gt;
	local max_prime = p.max_prime(a)&lt;br /&gt;
	local template_arg = &amp;quot;&amp;quot;&lt;br /&gt;
	local template_arg_without_trailing_zeros = &amp;quot;&amp;quot;&lt;br /&gt;
	local zeros_n = 0&lt;br /&gt;
	for i = 2, max_prime do&lt;br /&gt;
		if utils.is_prime(i) then&lt;br /&gt;
			if i &amp;gt; 2 then&lt;br /&gt;
				template_arg = template_arg .. &amp;quot; &amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
			template_arg = template_arg .. (a[i] or 0)&lt;br /&gt;
&lt;br /&gt;
			if (a[i] or 0) ~= 0 then&lt;br /&gt;
				if skip_many_zeros and zeros_n &amp;gt;= 4 then&lt;br /&gt;
					template_arg = template_arg_without_trailing_zeros&lt;br /&gt;
					if #template_arg &amp;gt; 0 then&lt;br /&gt;
						template_arg = template_arg .. &amp;quot; &amp;quot;&lt;br /&gt;
					end&lt;br /&gt;
					template_arg = template_arg .. &amp;quot;0&amp;lt;sup&amp;gt;&amp;quot; .. zeros_n .. &amp;quot;&amp;lt;/sup&amp;gt; &amp;quot; .. (a[i] or 0)&lt;br /&gt;
				end&lt;br /&gt;
				zeros_n = 0&lt;br /&gt;
				template_arg_without_trailing_zeros = template_arg&lt;br /&gt;
			else&lt;br /&gt;
				zeros_n = zeros_n + 1&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if #template_arg == 0 then&lt;br /&gt;
		template_arg = &amp;quot;0&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	if only_numbers then&lt;br /&gt;
		s = s .. template_arg&lt;br /&gt;
	else&lt;br /&gt;
		s = s .. frame:expandTemplate({&lt;br /&gt;
			title = &amp;quot;Monzo&amp;quot;,&lt;br /&gt;
			args = { template_arg },&lt;br /&gt;
		})&lt;br /&gt;
	end&lt;br /&gt;
	return s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- parse a rational number&lt;br /&gt;
-- returns nil on failure&lt;br /&gt;
function p.parse(unparsed)&lt;br /&gt;
	if type(unparsed) ~= &amp;quot;string&amp;quot; then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	-- removing whitespaces&lt;br /&gt;
	unparsed = unparsed:gsub(&amp;quot;%s&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
	-- removing &amp;lt;br&amp;gt; and &amp;lt;br/&amp;gt; tags&lt;br /&gt;
	unparsed = unparsed:gsub(&amp;quot;&amp;lt;br/?&amp;gt;&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	-- length limit: very long strings are not converted into Lua numbers correctly&lt;br /&gt;
	local max_length = 15&lt;br /&gt;
&lt;br /&gt;
	-- rational form&lt;br /&gt;
	local sign, n, _, m = unparsed:match(&amp;quot;^%s*(%-?)%s*(%d+)%s*(/%s*(%d+))%s*$&amp;quot;)&lt;br /&gt;
	if n == nil then&lt;br /&gt;
		-- integer form&lt;br /&gt;
		sign, n = unparsed:match(&amp;quot;^%s*(%-?)%s*(%d+)%s*$&amp;quot;)&lt;br /&gt;
		if n == nil then&lt;br /&gt;
			-- parsing failure&lt;br /&gt;
			return nil&lt;br /&gt;
		else&lt;br /&gt;
			m = 1&lt;br /&gt;
			if #n &amp;gt; max_length then&lt;br /&gt;
				return nil&lt;br /&gt;
			end&lt;br /&gt;
			n = tonumber(n)&lt;br /&gt;
			if #sign &amp;gt; 0 then&lt;br /&gt;
				n = -n&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	else&lt;br /&gt;
		if #n &amp;gt; max_length then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		n = tonumber(n)&lt;br /&gt;
		if #m &amp;gt; max_length then&lt;br /&gt;
			return nil&lt;br /&gt;
		end&lt;br /&gt;
		m = tonumber(m)&lt;br /&gt;
		if #sign &amp;gt; 0 then&lt;br /&gt;
			n = -n&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return p.new(n, m)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- a version of as_ket() that can be {{#invoke:}}d&lt;br /&gt;
function p.ket(frame)&lt;br /&gt;
	local unparsed = frame.args[1] or &amp;quot;1&amp;quot;&lt;br /&gt;
	local a = p.parse(unparsed)&lt;br /&gt;
	if a == nil then&lt;br /&gt;
		return &amp;#039;&amp;lt;span style=&amp;quot;color:red;&amp;quot;&amp;gt;Invalid rational number: &amp;#039; .. unparsed .. &amp;quot;.&amp;lt;/span&amp;gt;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	return p.as_ket(a, frame)&lt;br /&gt;
end&lt;br /&gt;
p.monzo = p.ket&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>R-4981</name></author>
	</entry>
</feed>