模組:Complex Number/Dual Number
本模組為基於Module:Complex Number的二元數運算系統,可提供其他模組呼叫使用,而若要直接在模板或條目中使用可透過Module:Complex Number/Calculate或{{複變運算}}來完成。
模組內容
本模組有2套數學資料結構的定義以及對應的數學運算庫:
使用方法
LUA
- 初始化數學庫
local 自訂函數庫名稱 = require("Module:Complex Number/Dual Number").函數庫名稱.init()
- 例如初始化二元數數學庫:
local dumath = require("Module:Complex Number/Dual Number").dumath.init()
- 例如初始化二元數數學庫:
- 初始化指定數學結構的數字
local 變數名稱 = 自訂函數庫名稱.constructor("描述數字的字串")
- 例如:
local num1 = dumath.constructor("2+3ε")
- 例如:
- 執行運算
- 例如:
local num1 = dumath.constructor("2+3ε") local num2 = dumath.constructor("4+5ε") print(num1 * num2)
- 輸出:8+22ε
- 或者使用函數庫內容:
local num1 = dumath.constructor("1+ε") print(dumath.sqrt(num1))
- 輸出:1+0.5ε
- 例如:
模板
使用{{複變運算}}
- 語法:
{{複變運算|運算式|number class=Module: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