跳转到内容

模組:Complex Number/Dual Number

本页使用了标题或全文手工转换
维基百科,自由的百科全书

p={}
local sollib = require("Module:Complex_Number/Solver")
local comp_lib = require("Module:Complex_Number")
local cmath = comp_lib.cmath.init()
local toCnumber = cmath.constructor
p.cmath = cmath
p.toCnumber = toCnumber
p.dumath={
	abs=function(z)
		local real, epsilon = p.dumath.readPart(z)
		if math.abs(epsilon) < 1e-12 then return math.abs(real) end
		return math.sqrt(real * real)
	end,
	floor=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.floor(real), math.floor(epsilon)) 
	end,
	ceil=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.ceil(real), math.ceil(epsilon)) 
	end,
	round=function(op1,op2,op3)
		local number = p.dumath.getDualNumber(tonumber(op1) or op1.real or 0, (tonumber(op1) and 0) or op1.epsilon or 0) 
		local digs = p.dumath.getDualNumber(tonumber(op2) or (op2 or {}).real or 0, (tonumber(op2) and 0) or (op2 or {}).epsilon or 0) 
		local base = p.dumath.getDualNumber(tonumber(op3) or (op3 or {}).real or 10, (tonumber(op3) and 0) or (op3 or {}).epsilon or 0) 
		local round_rad = p.dumath.pow(base,digs)
		local check_number = number * round_rad
		check_number.real = check_number.real + 0.5; check_number.epsilon = check_number.epsilon + 0.5; 
		return p.dumath.floor( check_number ) / round_rad
	end,
	div=function(op1,op2)return op1 / op2 end,
	re=function(z)return tonumber(z) or z.real end,
	im=function(z) return (tonumber(z) and 0) or z.epsilon end,
	nonRealPart=function(z) return p.dumath.getDualNumber(0, (tonumber(z) and 0) or z.epsilon) end,
	conjugate=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return p.dumath.getDualNumber(real, -epsilon)
	end,
	inverse=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return p.dumath.getDualNumber(1/real, -epsilon/(real*real))
	end,
	tovector=function(z)
		return {p.dumath.readPart(z)}
	end,
	trunc=function(z,digs)
		local real, epsilon = p.dumath.readPart(z)
		local n = tonumber(digs) or digs.real or 0
		return p.dumath.getDualNumber(sollib._trunc(real,n), sollib._trunc(epsilon,n))
	end,
	digits=function(z)
		local real, epsilon = p.dumath.readPart(z)
		real, epsilon = math.floor(math.abs(real)), math.floor(math.abs(epsilon))
		return math.max(tostring(real):len(),tostring(epsilon):len())
	end,
	sqrt=function(z)
		local real, epsilon = p.dumath.readPart(z)
		if epsilon == 0 then return p.dumath.getDualNumber(math.sqrt(real),0):clean()end
		if real ~= 0 then
			local sqrt_real = math.sqrt(real)
			return p.dumath.getDualNumber(sqrt_real, epsilon / (2 * sqrt_real))
		end
		return p.dumath.pow(z,0.5)
	end,

	sin=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.sin(real), epsilon * math.cos(real)) 
	end,
	cos=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.cos(real), -epsilon * math.sin(real)) 
	end,
	tan=function(z)
		local real, epsilon = p.dumath.readPart(z)
		local sec = 1 / math.cos(real)
		return p.dumath.getDualNumber(math.tan(real), epsilon * sec * sec) 
	end,
	cot=function(z)
		local real, epsilon = p.dumath.readPart(z)
		local csc = 1 / math.sin(real)
		return p.dumath.getDualNumber(1 / math.tan(real), -epsilon * csc * csc) 
	end,

	asin=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.asin(a), b / math.sqrt(1-a*a)) 
	end,
	acos=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.acos(a), -b / math.sqrt(1-a*a)) 
	end,
	atan=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.atan(a), b / (1+a*a)) 
	end,
	acot=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.atan(1/a), -b / (1+a*a)) 
	end,

	sinh=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.sinh(a), b * math.cosh(real)) 
	end,
	cosh=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.cosh(a), b * math.sinh(real)) 
	end,
	tanh=function(z)
		local a, b = p.dumath.readPart(z)
		local sech = 1 / math.cosh(a)
		return p.dumath.getDualNumber(math.tanh(a), b * sech * sech) 
	end,
	coth=function(z)
		local a, b = p.dumath.readPart(z)
		local csch = 1 / math.sinh(a)
		return p.dumath.getDualNumber(1 / math.tanh(a), -b * csch * csch) 
	end,

	asinh=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.asinh(a), b / math.sqrt(1+a*a)) 
	end,
	acosh=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.acosh(a), b / math.sqrt(a*a-1)) 
	end,
	atanh=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.atanh(a), b / (1-a*a)) 
	end,
	acoth=function(z)
		local a, b = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.atanh(1/a), b / (1-a*a)) 
	end,

	dot=function (op1, op2)
		local real1, epsilon1 = p.dumath.readPart(op1)
		local real2, epsilon2 = p.dumath.readPart(op2)
		return real1 * real2 + epsilon1 * epsilon2 
	end,
	sgn=function(z)
		local real, epsilon = p.dumath.readPart(z)
		if real == 0 and epsilon == 0 then return p.dumath.getDualNumber(0, 0) end
		local length = math.sqrt( real * real )
		return p.dumath.getDualNumber(real/length, epsilon/length)
	end,
	arg=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return epsilon / real 
	end,
	exp=function(z)
		local real, epsilon = p.dumath.readPart(z)
		local exp_r = math.exp(real)
		return p.dumath.getDualNumber(exp_r, epsilon*exp_r)
	end,
	elog=function(z)
		local real, epsilon = p.dumath.readPart(z)
		return p.dumath.getDualNumber(math.log(real), epsilon/real)
	end,
	log=function(z,basez)
		if basez~=nil then return p.dumath.elog(basez) * p.dumath.inverse(p.dumath.elog(z)) end
		return p.dumath.elog(z)
	end,
	pow=function(op1,op2)
		local check_op1, check_op2 = tonumber(tostring(op1)) or -1, tonumber(tostring(op2)) or -1
		if check_op1 == 1 then return p.dumath.getDualNumber(1,0) end -- 1^z === 1
		if check_op2 == 1 then return op1 end -- z^1 === z
		if check_op2 == 0 then -- z^0
			if check_op1 ~= 0 then return p.dumath.getDualNumber(1,0) -- z^0 === 1, z ≠ 0
			else return p.dumath.getDualNumber(tonumber('nan'),0) end -- 0^0 Indeterminate
		elseif check_op1 == 0 then 
			if check_op2 < 0 then return p.dumath.getDualNumber(tonumber('inf'),0) end -- 0^(-n) Infinity
			return p.dumath.getDualNumber(0,0) -- 0^z === 0, z ≠ 0
		end
			
		local a, b = p.dumath.readPart(op1)
		local ka, kb = p.dumath.readPart(op2)
		if math.abs(a) < 1e-14 and math.abs(b) > 1e-14 then
			if check_op2 == 0 then return p.dumath.getDualNumber(1,0)
			elseif check_op2 == 1 then return p.dumath.getDualNumber(0,1)
			else return p.dumath.getDualNumber(0,0) --Nilpotent
			end
		end
		return p.dumath.getDualNumber(math.pow(a,ka), kb*(math.pow(a,ka)*math.log(a))+b*ka*math.pow(a,ka-1))
		--a ^ z
		--local a = p.dumath.getDualNumber( tonumber(op1) or op1.real, (tonumber(op1) and 0) or op1.epsilon )
		--local z = p.dumath.getDualNumber( tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.epsilon )
		--return p.dumath.exp(z * p.dumath.log(a)):clean()
	end,
	random = function (op1, op2)
		if type(op1)==type(nil) and type(op2)==type(nil) then return p.dumath.getDualNumber(math.random(),0) end
			local real1, real2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
			local epsilon1, epsilon2 = (tonumber(op1) and 0) or (op1 or {}).epsilon, (tonumber(op2) and 0) or (op2 or {}).epsilon
		if type(op2)==type(nil) then return p.dumath.getDualNumber(sollib._random(real1), sollib._random(epsilon1)) end
		return p.dumath.getDualNumber(sollib._random(math.min(real1,real2), math.max(real1,real2)), sollib._random(math.min(epsilon1,epsilon2), math.max(epsilon1,epsilon2))) 
	end,

	isReal=function(z) return math.abs(p.dumath.nonRealPart(z).epsilon or 0) < 1e-14 end,
	
	DualNumberMeta = {
		__add = function (op1, op2) 
			local real1, real2 = tonumber(op1) or op1.real, tonumber(op2) or op2.real
			local epsilon1, epsilon2 = (tonumber(op1) and 0) or op1.epsilon, (tonumber(op2) and 0) or op2.epsilon
			return p.dumath.getDualNumber(real1 + real2, epsilon1 + epsilon2) 
		end,
		__sub = function (op1, op2) 
			local real1, real2 = tonumber(op1) or op1.real, tonumber(op2) or op2.real
			local epsilon1, epsilon2 = (tonumber(op1) and 0) or op1.epsilon, (tonumber(op2) and 0) or op2.epsilon
			return p.dumath.getDualNumber(real1 - real2, epsilon1 - epsilon2) 
		end,
		__mul = function (op1, op2) 
			local a, c = tonumber(op1) or op1.real, tonumber(op2) or op2.real
			local b, d = (tonumber(op1) and 0) or op1.epsilon, (tonumber(op2) and 0) or op2.epsilon
			return p.dumath.getDualNumber(a * c, a * d + b * c) 
		end,
		__div = function (op1, op2) 
			local a, c = tonumber(op1) or op1.real, tonumber(op2) or op2.real
			local b, d = (tonumber(op1) and 0) or op1.epsilon, (tonumber(op2) and 0) or op2.epsilon
			return p.dumath.getDualNumber(a/c, (b * c - a * d) / (c*c)) 
		end,
		__mod = function (op1, op2) 
			local x = p.dumath.getDualNumber(tonumber(op1) or op1.real, (tonumber(op1) and 0) or op1.epsilon)
			local y = p.dumath.getDualNumber(tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.epsilon) 
			return x - y * p.dumath.floor(x / y) 
		end,
		__tostring = function (this) 
			local body = ''
			if this.real ~= 0 then body = tostring(this.real) end
			if this.epsilon ~= 0 then 
				if body ~= '' and this.epsilon > 0 then body = body .. '+' end
				if this.epsilon == -1 then  body = body .. '-' end
				if math.abs(this.epsilon) ~= 1 then body = body .. tostring(this.epsilon) end
				body = body .. 'ε'
			end
			if sollib._isNaN(this.real) or sollib._isNaN(this.epsilon) then body = 'nan' end
			if body == '' then body = '0' end
			return body
		end,
		__unm = function (this)
			return p.dumath.getDualNumber(-this.real, -this.epsilon) 
		end,
		__eq = function (op1, op2)
			local diff_real = math.abs( (tonumber(op1) or op1.real) - (tonumber(op2) or op2.real) )
			local diff_epsilon1 = math.abs( ( (tonumber(op1) and 0) or op1.epsilon) - ( (tonumber(op2) and 0) or op2.epsilon) )
			return diff_real < 1e-12 and diff_epsilon1 < 1e-12
		end,
	},
	readDualNumber = function(z)
		if type(z) == type({}) then --if already be complex number, don't run string find.
			if z.numberType == "dualnumber" then
				return z
			elseif z.numberType == "complex" then
				return p.dumath.getDualNumber(z.real, 0)
			elseif z.numberType == "quaternion" then
				return p.dumath.getDualNumber(z.real, 0)
			end
		elseif type(z) == type(0) then
			return p.dumath.getDualNumber(z, 0)
		elseif type(z) == type(true) then
			return p.dumath.getDualNumber(z and 1 or 0, 0)
		end
		return p.dumath.getDualNumber(tonumber(z) or z.real, (tonumber(z) and 0) or z.epsilon)
	end,
	readPart = function(z)
		if type(z) == type({}) and (z.numberType == "dualnumber") then --if already be dual number, don't run string find.
			return z.real, z.epsilon
		elseif type(z) == type({}) and (z.numberType == "complex" or z.numberType == "quaternion") then --if already be complex number, don't run string find.
			return z.real, 0
		elseif type(z) == type(0) then
			return z, 0
		elseif type(z) == type(true) then
			return z and 1 or 0, 0
		end
		return tonumber(z) or z.real, (tonumber(z) and 0) or z.epsilon or 0
	end,
	ele=function(id)
		local _zero = p.dumath.getDualNumber(0, 0)
		local eles = (p.dumath.elements or {})
		local id_msg = tonumber(tostring(id)) or 0
		return eles[id_msg+1]or _zero
	end,
	getDualNumber = function(real,epsilon)
		local DualNumber = {}
		setmetatable(DualNumber,p.dumath.DualNumberMeta) 
		function DualNumber:update()
			self.argument = 0
			self.length = math.sqrt( self.real * self.real )
			if self.epsilon ~= 0 then
				self.argument = self.epsilon / self.real
			else
				if self.real > 0 then self.argument = 0.0 
				else self.argument = math.pi end
			end
		end
		function DualNumber:clean()
			if math.abs(self.real) <= 1e-12 then self.real = 0 end
			if math.abs(self.epsilon) <= 1e-12 then self.epsilon = 0 end
			if math.abs(self.real - math.floor(self.real)) <= 1e-12 then self.real = math.floor(self.real) end
			if math.abs(self.epsilon - math.floor(self.epsilon)) <= 1e-12 then self.epsilon = math.floor(self.epsilon) end
			return self
		end
		DualNumber.real, DualNumber.epsilon = real, epsilon
		DualNumber.numberType = "dualnumber"
		return DualNumber
	end,
	toDualNumber = function(num_str)
		if type(num_str) == type({}) then --if already be dual number, don't run string find.
			if num_str.numberType == "dualnumber" then
				return num_str
			elseif num_str.numberType == "complex" then
				return p.dumath.getDualNumber(num_str.real, 0)
			elseif num_str.numberType == "quaternion" then
				return p.dumath.getDualNumber(num_str.real, 0)
			end
		elseif type(num_str) == type(0) then
			return p.dumath.getDualNumber(num_str, 0)
		elseif type(num_str) == type(true) then
			return p.dumath.getDualNumber(num_str and 1 or 0, 0)
		elseif type(num_str) == type("string") then
			local check_number = tonumber(num_str)
			if check_number ~= nil then return p.dumath.getDualNumber(check_number, 0) end
		end
		local real, epsilon
		if num_str == nil then return nil end
		if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then
			real, epsilon = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.epsilon
		else real, epsilon = p.dumath.toDualNumberPart(num_str)end
		if real == nil or epsilon == nil then return nil end
		return p.dumath.getDualNumber(real, epsilon)
	end,
	toDualNumberPart = function(num_str)
		if type(num_str) == type(function()end) then return end
		if type(num_str) == type(true) then if num_str then return 1,0 else return 0,0 end end

		local body = ''
		local real, epsilon = 0, 0
		local split_str = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(
				mw.ustring.gsub(num_str or '','(%d)%s*%*%s*([ε])','%1%2'),
			'%s+',''),'%++([%d%.])',',+%1'),'%++([ε])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ε])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ε])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ε])',',/1%1'),',')
		local first = true
		local continue = false
		for k,v in pairs(split_str) do
			continue = false
			local val = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.text.trim(v),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ε]+)','+1%1')
			if mw.ustring.find(val,"%/") or mw.ustring.find(val,"%*") then return end

			if val == nil or val == '' then if first == true then first = false continue = true else return end end
			if not continue then
				local num_text = mw.ustring.match(val,"[%+%-][%d%.]+[ε]*")
				if num_text ~= val then return end
				local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
				if num_part == nil then return end
				local f_start, f_end = mw.ustring.find(num_text,"[ε]+")
				local part_str = ''
				if f_start then part_str = mw.ustring.sub(num_text, f_start, f_end) end
				
				if part_str == "" then real = real + num_part -- +1.0
				elseif part_str == "ε" then epsilon = epsilon + num_part -- +ε
				end
			end
		end
		return real, epsilon
	end,
	init = function()
		p.dumath.e = p.dumath.getDualNumber(math.exp(1), 0)
		p.dumath.pi = p.dumath.getDualNumber(math.pi, 0)
		p.dumath["π"] = p.dumath.getDualNumber(math.pi, 0)
		p.dumath["°"] = p.dumath.getDualNumber(math.pi/180, 0)
		p.dumath.nan = p.dumath.getDualNumber(tonumber("nan"), tonumber("nan"))
		p.dumath.zero = p.dumath.getDualNumber(0, 0)
		p.dumath.one = p.dumath.getDualNumber(1, 0)
		p.dumath[-1] = p.dumath.getDualNumber(-1, 0)
		p.dumath["ε"] = p.dumath.getDualNumber(0, 1)
		p.dumath.epsilon = p.dumath.getDualNumber(0, 1)
		p.dumath[0],p.dumath[1] = p.dumath.zero,p.dumath.one
		p.dumath.numberType = sollib._numberType
		p.dumath.constructor = p.dumath.toDualNumber
		p.dumath.elements = {
			p.dumath.getDualNumber(1, 0),
			p.dumath.getDualNumber(0, 1)
		}
		return p.dumath
	end

}
p.ducmath={
	abs=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		local A, B, C, D = non_epsilon.real, non_epsilon.imag, epsilon.real, epsilon.imag
		return A * A + B * B
	end,
	floor=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.floor(non_epsilon), cmath.floor(epsilon)) 
	end,
	ceil=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.ceil(non_epsilon), cmath.ceil(epsilon)) 
	end,
	round=function(op1,op2,op3)
		local number = p.ducmath.getDualComplexNumber(toCnumber(op1) or op1.non_epsilon or 0, (toCnumber(op1) and 0) or op1.epsilon or 0) 
		local digs = p.ducmath.getDualComplexNumber(toCnumber(op2) or (op2 or {}).non_epsilon or 0, (toCnumber(op2) and 0) or (op2 or {}).epsilon or 0) 
		local base = p.ducmath.getDualComplexNumber(toCnumber(op3) or (op3 or {}).non_epsilon or 10, (toCnumber(op3) and 0) or (op3 or {}).epsilon or 0) 
		local round_rad = p.ducmath.pow(base,digs)
		local check_number = number * round_rad
		check_number.non_epsilon = check_number.non_epsilon + 0.5; check_number.epsilon = check_number.epsilon + 0.5; 
		return p.ducmath.floor( check_number ) / round_rad
	end,
	div=function(op1,op2)return op1 / op2 end,
	re=function(z)return cmath.re(toCnumber(z) or z.non_epsilon) end,
	im=function(z) return cmath.im(toCnumber(z) or z.non_epsilon) end,
	nonRealPart=function(z) return p.ducmath.getDualComplexNumber(cmath.nonRealPart(toCnumber(z) or z.non_epsilon), (toCnumber(z) and 0) or z.epsilon) end,
	conjugate=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.conjugate(non_epsilon), -epsilon)
	end,
	inverse=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		local A, B, C, D = non_epsilon.real, non_epsilon.imag, epsilon.real, epsilon.imag
		local len = A * A + B * B
		return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(
			A/len, 
			-B/len), cmath.getComplexNumber(
			-C/len, 
			-D/len))
	end,
	tovector=function(z)
		return {p.ducmath.readPart(z)}
	end,
	trunc=function(z,digs)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		local n = toCnumber(digs) or digs.non_epsilon or cmath.getComplexNumber(0, 0)
		return p.ducmath.getDualComplexNumber(sollib._trunc(non_epsilon,n), sollib._trunc(epsilon,n))
	end,
	digits=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		non_epsilon, epsilon = cmath.floor(cmath.abs(non_epsilon)), cmath.floor(cmath.abs(epsilon))
		return cmath.max(tostring(non_epsilon):len(),tostring(epsilon):len())
	end,
	sqrt=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		if epsilon == cmath.getComplexNumber(0, 0) then return p.ducmath.getDualComplexNumber(cmath.sqrt(non_epsilon),cmath.getComplexNumber(0, 0)):clean()end
		if non_epsilon ~= cmath.getComplexNumber(0, 0) then
			local sqrt_non_epsilon = cmath.sqrt(non_epsilon)
			return p.ducmath.getDualComplexNumber(sqrt_non_epsilon, epsilon / (2 * sqrt_non_epsilon))
		end
		return p.ducmath.pow(z,cmath.getComplexNumber(0.5, 0))
	end,

	sin=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.sin(non_epsilon), epsilon * cmath.cos(non_epsilon)) 
	end,
	cos=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.cos(non_epsilon), -epsilon * cmath.sin(non_epsilon)) 
	end,
	tan=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		local sec = 1 / cmath.cos(non_epsilon)
		return p.ducmath.getDualComplexNumber(cmath.tan(non_epsilon), epsilon * sec * sec) 
	end,
	cot=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		local csc = cmath.getComplexNumber(1, 0) / cmath.sin(non_epsilon)
		return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(1, 0) / cmath.tan(non_epsilon), -epsilon * csc * csc) 
	end,

	asin=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.asin(a), b / cmath.sqrt(cmath.getComplexNumber(1, 0)-a*a)) 
	end,
	acos=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.acos(a), -b / cmath.sqrt(cmath.getComplexNumber(1, 0)-a*a)) 
	end,
	atan=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.atan(a), b / (cmath.getComplexNumber(1, 0)+a*a)) 
	end,
	acot=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.atan(cmath.getComplexNumber(1, 0)/a), -b / (cmath.getComplexNumber(1, 0)+a*a)) 
	end,

	sinh=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.sinh(a), b * cmath.cosh(non_epsilon)) 
	end,
	cosh=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.cosh(a), b * cmath.sinh(non_epsilon)) 
	end,
	tanh=function(z)
		local a, b = p.ducmath.readPart(z)
		local sech = cmath.getComplexNumber(1, 0) / cmath.cosh(a)
		return p.ducmath.getDualComplexNumber(cmath.tanh(a), b * sech * sech) 
	end,
	coth=function(z)
		local a, b = p.ducmath.readPart(z)
		local csch = cmath.getComplexNumber(1, 0) / cmath.sinh(a)
		return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(1, 0) / cmath.tanh(a), -b * csch * csch) 
	end,

	asinh=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.asinh(a), b / cmath.sqrt(cmath.getComplexNumber(1, 0)+a*a)) 
	end,
	acosh=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.acosh(a), b / cmath.sqrt(a*a-cmath.getComplexNumber(1, 0))) 
	end,
	atanh=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.atanh(a), b / (cmath.getComplexNumber(1, 0)-a*a)) 
	end,
	acoth=function(z)
		local a, b = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.atanh(cmath.getComplexNumber(1, 0)/a), b / (cmath.getComplexNumber(1, 0)-a*a)) 
	end,

	dot=function (op1, op2)
		local non_epsilon1, epsilon1 = p.ducmath.readPart(op1)
		local non_epsilon2, epsilon2 = p.ducmath.readPart(op2)
		return non_epsilon1 * non_epsilon2 + epsilon1 * epsilon2 
	end,
	sgn=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		if non_epsilon == 0 and epsilon == 0 then return p.ducmath.getDualComplexNumber(0, 0) end
		local length = cmath.sqrt( non_epsilon * non_epsilon )
		return p.ducmath.getDualComplexNumber(non_epsilon/length, epsilon/length)
	end,
	arg=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		return epsilon / non_epsilon 
	end,
	exp=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		local exp_r = cmath.exp(non_epsilon)
		return p.ducmath.getDualComplexNumber(exp_r, epsilon*exp_r)
	end,
	elog=function(z)
		local non_epsilon, epsilon = p.ducmath.readPart(z)
		return p.ducmath.getDualComplexNumber(cmath.log(non_epsilon), epsilon/non_epsilon)
	end,
	log=function(z,basez)
		if basez~=nil then return p.ducmath.elog(basez) * p.ducmath.inverse(p.ducmath.elog(z)) end
		return p.ducmath.elog(z)
	end,
	pow=function(op1,op2)
		local check_op1, check_op2 = toCnumber(tostring(op1)) or cmath.getComplexNumber(-1, 0), toCnumber(tostring(op2)) or cmath.getComplexNumber(-1, 0)
		if check_op1 == cmath.getComplexNumber(1, 0) then return p.ducmath.getDualComplexNumber(1,0) end -- 1^z === 1
		if check_op2 == cmath.getComplexNumber(1, 0) then return op1 end -- z^1 === z
		if check_op2 == cmath.getComplexNumber(0, 0) then -- z^0
			if check_op1 ~= cmath.getComplexNumber(0, 0) then return p.ducmath.getDualComplexNumber(1,0) -- z^0 === 1, z ≠ 0
			else return p.ducmath.getDualComplexNumber(toCnumber('nan'), 0) end -- 0^0 Indeterminate
		elseif check_op1 == cmath.getComplexNumber(0, 0) then 
			if cmath.re(check_op2) < 0 then return p.ducmath.getDualComplexNumber(toCnumber('inf'),0) end -- 0^(-n) Infinity
			return p.ducmath.getDualComplexNumber(0, 0) -- 0^z === 0, z ≠ 0 
		end
			
		local a, b = p.ducmath.readPart(op1)
		local ka, kb = p.ducmath.readPart(op2)
		if cmath.abs(a) < 1e-14 and cmath.abs(b) > 1e-14 then
			if check_op2 == cmath.getComplexNumber(0, 0) then return p.ducmath.getDualComplexNumber(1,0)
			elseif check_op2 == cmath.getComplexNumber(1, 0)then return p.ducmath.getDualComplexNumber(0,1)
			else return p.ducmath.getDualComplexNumber(0,0) --Nilpotent
			end
		end
		return p.ducmath.getDualComplexNumber(cmath.pow(a,ka), kb*(cmath.pow(a,ka)*cmath.log(a))+b*ka*cmath.pow(a,ka-1))
		--a ^ z
		--local a = p.ducmath.getDualComplexNumber( toCnumber(op1) or op1.non_epsilon, (toCnumber(op1) and 0) or op1.epsilon )
		--local z = p.ducmath.getDualComplexNumber( toCnumber(op2) or op2.non_epsilon, (toCnumber(op2) and 0) or op2.epsilon )
		--return p.ducmath.exp(z * p.ducmath.log(a)):clean()
	end,
	random = function (op1, op2)
		if type(op1)==type(nil) and type(op2)==type(nil) then return p.ducmath.getDualComplexNumber(cmath.random(), cmath.getComplexNumber(0, 0)) end
		local a, b = p.ducmath.readPart(op1)
		if type(op2)==type(nil) then return p.ducmath.getDualComplexNumber(cmath.random(a), cmath.random(b)) end
		local c, d = p.ducmath.readPart(op2)
		return p.ducmath.getDualComplexNumber(cmath.random(a, c), cmath.random(b, d))
	end,
	isReal=function(z) 
		local nonReal = p.ducmath.nonRealPart(z)
		return (cmath.abs(nonReal.non_epsilon) + cmath.abs(nonReal.epsilon)) < 1e-14 
	end,
	
	DualComplexNumberMeta = {
		__add = function (op1, op2) 
			local a, b = p.ducmath.readPart(op1)
			local c, d = p.ducmath.readPart(op2)
			return p.ducmath.getDualComplexNumber(a + c, b + d) 
		end,
		__sub = function (op1, op2) 
			local a, b = p.ducmath.readPart(op1)
			local c, d = p.ducmath.readPart(op2)
			return p.ducmath.getDualComplexNumber(a - c, b - d) 
		end,
		__mul = function (op1, op2) 
			local A, B = p.ducmath.readPart(op1)
			local C, D = p.ducmath.readPart(op2)
			local a1, a2 = (type(A)==type(0)) and A or(A.real or tonumber(tostring(A)) or 0) or 0, ((type(A)==type(0))and 0) or A.imag or 0
			local a3, a4 = (type(B)==type(0)) and B or(B.real or tonumber(tostring(B)) or 0) or 0, ((type(B)==type(0))and 0) or B.imag or 0
			local b1, b2 = (type(C)==type(0)) and C or(C.real or tonumber(tostring(C)) or 0) or 0, ((type(C)==type(0))and 0) or C.imag or 0
			local b3, b4 = (type(D)==type(0)) and D or(D.real or tonumber(tostring(D)) or 0) or 0, ((type(D)==type(0))and 0) or D.imag or 0
			return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(a1*b1-a2*b2,a2*b1+a1*b2, a2*b1+a1*b2), cmath.getComplexNumber(a3*b1+a4*b2+a1*b3-a2*b4, a4*b1-a3*b2+a2*b3+a1*b4)) 
		end,
		__div = function (op1, op2) 
			local o1 = p.ducmath.getDualComplexNumber(p.ducmath.readPart(op1))
			local o2 = p.ducmath.getDualComplexNumber(p.ducmath.readPart(op2))
			return o1 * p.ducmath.inverse(o2)
		end,
		__mod = function (op1, op2) 
			local x = p.ducmath.getDualComplexNumber(p.ducmath.readPart(op1)) 
			local y = p.ducmath.getDualComplexNumber(p.ducmath.readPart(op2)) 
			return x - y * p.ducmath.floor(x / y) 
		end,
		__tostring = function (this) 
			local body = ''
			local non_epsilon, epsilon = p.ducmath.readPart(this)
			local body = ''
			if non_epsilon.real ~= 0 then body = tostring(non_epsilon.real) end
			if non_epsilon.imag ~= 0 then 
				if body ~= '' and non_epsilon.imag > 0 then body = body .. '+' end
				if non_epsilon.imag == -1 then  body = body .. '-' end
				if math.abs(non_epsilon.imag) ~= 1 then body = body .. tostring(non_epsilon.imag) end
				body = body .. 'i'
			end
			if this.mathform then
				if epsilon.real ~= 0 then 
					if body ~= '' and epsilon.real > 0 then body = body .. '+' end
					if epsilon.real == -1 then  body = body .. '-' end
					if math.abs(epsilon.real) ~= 1 then body = body .. tostring(epsilon.real) end
					body = body .. 'εj'
				end
				if epsilon.imag ~= 0 then 
					if body ~= '' and epsilon.imag > 0 then body = body .. '+' end
					if epsilon.imag == -1 then  body = body .. '-' end
					if math.abs(epsilon.imag) ~= 1 then body = body .. tostring(epsilon.imag) end
					body = body .. 'εk'
				end
			else
				if epsilon.real ~= 0 then 
					if body ~= '' and epsilon.real > 0 then body = body .. '+' end
					if epsilon.real == -1 then  body = body .. '-' end
					if math.abs(epsilon.real) ~= 1 then body = body .. tostring(epsilon.real) end
					body = body .. 'ε'
				end
				if epsilon.imag ~= 0 then 
					if body ~= '' and epsilon.imag > 0 then body = body .. '+' end
					if epsilon.imag == -1 then  body = body .. '-' end
					if math.abs(epsilon.imag) ~= 1 then body = body .. tostring(epsilon.imag) end
					body = body .. 'iε'
				end
			end
		
			if sollib._isNaN(non_epsilon.real) or sollib._isNaN(non_epsilon.imag) or sollib._isNaN(epsilon.real) or sollib._isNaN(epsilon.imag) then body = 'nan' end
			if body == '' then body = '0' end
			return body

		end,
		__unm = function (this)
			return p.ducmath.getDualComplexNumber(-this.non_epsilon, -this.epsilon) 
		end,
		__eq = function (op1, op2)
			local diff_non_epsilon = cmath.abs( (toCnumber(op1) or op1.non_epsilon) - (toCnumber(op2) or op2.non_epsilon) )
			local diff_epsilon1 = cmath.abs( ( (toCnumber(op1) and 0) or op1.epsilon) - ( (toCnumber(op2) and 0) or op2.epsilon) )
			return diff_non_epsilon < 1e-12 and diff_epsilon1 < 1e-12
		end,
	},
	mathform = function(z)
		if type(z) == type({}) then if z.numberType == "dualcomplex" then result = z
		elseif z.numberType == "dualnumber" then result = p.ducmath.getDualComplexNumber(z, 0)
		elseif z.numberType == "complex" then result = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(z.real, z.imag), 0)
		elseif z.numberType == "quaternion" then result = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(z.real, z.imag), 0)end
		elseif type(z) == type(0) then result = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(z, 0), 0) end
		result.mathform = true
		return result
	end,
	readDualComplexNumber = function(z)
		if type(z) == type({}) then --if already be complex number, don't run string find.
			if z.numberType == "dualcomplex" then
				return z
			elseif z.numberType == "dualnumber" then
				return p.ducmath.getDualComplexNumber(z, 0)
			elseif z.numberType == "complex" then
				return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(z.real, z.imag), 0)
			elseif z.numberType == "quaternion" then
				return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(z.real, z.imag), 0)
			end
		elseif type(z) == type(0) then
			return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(z, 0), 0)
		elseif type(z) == type(true) then
			return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(z and 1 or 0, 0), 0)
		end
		return p.ducmath.getDualComplexNumber(toCnumber(z) or z.non_epsilon, (toCnumber(z) and 0) or z.epsilon)
	end,
	readPart = function(z)
		if type(z) == type({}) and (z.numberType == "dualcomplex") then --if already be dual number, don't run string find.
			return toCnumber(z.non_epsilon), toCnumber(z.epsilon)
		elseif type(z) == type({}) and (z.numberType == "dualnumber") then --if already be dual number, don't run string find.
			return z, cmath.getComplexNumber(0, 0)
		elseif type(z) == type({}) and (z.numberType == "complex" or z.numberType == "quaternion") then --if already be complex number, don't run string find.
			return cmath.getComplexNumber(z.real, z.imag), cmath.getComplexNumber(0, 0)
		elseif type(z) == type(0) then
			return cmath.getComplexNumber(z, 0), cmath.getComplexNumber(0, 0)
		elseif type(z) == type(true) then
			return cmath.getComplexNumber(z and 1 or 0, 0), cmath.getComplexNumber(0, 0)
		end
		return cmath.getComplexNumber(toCnumber(z) or z.non_epsilon, (toCnumber(z) and 0) or z.epsilon or 0), cmath.getComplexNumber(0, 0)
	end,
	ele=function(id)
		local _zero = p.ducmath.getDualComplexNumber(0, 0)
		local eles = (p.ducmath.elements or {})
		local id_msg = tonumber(tostring(id)) or 0
		return eles[id_msg+1]or _zero
	end,
	getDualComplexNumber = function(non_epsilon,epsilon)
		local DualComplexNumber = {}
		setmetatable(DualComplexNumber,p.ducmath.DualComplexNumberMeta) 
		function DualComplexNumber:update()
			self.argument = 0
			self.length = cmath.sqrt( self.non_epsilon * self.non_epsilon )
			if self.epsilon ~= 0 then
				self.argument = self.epsilon / self.non_epsilon
			else
				if self.non_epsilon > 0 then self.argument = 0.0 
				else self.argument = cmath.pi end
			end
		end
		function DualComplexNumber:clean()
			if cmath.abs(self.non_epsilon) <= 1e-12 then self.non_epsilon = 0 end
			if cmath.abs(self.epsilon) <= 1e-12 then self.epsilon = 0 end
			if cmath.abs(self.non_epsilon - cmath.floor(self.non_epsilon)) <= 1e-12 then self.non_epsilon = cmath.floor(self.non_epsilon) end
			if cmath.abs(self.epsilon - cmath.floor(self.epsilon)) <= 1e-12 then self.epsilon = cmath.floor(self.epsilon) end
			return self
		end
		DualComplexNumber.non_epsilon, DualComplexNumber.epsilon = non_epsilon, epsilon
		DualComplexNumber.numberType = "dualcomplex"
		return DualComplexNumber
	end,
	toDualComplexNumber = function(num_str)
		if type(num_str) == type({}) then --if already be dual number, don't run string find.
			if num_str.numberType == "dualcomplex" then
				return num_str
			elseif num_str.numberType == "dualnumber" then
				return p.ducmath.getDualComplexNumber(num_str, 0)
			elseif num_str.numberType == "complex" then
				return p.ducmath.getDualComplexNumber(num_str, 0)
			elseif num_str.numberType == "quaternion" then
				return p.ducmath.getDualComplexNumber(toCnumber(num_str.real, num_str.imag), 0)
			end
		elseif type(num_str) == type(0) then
			return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(num_str, 0), 0)
		elseif type(num_str) == type(true) then
			return p.ducmath.getDualComplexNumber(cmath.getComplexNumber(num_str and 1 or 0, 0), 0)
		elseif type(num_str) == type("string") then
			local check_number = toCnumber(num_str)
			if check_number ~= nil then return p.ducmath.getDualComplexNumber(check_number, 0) end
		end
		local non_epsilon, epsilon
		if num_str == nil then return nil end
		if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.non_epsilon)==type(0) ) ) then
			non_epsilon, epsilon = toCnumber(num_str) or num_str.non_epsilon, (toCnumber(num_str) and 0) or num_str.epsilon
		else non_epsilon, epsilon = p.ducmath.toDualComplexNumberPart(num_str)end
		if non_epsilon == nil or epsilon == nil then return nil end
		return p.ducmath.getDualComplexNumber(non_epsilon, epsilon)
	end,
	toDualComplexNumberPart = function(num_str)
		if type(num_str) == type(function()end) then return end
		if type(num_str) == type(true) then if num_str then return 1,0,0,0 else return 0,0,0,0 end end
		
		local body = ''
		local real, imag, re_epsilon, im_epsilon = 0, 0, 0, 0
		local split_str = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(
				mw.ustring.gsub(num_str or '','(%d)%s*%*%s*([ijkε])','%1%2'),
			'%s+',''),'%++([%d%.])',',+%1'),'%++([ijkε])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijkε])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijkε])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijkε])',',/1%1'),',')
		local first = true
		local continue = false
		for k,v in pairs(split_str) do
			continue = false
			local val = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.text.trim(v),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ijkε]+)','+1%1')
			if mw.ustring.find(val,"%/") or mw.ustring.find(val,"%*") then return end

			if val == nil or val == '' then if first == true then first = false continue = true else return end end
			if not continue then
				local num_text = mw.ustring.match(val,"[%+%-][%d%.]+[ijkε]*")
				if num_text ~= val then return end
				local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
				if num_part == nil then return end
				local f_start, f_end = mw.ustring.find(num_text,"[ijkε]+")
				local part_str = ''
				if f_start then part_str = mw.ustring.sub(num_text, f_start, f_end) end
				
				if part_str == "" then real = real + num_part -- +1.0
				elseif part_str == "i" then imag = imag + num_part -- +i
				elseif part_str == "ε" then re_epsilon = re_epsilon + num_part -- +j

				elseif part_str == "iε" then im_epsilon = im_epsilon + num_part -- +iε == +iε
				elseif part_str == "εj" then im_epsilon = im_epsilon + num_part -- +εj == +ε
				elseif part_str == "εk" then re_epsilon = re_epsilon + num_part -- +εk == +iε
				elseif part_str == "εi" then im_epsilon = im_epsilon - num_part -- +εi == -iε
				end
			end
		end
		return cmath.getComplexNumber(real, imag), cmath.getComplexNumber(re_epsilon, im_epsilon)
	end,
	init = function()
		p.ducmath.e = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(math.exp(1), 0), cmath.getComplexNumber(0, 0))
		p.ducmath.pi = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(math.pi, 0), cmath.getComplexNumber(0, 0))
		p.ducmath["π"] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(math.pi, 0), cmath.getComplexNumber(0, 0))
		p.ducmath["°"] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(math.pi/180, 0), cmath.getComplexNumber(0, 0))
		p.ducmath.nan = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(toCnumber("nan"), toCnumber("nan")), cmath.getComplexNumber(toCnumber("nan"), toCnumber("nan")))
		p.ducmath.zero = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(0, 0))
		p.ducmath.one = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(1, 0), cmath.getComplexNumber(0, 0))
		p.ducmath[-1] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(-1, 0), cmath.getComplexNumber(0, 0))
		p.ducmath.i = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 1), cmath.getComplexNumber(0, 0))
		p.ducmath["ε"] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(1, 0))
		p.ducmath["iε"] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(0, 1))
		p.ducmath["εi"] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(0, -1))
		p.ducmath["εj"] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(0, 1))
		p.ducmath["εk"] = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(1, 0))
		p.ducmath.epsilon = p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(1, 0))
		p.ducmath[0],p.ducmath[1] = p.ducmath.zero,p.ducmath.one
		p.ducmath.numberType = sollib._numberType
		p.ducmath.constructor = p.ducmath.toDualComplexNumber
		p.ducmath.elements = {
			p.ducmath.getDualComplexNumber(cmath.getComplexNumber(1, 0), cmath.getComplexNumber(0, 0)),
			p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 1), cmath.getComplexNumber(0, 0)),
			p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(1, 0)),
			p.ducmath.getDualComplexNumber(cmath.getComplexNumber(0, 0), cmath.getComplexNumber(0, 1))
		}
		return p.ducmath
	end

}
return p