模块:Complex Number/Functions

来自有兽档案馆
文档图示 模块文档[创建] [跳转到代码]

本模块还没有文档页面。

您可以创建文档以让编者更好地理解本模块的用途。
编者可以在本模块的沙盒创建 | 镜像和测试样例创建页面进行实验。
请将模块自身所属的分类添加在文档中。本模块的子页面
local p = {}

function p._init(_math_lib, _to_number)
	local warp_funcs={"factorial","gamma","sec","csc","sech","csch","asec","acsc","asech","acsch","gd","cogd","arcgd",
		"gcd","range","binomial",'minimum','maximum','average','geoaverage','var','σ',
		'selectlist',
		'hide'--調整條目中定義不顯示的函數
	}
	for i=1,#warp_funcs do
		_math_lib[ warp_funcs[i] ] = p['_' .. warp_funcs[i] ]
	end
	math_lib = _math_lib
	to_number = _to_number
	return _math_lib
end
function p._complex_number()
	return p._init(require("Module:Complex Number").cmath.init(), require("Module:Complex Number").cmath.init().toComplexNumber)
end

function p._binomial(cal_n,cal_k)
	local r_n=tonumber(tostring(cal_n))
	local r_k=tonumber(tostring(cal_k))
	if r_n and r_k then
		if r_n>0 and r_k>=0  then
			local f_n, f_k;
			_,f_n = math.modf(r_n);_,f_k = math.modf(r_k)
			if math.abs(f_n) < 1e-12 and math.abs(f_k) < 1e-12 then
				local result = 1
				if r_n == 0 then return result end
				while r_k>0 do
					result = result * r_n / r_k
					r_n = r_n - 1
					r_k = r_k - 1
				end
				return result
			end
		end
	end
	local n=to_number(cal_n)
	local k=to_number(cal_k)
	return p._factorial(n) * math_lib.inverse( p._factorial(k) ) * math_lib.inverse( p._factorial(n-k) )
end

function p._factorial(cal_z)return p._gamma(to_number(cal_z) + 1)end
function p._hide(cal_z)return to_number(0)end
function p._sec(cal_z)return math_lib.inverse( math_lib.cos( to_number(cal_z) ) )end
function p._csc(cal_z)return math_lib.inverse( math_lib.sin( to_number(cal_z) ) )end
function p._sech(cal_z)return math_lib.inverse( math_lib.cosh( to_number(cal_z) ) )end
function p._csch(cal_z)return math_lib.inverse( math_lib.sinh( to_number(cal_z) ) )end
function p._asec(cal_z)return  math_lib.acos( math_lib.inverse( to_number(cal_z) ) )end
function p._acsc(cal_z)return  math_lib.asin( math_lib.inverse( to_number(cal_z) ) )end
function p._asech(cal_z)return  math_lib.acosh( math_lib.inverse( to_number(cal_z) ) )end
function p._acsch(cal_z)return  math_lib.asinh( math_lib.inverse( to_number(cal_z) ) )end
function p._gd(cal_z)return math_lib.atan( math_lib.tanh( to_number(cal_z) * 0.5 ) ) * 2 end
function p._arcgd(cal_z)return math_lib.atanh( math_lib.tan( to_number(cal_z) * 0.5 ) ) * 2 end
function p._cogd(cal_z)local x = to_number(cal_z); return - math_lib.sgn( x ) * math_lib.log( math_lib.abs( math_lib.tanh( x * 0.5 ) ) ) end

function p._range(val,vmin,vmax)
	local v_val, v_min, v_max = math_lib.tovector(to_number(val)), math_lib.tovector(to_number(vmin)), math_lib.tovector(to_number(vmax))
	for i=1,#v_val do
		local min_v, max_v = math.min(v_min[i],v_max[i]), math.max(v_min[i],v_max[i])
		if v_val[i] < min_v or v_val[i] > max_v then return to_number(math_lib.nan) end
	end
	return to_number(val)
end

