跳转到内容

模組:Complex Number/Dual Number

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

这是本页的一个历史版本,由A2569875留言 | 贡献2022年4月25日 (一) 06:47编辑。这可能和当前版本存在着巨大的差异。

p={}
local sollib = require("Module:Complex_Number/Solver")
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
		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)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 return p.dumath.getDualNumber(0,0) end -- 0^z === 0, z ≠ 0
		--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,
	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)
		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
		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)
		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("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)
		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'),'^([ijkl]+)','+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

}
return p