模組:Number/docUtil

local p = { PrimeTable = {} }
local numlib = require("Module:Number")
local numdata = require("Module:Number/data")

function p.printDoc(frame)
	local body = ''
	temp_frame = frame
	for key,value in pairs(numdata.numberFormat) do
		body = body .. p._printDocRow(value, key) ..'\n'
	end
	return mw.text.trim(body)
end

function p._printDocRow(num_data_row, namekey)
	local body = "|- \n| "
	body = body .. "-{" .. namekey .. "}- || "
	if num_data_row.page then body = body .. "[[" .. num_data_row.page .. "]]" end
	body = body .. "\n| "
	if temp_frame and num_data_row.info then 
		body = body .. temp_frame:callParserFunction{name = "#tag:code", args = {mw.text.nowiki(num_data_row.info)}} 
	end
	body = body .. "\n| \n"
	if num_data_row.arg_desc then
		for key,value in pairs(num_data_row.arg_desc) do
			local keystr = tostring(key)
			if temp_frame then 
				keystr = temp_frame:callParserFunction{name = "#tag:code", args = {mw.text.nowiki("{{{ ") .. '\'\'\'' .. keystr .. '\'\'\'' .. mw.text.nowiki(" }}}")}} 
			end
			body = body .. '*' .. keystr .. '\n'
			body = body .. "*:" .. tostring(value) .. '\n'
		end
	end
	body = body .. "| \n"
	if num_data_row.example then
		body = body .. ';' .. tostring(num_data_row.example) .. '\n'
		body = body .. _number_example_row(num_data_row, namekey) .. '\n'
	end
	body = body .. '|'
	if num_data_row.name == "質數" then
		body = body .. "前1000項<br/>2 ~ 7919"
	elseif num_data_row.list then
		local count, val_max, id_max, val_min = 0, 0, 0, nil
		for key,value in pairs(num_data_row.list) do
			if tonumber(key) > tonumber(val_max) then val_max,id_max = key,value end
			if val_min == nil then val_min = key end
			if tonumber(key) < tonumber(val_min) then val_min = key end
			count = count + 1
		end
		if val_min then
			body = body .. '前' .. tostring(count) .."項<br/>" .. val_min .. " ~ " .. val_max
		end
	end
	body = body .. "\n|"
	if num_data_row.name == "半完全數" then
		if temp_frame then 
			body = body .. temp_frame:expandTemplate{title = "Partial_success", args = {"速度慢"}} 
		else
			body = body .. "速度慢"
		end
	elseif num_data_row.check then
		if temp_frame then 
			body = body .. temp_frame:expandTemplate{title = "Yes", args = {"支援"}} 
		else
			body = body .. "支援"
		end
	else
		if temp_frame then 
			body = body .. temp_frame:expandTemplate{title = "No", args = {"不支援"}} 
		else
			body = body .. "不支援"
		end
	end
	return body
end

function p.single_property_example(frame)
	local body = ''
	temp_frame = frame
	local to_display = mw.text.trim(frame.args[1] or '')
	if to_display == '' then return '' end
	local num_data_row = numdata.numberFormat[frame.args[1]]
	if num_data_row == nil then return '' end
	if num_data_row.example then
		body = body .. ';' .. tostring(num_data_row.example) .. '\n'
		body = body .. _number_example_row(num_data_row, to_display) .. '\n'
	end
	return mw.text.trim(body)
end