function p._selectlist(x,...) return ({ ... })[tonumber(tostring(x)) or 0] or tonumber('nan') end
function p._minimum(...) return p.minmax('min', ...) end
function p._maximum(...) return p.minmax('max', ...) end
function p._average(...) return p.minmax('avg', ...) end
function p._geoaverage(...) return p.minmax('gavg', ...) end
function p._var(...) return p.minmax('var', ...) end
p['_σ'] = function(...) return p.minmax('σ',...) end
function p.minmax(mode,...)
	local tonumber_lib = to_number or tonumber
	local lib_math = math_lib or math
	local args, tester = { ... }, {tonumber("nan")}
	local sum, prod, count, sumsq, sig = tonumber_lib(0), tonumber_lib(1), 0, tonumber_lib(0), (mode =='var'or mode=='σ')
	local mode_map = {}
	local non_nan
	for i=1,#args do
		local got_number, calc_number = tonumber(tostring(args[i])) or tonumber("nan"), tonumber_lib(args[i])
		if calc_number then sum, prod, count = calc_number + sum, calc_number * prod, count + 1 end
		if sig == true then 
			local x_2 = calc_number * calc_number
			if lib_math.dot then
				x_2 = lib_math.dot(calc_number, lib_math.conjugate(calc_number))
			end
			sumsq = sumsq + x_2 
		end
		mode_map[args[i]] = (mode_map[args[i]]or 0) + 1
		if tostring(got_number):lower()~="nan" and type(non_nan) == type(nil) then
			tester[1], non_nan = got_number, got_number
		else tester[#tester + 1] = got_number end
	end
	local modes={min=math.min,max=math.max,sum=function()return sum end,prod=function()return prod end,count=function()return count end,
		avg=function()return sum*tonumber_lib(1/count) end,
		gavg=function()return lib_math.pow(prod,tonumber_lib(1/count)) end,
		var=function()return sumsq*tonumber_lib(1/count)-sum*sum*tonumber_lib(1/(count*count)) end,
		['σ']=function()return lib_math.sqrt(sumsq*tonumber_lib(1/count)-sum*sum*tonumber_lib(1/(count*count))) end,
		mode=function()
			local max_count, mode_data = 0, ''
			for mkey, mval in pairs(mode_map) do
				if mval > max_count then
					max_count = mval
					mode_data = mkey
				end
			end
			return mode_data
		end
	}
	if tostring(tester[1]):lower()=="nan" and mode:sub(1,1)=='m' then
		local error_msg = ''
		for i=1,#args do if error_msg~=''then error_msg = error_msg .. '、 ' end
			error_msg = error_msg .. tostring(args[i])
		end
		error("給定的數字 " .. error_msg .." 無法比較大小") 
	end
	if type(modes[mode]) ~= type(tonumber) then
		error("未知的統計方式 '" .. mode .."' ") 
	end
	return modes[mode](unpack(tester))
end

local function fold(func, ...)
	-- Use a function on all supplied arguments, and return the result. The function must accept two numbers as parameters,
	-- and must return a number as an output. This number is then supplied as input to the next function call.
	local vals = {...}
	local count = #vals -- The number of valid arguments
	if count == 0 then return
		-- Exit if we have no valid args, otherwise removing the first arg would cause an error.
		nil, 0
	end 
	local ret = table.remove(vals, 1)
	for _, val in ipairs(vals) do
		ret = func(ret, val)
	end
	return ret, count
end

--[[
Fold arguments by selectively choosing values (func should return when to choose the current "dominant" value).
]]
local function binary_fold(func, ...)
	local value = fold((function(a, b) if func(a, b) then return a else return b end end), ...)
	return value
end
local Reciprocal_gamma_coeff = {1,0.577215664901532860607,-0.655878071520253881077,-0.0420026350340952355290,0.166538611382291489502,-0.0421977345555443367482,-0.00962197152787697356211,0.00721894324666309954240,-0.00116516759185906511211,-0.000215241674114950972816,0.000128050282388116186153,-0.0000201348547807882386557,-1.25049348214267065735e-6,1.13302723198169588237e-6,-2.05633841697760710345e-7,6.11609510448141581786e-9,5.00200764446922293006e-9,-1.18127457048702014459e-9,1.04342671169110051049e-10,7.78226343990507125405e-12,-3.69680561864220570819e-12,5.10037028745447597902e-13,-2.05832605356650678322e-14,-5.34812253942301798237e-15,1.22677862823826079016e-15,-1.18125930169745876951e-16,1.18669225475160033258e-18,1.41238065531803178156e-18,-2.29874568443537020659e-19,1.71440632192733743338e-20}
--https://oeis.org/A001163 、 https://oeis.org/A001164
local stirling_series_coeff = {1,0.0833333333333333333333333,0.00347222222222222222222222,-0.00268132716049382716049383,-0.000229472093621399176954733,0.000784039221720066627474035,0.0000697281375836585777429399,-0.000592166437353693882864836,-0.0000517179090826059219337058,0.000839498720672087279993358,0.0000720489541602001055908572,-0.00191443849856547752650090,-0.000162516262783915816898635,0.00640336283380806979482364,0.000540164767892604515180468,-0.0295278809456991205054407,-0.00248174360026499773091566,0.179540117061234856107699,0.0150561130400264244123842,-1.39180109326533748139915,-0.116546276599463200850734}
function p._gamma_high_imag(cal_z)
	local z = to_number(cal_z)
	if z ~= nil and math_lib.abs(math_lib.nonRealPart(z)) > 1 then
		local inv_z = math_lib.inverse(z)
		return math_lib.sqrt((math_lib.pi * 2) * inv_z) * math_lib.pow(z * math_lib.exp(-1) *
			math_lib.sqrt( (z * math_lib.sinh(inv_z) ) + math_lib.inverse(to_number(810) * z * z * z * z * z * z) ),z)
	end
	return nil
end
function p._gamma_morethen_lua_int(cal_z)
	local z = to_number(cal_z) - to_number(1)
	local lua_int_term = 18.1169 --FindRoot[ Factorial[ x ] == 2 ^ 53, {x, 20} ]
	if math_lib.abs(z) > (lua_int_term - 1) or (math_lib.re(z) < 0 and math_lib.abs(math_lib.nonRealPart(z)) > 1 ) then
		local sum = 1
		for i = 1, #stirling_series_coeff - 1 do
			local a, n = to_number(z), tonumber(i) local y, k, f = to_number(1), n, to_number(a)
			while k ~= 0 do 
				if k % 2 == 1 then y = y * f end 
				k = math.floor(k / 2); f = f * f
			end
			sum = sum + stirling_series_coeff[i + 1] * math_lib.inverse(y)
		end
		return math_lib.sqrt( (2 * math.pi) * z ) * math_lib.pow( z * math.exp(-1), z ) * sum
	end
	return nil
end
function p._gamma_abs_less1(cal_z)
	local z = to_number(cal_z)
	if math_lib.abs(z) <=1.001 then
		if math_lib.abs(math_lib.nonRealPart(z)) < 1e-14 and ( (math.abs(math_lib.re(z) - 1) < 1e-14) or (math.abs(math_lib.re(z) - 2) < 1e-14) ) then return to_number(1)end
		return math_lib.inverse(p._recigamma_abs_less1(z))
	end
	return nil
end
function p._recigamma_abs_less1(z)
	local result = to_number(0)
	for i=1,#Reciprocal_gamma_coeff do
		result = result + Reciprocal_gamma_coeff[i] * math_lib.pow(z,i)
	end
	return result
end
function p._gamma(cal_z)
	local z = to_number(cal_z)
	if math_lib.abs(math_lib.nonRealPart(z)) < 1e-14 and ((math_lib.re(z) < 0 or math.abs(math_lib.re(z)) < 1e-14)
		and math.abs(math.floor(math_lib.re(z)) - math_lib.re(z)) < 1e-14 ) then return tonumber("nan") end
	local pre_result = p._gamma_morethen_lua_int(z) or p._gamma_high_imag(z) or p._gamma_abs_less1(z)
	if pre_result then return pre_result end
	local real_check = math_lib.re(z)
	local loop_count = math.floor(real_check)
	local start_number, zero_flag = z - loop_count, false
	if math_lib.abs(start_number) <= 1e-14 then start_number = to_number(1);zero_flag = true end
	local result = math_lib.inverse(p._recigamma_abs_less1(start_number))
	if math_lib.abs(math_lib.nonRealPart(z)) < 1e-14 and ((math_lib.re(z) > 1e-14 )and math.abs(math.floor(math_lib.re(z)) - math_lib.re(z)) < 1e-14 ) then result = to_number(1)  end
	local j = to_number(start_number)
	for i=1,math.abs(loop_count) do
		if loop_count > 0 then result = result * j else result = result * math_lib.inverse(j-1) end
		if zero_flag==true and loop_count > 0 then zero_flag=false else if loop_count > 0 then j = j + 1 else j = j - 1 end end
	end
	if math_lib.abs(math_lib.nonRealPart(z)) < 1e-14 and ((math_lib.re(z) > 1e-14 )and math.abs(math.floor(math_lib.re(z)) - math_lib.re(z)) < 1e-14 ) then return math_lib.floor(result) end
	return result
end
function p._gcd(...)
	local function findGcd(a, b)
		local r, oldr = to_number(b), to_number(a)
		while math_lib.abs(r) > 1e-6 do local mod_val = oldr % r oldr, r = to_number(r), mod_val end
		if math_lib.abs(math_lib.nonRealPart(oldr)) < 1e-14 and (math_lib.re(oldr) < 0 ) then oldr = -oldr end
		return oldr
	end
	local result, count = fold(findGcd, ...)
	return result
end

return p