Module:Pop density
--
 -- This module implements {{Pop density}}
 --
 local p = {}
 local math_module = require( &quot;Module:Math&quot; )
 local precision = math_module._precision
 local sortkey = require( &quot;Module:Sortkey&quot; )
 
 local function rnd(num, digits)
 	-- This function implements {{rnd}}
 	return math_module._precision_format(tostring(num), tostring(digits))
 end
 local unitnames = {
 	[&quot;km²&quot;] = &quot;km2&quot;,
 	[&quot;sqkm&quot;] = &quot;km2&quot;,
 	[&quot;km2&quot;] = &quot;km2&quot;,
 	[&quot;mi2&quot;] = &quot;sqmi&quot;,
 	[&quot;sqmi&quot;] = &quot;sqmi&quot;,
 	[&quot;acres&quot;] = &quot;acre&quot;,
 	[&quot;acre&quot;] = &quot;acre&quot;,
 	[&quot;ha&quot;] = &quot;ha&quot;,
 	[&quot;dunam&quot;] = &quot;dunam&quot;,
 	[&quot;m²&quot;] = &quot;m2&quot;,
 	[&quot;sqm&quot;] = &quot;m2&quot;,
 	[&quot;m2&quot;] = &quot;m2&quot;
 }
 local unitmult = {
 	[&quot;km2&quot;] = 1000000,
 	[&quot;sqmi&quot;] = 2589988.110336,
 	[&quot;acre&quot;] = 4046.8564224,
 	[&quot;ha&quot;] = 10000,
 	[&quot;dunam&quot;] = 1000,
 	[&quot;m2&quot;] = 1
 }
 local unitstr = {
 	[&quot;km2&quot;] = 'km&lt;sup&gt;2&lt;/sup&gt;',
 	[&quot;sqmi&quot;] = 'sq&amp;nbsp;mi',
 	[&quot;acre&quot;] = 'acre',
 	[&quot;ha&quot;] = 'ha',
 	[&quot;dunam&quot;] = 'dunam',
 	[&quot;m2&quot;] = 'm&lt;sup&gt;2&lt;/sup&gt;'
 }
 
 local function popdensity(pop, area1, areaunit1, areaunit2, prec, disp, flip)
 	local dens1, dens1sort, prec1
 	local dens2, dens2sort, prec2
 	local str1, str2 = '', ''
 	local uniterror = '&lt;sup&gt;[[Template:Pop density|?Unknown unit?]]&lt;/sup&gt;[[Category:Pop density using unsupported units]]'
 	
 	if(pop ~= '' and area1 ~= '') then
 		-- pop and area are defined
 		local popnum = tonumber(pop)
 		if not popnum then
 			error(string.format('Unable to convert population &quot;%s&quot; to a number', pop), 2)
 		end
 		local area1num = tonumber(area1)
 		if not area1num then
 			error(string.format('Unable to convert area &quot;%s&quot; to a number', area1), 2)
 		end
 		local dens1num = popnum/area1num
 		
 		local unit1 = unitnames[areaunit1] or nil
 		local unit2 = unitnames[areaunit2] or nil
 		
 		prec1 = (prec ~= '') and tonumber(prec) 
 			or (1+math.log10(2*area1/(1/10^precision(pop)+pop/area1/10^precision(area1))))
 		dens1 = rnd(dens1num, math.floor(prec1 + 0.5))
 		dens1sort = '&lt;span style=&quot;display:none&quot; data-sort-value=&quot;'
 			.. sortkey._sortKeyForNumber(dens1num) .. '♠&quot;&gt;&lt;/span&gt;'
 		if (unit1) then
 			str1 = '/' .. unitstr[unit1]
 			if(unit2) then
 				-- convert
 				local mult = unitmult[unit2]/unitmult[unit1]
 				prec2 = prec1 - math.log10(mult)
 				dens2 = rnd(dens1num*mult, math.floor(prec2 + 0.5))
 				dens2sort = '&lt;span style=&quot;display:none&quot; data-sort-value=&quot;'
 					.. sortkey._sortKeyForNumber(dens1num*mult) .. '♠&quot;&gt;&lt;/span&gt;'
 				str2 = '/' .. unitstr[unit2]
 			elseif(areaunit2 ~= '') then
 				if( disp ~= 'num' ) then
 					dens2 = '?'
 				else
 					dens2 = '?' .. uniterror
 				end
 				str2 = '/' .. areaunit2 .. uniterror
 			end
 		elseif(areaunit1 ~= '') then
 			if( disp ~= 'num' ) then
 				dens2 = '?'
 			else
 				dens2 = '?' .. uniterror
 			end
 			if(unit2) then
 				str2 = '/' .. unitstr[unit2]
 			elseif(areaunit2 ~= '') then
 				str2 = '/' .. areaunit2 .. uniterror				
 			end
 			str1 = '/' .. areaunit1 .. uniterror
 		end
 
 		-- form output
 		if( str2 ~= '' ) then
 			-- has a converted unit
 			if( disp ~= 'num' and disp ~= 'table' ) then
 				-- display input and output density numbers with units
 				if( flip == 'on' ) then
 					return (dens2sort or '') .. dens2 .. str2 .. ' (' .. dens1 .. str1 .. ')'
 				else
 					return (dens1sort or '') .. dens1 .. str1 .. ' (' .. dens2 .. str2 .. ')'
 				end
 			elseif( disp == 'table') then
 				dens1 = (dens1sort or '') .. dens1
 				dens2 = (dens2sort or '') .. dens2
 				return pop .. '||' .. area1 .. '||' .. dens1 .. '||' .. dens2
 			else
 				-- display output density number without unit
 				return dens2
 			end
 		else
 			-- no converted unit
 			if( disp ~= 'num' and disp ~= 'table' ) then
 				-- display input density number with unit 
 				return (dens1sort or '') .. dens1 .. str1 
 			elseif( disp == 'table') then
 				return pop .. '||' .. area1 .. '||' ..(dens1sort or '') .. dens1
 			else
 				-- display input density number without unit
 				return dens1
 			end
 		end
 	end
 	return ''
 end
 
 function p.density(frame)
 	local args = (frame.args[3] ~= nil) and frame.args or frame:getParent().args
 	return popdensity(
 		args[1] or '', args[2] or '', args[3] or '', args[4] or '', 
 		args['prec'] or '', args['disp'] or '', args['flip'] or ''
 		)
 end