function _number_example_row(num_data_row, namekey)
	if numlib == nil then numlib = require("Module:Number") end
	
    local body = ''

	if temp_frame then can_math = true end
	local number = tonumber(num_data_row.example)
	
	--因數分解
	if p.PrimeTable.table_max == nil then p.PrimeTable = require('Module:Factorization') end
	local primedata = p.PrimeTable._factorization(number)
	local divdata = p.PrimeTable._findDivisorByPrimeFactor(primedata)
 	--因數分解發生錯誤,停止執行並返回錯誤
	if primedata.has_err ~= nil or divdata.has_err ~= nil then
		local Error = require("Module:Error")
		if primedata.has_err ~= nil then return body .. '\n' .. Error.error({[1]="錯誤:" .. primedata.has_err})
		else return body .. '\n' .. Error.error({[1]="錯誤:" .. divdata.has_err}) end
	end
	
	local is_prime = true --表示數字是否為質數
	local num_sqrt = math.sqrt(number) --表示數字的平方根
	local admirable_div = nil --表示佩服數的相減因數
	local is_unusual = nil --表示數字是否有大於平方根的質因數
	local div_sum = 0 --因數和
	local prime_count = 0 --相異質因數個數
	local div_sum_harmonic = 0 --因數調和總和
	local div_harmonic_avg = 0.001 --因數調和平均數
	local div_count = 0 --因數數量
	local exp_num = 0 --質因數總指數 (Ω)
	local prime_digits = 0
	local buffer_text = ''
	local mersenne_prime_for_perfect_number = ''
	--掃描質因數
	for first,second in pairs(primedata) do
		if first ~= 'has_err' then 
			if first ~= 1 and first ~= number then 
				is_prime = false
			end
			if first ~= 1 then
				--判斷是否為不尋常數 (是否有大於平方根的質因數)
				if first > num_sqrt then is_unusual = first end
				--計算質因數總指數 (Ω)
				exp_num = exp_num + second
				--計算相異質因數數量
				prime_count = prime_count + 1
				prime_digits = prime_digits + 
				mw.ustring.len( mw.ustring.format( "%d",math.floor(math.abs(first)) ) )
				if second > 1 then prime_digits = prime_digits + 
				mw.ustring.len( mw.ustring.format( "%d",math.floor(math.abs(second)) ) ) end
			end
		end
	end
	
	--計算因數和
	for first,second in pairs(divdata) do
		if first ~= 'has_err' then 
			if second ~= number then div_sum = div_sum + second end
			div_sum_harmonic = div_sum_harmonic + (1.0 / second)
			div_count = div_count + 1
		end
	end
	
	--計算因數的調和平均數
	div_harmonic_avg = (div_count + 0.000000) / div_sum_harmonic
	for first,second in pairs(divdata) do
		if first ~= 'has_err' then 
			--判斷數字是否為佩服數
			if div_sum - second * 2 == number then admirable_div = second end
		end
	end
	
	--產生<math>格式,以印出質因數分解於條目
	local times = " x "
	local pow_h = "<sup>"
	local pow_f = "</sup>"
	local left_ = "("
	local right_ = ")"
	if can_math then
		times = "\\times "
		pow_h = "^{"
		pow_f = "} "
		left_ = "\\left( "
		right_ = "\\right) "
	end
	
	local is_gprime = true
	local gfactors_str = ''
	if mw.text.trim(namekey) == "高斯整數分解" then
		if cmath==nil then cmath = require("Module:Complex Number").cmath.init() end
		local cnum = cmath.toComplexNumber(tostring(number))
		is_gprime = cmath.is_prime_quadrant1(cnum)
		if is_gprime ~= nil then
			if not is_gprime then
				local gprimedata, gfactors = p.PrimeTable._gaussianFactorization(tostring(number)), {}
				for first,second in pairs(gprimedata) do
					if first ~= 'has_err' then 
						local complex_num = cmath.toComplexNumber(first) 
						if complex_num.real ~= 0 and complex_num.imag ~= 0 then
							gfactors[left_ .. tostring(first) .. right_] = second
						else
							gfactors[first] = second
						end
					end
				end
				--印出質因數分解於條目
				gfactors_str = p.PrimeTable.create_factorization_string(gfactors, times, pow_h, pow_f)
				if mw.text.trim(gfactors_str) == '' then is_gprime = true end
				if can_math then 
					gfactors_str = temp_frame:callParserFunction{name = "#tag:math", args = {gfactors_str}} 
				end
			end
		end
	end
	
	--印出質因數分解於條目
	local factors_str = p.PrimeTable.create_factorization_string(primedata, times, pow_h, pow_f)
	if can_math then 
		factors_str = temp_frame:callParserFunction{name = "#tag:math", args = {factors_str}} 
		if div_sum == number then
			mersenne_prime_for_perfect_number= "2^{" .. tostring(primedata[2]) .. "}\\times\\left( 2^{" .. 
				tostring(primedata[2]+1) .. "}-1\\right)"
			mersenne_prime_for_perfect_number = temp_frame:callParserFunction{name = "#tag:math", args = {mersenne_prime_for_perfect_number}} 
		end
	end
	
	local simi_div = {}
	if div_sum > number and number > 0 then 
		if #divdata <= 32 then
			--此為指數時間複雜度演算法,因此當因數超過32個時則放棄計算
			simi_div = numlib._checkSemiperfectNumberByDivisor(divdata)
		end
	end
	
	local printer = numdata.getIntegerInfoPrinter()
	printer:init({
		number=number,
		is_prime=is_prime,
		admirable_div=admirable_div,
		is_unusual=is_unusual,
		div_sum=div_sum,
		prime_count=prime_count,
		div_sum_harmonic=div_sum_harmonic,
		div_harmonic_avg=div_harmonic_avg,
		div_count=div_count,
		exp_num=exp_num,
		prime_digits=prime_digits,
		divdata=divdata,
		primedata=primedata,
		simi_div=simi_div,
		factors_str=factors_str,
		mersenne_prime_for_perfect_number=mersenne_prime_for_perfect_number,
		is_gprime=is_gprime,
		gfactors_str=gfactors_str,
	});

	local text = ''
	local args = {}
	args = printer:getValue(namekey)
	if num_data_row.value then num_data_row.value(printer, args) end
	body = numdata._getFormatingStringByArgument(' ' .. num_data_row.info, args)

	return mw.text.trim(body)
end

return p