Module:Complex Number
--' local p = { PrimeTable = {} } local numlib = require("Module:Number") local numdata = require("Module:Number/data") local calclib = require("Module:Complex Number/Calculate") local sollib = require("Module:Complex_Number/Solver")
p._numberType = sollib._numberType p._isNaN = sollib._isNaN
--debug --local cmath,tonum=p.cmath.init(),p.cmath.init().toComplexNumber; mw.logObject(cmath.abs(cmath.nonRealPart(tonum("2+3i")))) local eReal, eImag = 'reω', 'ω' p.cmath = { abs=function(z) local real, imag = p.cmath.readPart(z) if math.abs(imag) < 1e-12 then return math.abs(real) end return math.sqrt(real * real + imag * imag) end, floor=function(z) local real, imag = p.cmath.readPart(z) return p.cmath.getComplexNumber(math.floor(real), math.floor(imag)) end, ceil=function(z) local real, imag = p.cmath.readPart(z) return p.cmath.getComplexNumber(math.ceil(real), math.ceil(imag)) end, round=function(op1,op2,op3) local number = p.cmath.getComplexNumber(tonumber(op1) or op1.real or 0, (tonumber(op1) and 0) or op1.imag or 0) local digs = p.cmath.getComplexNumber(tonumber(op2) or (op2 or {}).real or 0, (tonumber(op2) and 0) or (op2 or {}).imag or 0) local base = p.cmath.getComplexNumber(tonumber(op3) or (op3 or {}).real or 10, (tonumber(op3) and 0) or (op3 or {}).imag or 0) local round_rad = p.cmath.pow(base,digs) local check_number = number * round_rad check_number.real = check_number.real + 0.5; check_number.imag = check_number.imag + 0.5; return p.cmath.floor( check_number ) / round_rad 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.imag, (tonumber(op2) and 0) or op2.imag local op1_d, op2_d = a*a + b*b, c*c + d*d if op2_d <= 0 then return op1_d / op2_d end return p.cmath.getComplexNumber((a * c + b * d) / op2_d, (b * c - a * d) / op2_d) end, re=function(z)return tonumber(z) or z.real end, im=function(z) return (tonumber(z) and 0) or z.imag end, nonRealPart=function(z) return p.cmath.getComplexNumber(0, (tonumber(z) and 0) or z.imag) end, conjugate=function(z) local real, imag = p.cmath.readPart(z) return p.cmath.getComplexNumber(real, -imag) end, inverse=function(z) local real, imag = p.cmath.readPart(z) return p.cmath.getComplexNumber(real, -imag) / ( real*real + imag*imag ) end, tovector=function(z) return {p.cmath.readPart(z)} end, trunc=function(z,digs) local real, imag = p.cmath.readPart(z) local n = tonumber(digs) or digs.real or 0 return p.cmath.getComplexNumber(sollib._trunc(real,n), sollib._trunc(imag,n)) end, digits=function(z) local real, imag = p.cmath.readPart(z) real, imag = math.floor(math.abs(real)), math.floor(math.abs(imag)) return math.max(tostring(real):len(),tostring(imag):len()) end, --判斷是否為第一象限高斯質數 is_prime_quadrant1=function(z) local real, imag = p.cmath.readPart(z) if imag == 0 and real == 0 then return false end if not numdata._is_integer(imag) or not numdata._is_integer(real) then return false end if imag == 0 then if real <= 1 then return false end if numdata._is_integer((real - 3.0) / 4.0) then if p.PrimeTable.table_max == nil then p.PrimeTable = require('Module:Factorization') end p.PrimeTable.primeIndexOf({(real or 0)+2}) return p.PrimeTable.lists[real] ~= nil end end --非第一象限高斯質數 if imag < 0 or real < 0 then return false end if imag ~= 0 and real == 0 then return false end local value = imag*imag + real*real --both are nonzero and a² + b² is a prime number (which will not be of the form 4n + 3). if numdata._is_integer((value - 3.0) / 4.0) then return false end if p.PrimeTable.table_max == nil then p.PrimeTable = require('Module:Factorization') end p.PrimeTable.primeIndexOf({value+2}) return p.PrimeTable.lists[value] ~= nil end, sqrt=function(z) local real, imag = p.cmath.readPart(z) local argument = 0 local length = math.sqrt( real * real + imag * imag ) if imag ~= 0 then argument = 2.0 * math.atan(imag / (length + real)) else if real > 0 then argument = 0.0 else argument = math.pi end end local sq_len = math.sqrt(length) return p.cmath.getComplexNumber(sq_len * math.cos(argument/2.0), sq_len * math.sin(argument/2.0)):clean() end, root=function(_z,_n,_num) local z = p.cmath.getComplexNumber(p.cmath.readPart(_z)) local n = p.cmath.getComplexNumber(p.cmath.readPart(_n or 2)) local num = p.cmath.getComplexNumber(p.cmath.readPart(_num or 1)) if num == p.cmath.one or num == p.cmath.zero or num == nil then return p.cmath.pow(z, p.cmath.inverse(n)) end local sgn_data = p.cmath.getComplexNumber(0, 1) local result = p.cmath.pow(p.cmath.abs(z), p.cmath.inverse(n)) * p.cmath.exp(sgn_data * (p.cmath.arg(z) + (num-1)*(2*math.pi) ) * p.cmath.inverse(n)) result:clean() return result end, sin=function(z) local real, imag = p.cmath.readPart(z) return p.cmath.getComplexNumber(math.sin(real) * math.cosh(imag), math.cos(real) * math.sinh(imag)) end, cos=function(z) local real, imag = p.cmath.readPart(z) return p.cmath.getComplexNumber(math.cos(real) * math.cosh(imag), -math.sin(real) * math.sinh(imag)) end, tan=function(z) local theta = p.cmath.readComplexNumber(z) return p.cmath.sin(theta) / p.cmath.cos(theta) end, cot=function(z) local theta = p.cmath.readComplexNumber(z) return p.cmath.cos(theta) / p.cmath.sin(theta) end,
asin=function(z) local real, imag = p.cmath.readPart(z) local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag) local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end return -sgnimag * p.cmath.asinh( v * sgnimag ) end, acos=function(z) local real, imag = p.cmath.readPart(z) local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag) local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end return -sgnimag * p.cmath.acosh( v ) end, atan=function(z) local real, imag = p.cmath.readPart(z) local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag) local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end return -sgnimag * p.cmath.atanh( v * sgnimag ) end, acot=function(z) local real, imag = p.cmath.readPart(z) local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag) local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end return sgnimag * p.cmath.acoth( v * sgnimag ) end,
sinh=function(z) local real, imag = p.cmath.readPart(z) local im_sgn if imag > 0 then im_sgn = 1 elseif imag < 0 then im_sgn = -1 else im_sgn = 0 end return p.cmath.getComplexNumber( math.cos(math.abs(imag)) * math.sinh(real) , im_sgn * math.sin(math.abs(imag)) * math.cosh(real) ) end, cosh=function(z) local real, imag = p.cmath.readPart(z) local im_sgn if imag > 0 then im_sgn = 1 elseif imag < 0 then im_sgn = -1 else im_sgn = 0 end return p.cmath.getComplexNumber( math.cos(math.abs(imag)) * math.cosh(real) , im_sgn * math.sin(math.abs(imag)) * math.sinh(real) ) end, tanh=function(z) local theta = p.cmath.readComplexNumber(z) return p.cmath.sinh(theta) / p.cmath.cosh(theta) end, coth=function(z) local theta = p.cmath.readComplexNumber(z) return p.cmath.cosh(theta) / p.cmath.sinh(theta) end,
asinh=function(z) local real, imag = p.cmath.readPart(z) local u = p.cmath.getComplexNumber(real, imag) return p.cmath.log( u + p.cmath.sqrt( u * u + p.cmath.getComplexNumber(1,0) ) ) end, acosh=function(z) local real, imag = p.cmath.readPart(z) local u = p.cmath.getComplexNumber(real, imag) return p.cmath.log( u + p.cmath.sqrt( u + p.cmath.getComplexNumber(1,0) ) * p.cmath.sqrt( u + p.cmath.getComplexNumber(-1,0) ) ) end, atanh=function(z) local real, imag = p.cmath.readPart(z) local u = p.cmath.getComplexNumber(real, imag) return ( p.cmath.log( 1 + u ) - p.cmath.log( 1 - u ) ) / 2 end, acoth=function(z) local real, imag = p.cmath.readPart(z) local u = p.cmath.getComplexNumber(real, imag) return ( p.cmath.log( 1 + p.cmath.inverse(u) ) - p.cmath.log( 1 - p.cmath.inverse(u) ) ) / 2 end,
dot=function (op1, op2) local real1, imag1 = p.cmath.readPart(op1) local real2, imag2 = p.cmath.readPart(op2) return real1 * real2 + imag1 * imag2 end, outer = function (op1, op2) return p.cmath.getComplexNumber(0, 0) end, sgn=function(z) local real, imag = p.cmath.readPart(z) if real == 0 and imag == 0 then return p.cmath.getComplexNumber(0, 0) end local length = math.sqrt( real * real + imag * imag ) return p.cmath.getComplexNumber(real/length, imag/length) end, arg=function(z) local real, imag = p.cmath.readPart(z) if imag ~= 0 then local length = math.sqrt( real * real + imag * imag ) return 2.0 * math.atan(imag / (length + real)) else if real >= 0 then return 0.0 else return math.pi end end return tonumber("nan") end, cis=function(z) local real, imag = p.cmath.readPart(z) local hyp = 1 if imag ~= 0 then hyp = math.cosh(imag) - math.sinh(imag) end return p.cmath.getComplexNumber(math.cos(real) * hyp, math.sin(real) * hyp) end, exp=function(z) local real, imag = p.cmath.readPart(z) local cis_r, cis_i, exp_r = 1, 0, math.exp(real) if imag ~= 0 then cis_r, cis_i = math.cos(imag), math.sin(imag) end return p.cmath.getComplexNumber(exp_r * cis_r, exp_r * cis_i) end, elog=function(z) local real, imag = p.cmath.readPart(z) local argument = 0 local length = math.sqrt( real * real + imag * imag ) if imag ~= 0 then argument = 2.0 * math.atan(imag / (length + real)) else if real > 0 then argument = 0.0 else argument = math.pi end end return p.cmath.getComplexNumber(math.log(length), argument) end, log=function(z,basez) if basez~=nil then return p.cmath.elog(basez) * p.cmath.inverse(p.cmath.elog(z)) end return p.cmath.elog(z) end, eisenstein=function(op1) local real1, imag1 = tonumber(op1) or op1.real, (tonumber(op1) and 0) or op1.imag local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) return p._eisenstein_integer(real1+sqrt33*imag1, 2*sqrt33*imag1) 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.cmath.getComplexNumber(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.cmath.getComplexNumber(1,0) -- z^0 === 1, z ≠ 0 else return p.cmath.getComplexNumber(tonumber('nan'),0) end -- 0^0 Indeterminate elseif check_op1 == 0 then if check_op2 < 0 then return p.cmath.getComplexNumber(tonumber('inf'),0) end -- 0^(-n) Infinity return p.cmath.getComplexNumber(0,0) -- 0^z === 0, z ≠ 0 end --a ^ z local a = p.cmath.getComplexNumber( tonumber(op1) or op1.real, (tonumber(op1) and 0) or op1.imag ) local z = p.cmath.getComplexNumber( tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag ) return p.cmath.exp(z * p.cmath.log(a)):clean() end,
random = function (op1, op2) if type(op1)==type(nil) and type(op2)==type(nil) then return p.cmath.getComplexNumber(math.random(),0) end local real1, real2 = tonumber(op1) or op1.real, tonumber(op2) or (op2 or{}).real local imag1, imag2 = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or (op2 or{}).imag if type(op2)==type(nil) then return p.cmath.getComplexNumber(sollib._random(real1), sollib._random(imag1)) end return p.cmath.getComplexNumber(sollib._random(math.min(real1,real2), math.max(real1,real2)), sollib._random(math.min(imag1,imag2), math.max(imag1,imag2))) end,
isReal=function(z) return math.abs((tonumber(z) and 0) or z.imag) < 1e-14 end,
ComplexNumberMeta = { __add = function (op1, op2) local real1, real2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local imag1, imag2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag return p.cmath.getComplexNumber(real1 + real2, imag1 + imag2) end, __sub = function (op1, op2) local real1, real2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local imag1, imag2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag return p.cmath.getComplexNumber(real1 - real2, imag1 - imag2) end, __mul = function (op1, op2) local a, c = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local b, d = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag return p.cmath.getComplexNumber(a * c - b * d, b * c + a * d) end, __div = function (op1, op2) local a, c = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local b, d = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag local op1_d, op2_d = a*a + b*b, c*c + d*d if op2_d <= 0 then return op1_d / op2_d end return p.cmath.getComplexNumber((a * c + b * d) / op2_d, (b * c - a * d) / op2_d) end, __mod = function (op1, op2) local x = p.cmath.getComplexNumber(tonumber(op1) or (op1 or {}).real, (tonumber(op1) and 0) or (op1 or {}).imag) local y = p.cmath.getComplexNumber(tonumber(op2) or (op2 or {}).real, (tonumber(op2) and 0) or (op2 or {}).imag) return x - y * p.cmath.floor(x / y) end, __tostring = function (this) local body = if this.real ~= 0 then body = tostring(this.real) end if this.imag ~= 0 then if body ~= and this.imag > 0 then body = body .. '+' end if this.imag == -1 then body = body .. '-' end if math.abs(this.imag) ~= 1 then body = body .. tostring(this.imag) end body = body .. 'i' end if sollib._isNaN(this.real) or sollib._isNaN(this.imag) then body = 'nan' end if body == then body = '0' end return body end, __unm = function (this) return p.cmath.getComplexNumber(-this.real, -this.imag) end, __eq = function (op1, op2) local diff_real = math.abs( (tonumber(op1) or (op1 or {}).real) - (tonumber(op2) or (op2 or {}).real) ) local diff_imag1 = math.abs( ( (tonumber(op1) and 0) or (op1 or {}).imag) - ( (tonumber(op2) and 0) or (op2 or {}).imag) ) return diff_real < 1e-12 and diff_imag1 < 1e-12 end, }, readComplexNumber = function(z) if type(z) == type({}) then --if already be complex number, don't run string find. if z.numberType == "complex" then return z elseif z.numberType == "quaternion" then return p.cmath.getComplexNumber(z.real, z.imag) end elseif type(z) == type(0) then return p.cmath.getComplexNumber(z, 0) elseif type(z) == type(true) then return p.cmath.getComplexNumber(z and 1 or 0, 0) end return p.cmath.getComplexNumber(tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or (z or {}).imag or 0) end, readPart = function(z) if 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, z.imag 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 or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or (z or {}).imag or 0 end, ele=function(id) local _zero = p.cmath.getComplexNumber(0, 0) local eles = (p.cmath.elements or {}) local id_msg = tonumber(tostring(id)) or 0 return eles[id_msg+1]or _zero end, getComplexNumber = function(real,imag) local ComplexNumber = {} setmetatable(ComplexNumber,p.cmath.ComplexNumberMeta) function ComplexNumber:update() self.argument = 0 self.length = math.sqrt( self.real * self.real + self.imag * self.imag ) if self.imag ~= 0 then self.argument = 2.0 * math.atan(self.imag / (self.length + self.real)) else if self.real > 0 then self.argument = 0.0 else self.argument = math.pi end end end function ComplexNumber:clean() if math.abs(self.real) <= 1e-12 then self.real = 0 end if math.abs(self.imag) <= 1e-12 then self.imag = 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.imag - math.floor(self.imag)) <= 1e-12 then self.imag = math.floor(self.imag) end return self end ComplexNumber.real, ComplexNumber.imag = real, imag ComplexNumber.numberType = "complex" return ComplexNumber end, toComplexNumber = function(num_str) if type(num_str)==type({"table"}) and num_str.isEisensteinNumber == true then real, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local eis = p._eisenstein_integer(real+sqrt33*imag, 2*sqrt33*imag) eis.real,eis.imag = real, imag return eis end if type(num_str) == type({}) then --if already be complex number, don't run string find. if num_str.numberType == "complex" then return num_str elseif num_str.numberType == "quaternion" then return p.cmath.getComplexNumber(num_str.real, num_str.imag) end elseif type(num_str) == type(0) then return p.cmath.getComplexNumber(num_str, 0) elseif type(num_str) == type(true) then return p.cmath.getComplexNumber(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.cmath.getComplexNumber(check_number, 0) end end local real, imag 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, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag else real, imag = p.cmath.toComplexNumberPart(num_str)end if real == nil or imag == nil then return nil end return p.cmath.getComplexNumber(real, imag) end, toComplexNumberPart = 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, imag = 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( tostring(num_str) or , '%s+',),'%++([%d%.])',',+%1'),'%++([ij])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ij])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ij])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ij])',',/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.ustring.gsub(mw.text.trim(v),'[ij]+','i'),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ij])','+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%.]+i?") if num_text ~= val then return end local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+")) if num_part == nil then return end if mw.ustring.find(num_text,"i") then imag = imag + num_part else real = real + num_part end end end return real, imag end, halfNumberParts = function(num) local real, imag = p.cmath.readPart(num) return {real, imag} end, init = function() p.cmath.e = p.cmath.getComplexNumber(math.exp(1), 0) p.cmath.pi = p.cmath.getComplexNumber(math.pi, 0) p.cmath["π"] = p.cmath.getComplexNumber(math.pi, 0) p.cmath["°"] = p.cmath.getComplexNumber(math.pi/180, 0) p.cmath.nan = p.cmath.getComplexNumber(tonumber("nan"), tonumber("nan")) p.cmath.infi = p.cmath.getComplexNumber(0, tonumber("inf")) p.cmath.zero = p.cmath.getComplexNumber(0, 0) p.cmath.one = p.cmath.getComplexNumber(1, 0) p.cmath[-1] = p.cmath.getComplexNumber(-1, 0) p.cmath[eImag] = p._eisenstein_integer(0, 1) p.cmath.i = p.cmath.getComplexNumber(0, 1) p.cmath[0],p.cmath[1] = p.cmath.zero,p.cmath.one p.cmath.numberType = sollib._numberType p.cmath.constructor = p.cmath.toComplexNumber p.cmath.elements = { p.cmath.getComplexNumber(1, 0), p.cmath.getComplexNumber(0, 1) } return p.cmath end } p.math={ init = function() local my_math = math my_math.e, my_math.nan = math.exp(1), tonumber("nan") my_math["π"] = math.pi my_math["°"] = math.pi/180 my_math.zero, my_math.one, my_math[-1] = 0, 1, -1 my_math[0],my_math[1] = my_math.zero,my_math.one
my_math.inverse = function(x)return 1.0/(tonumber(x)or 1.0)end my_math.sgn=function(x)if x==0 then return 0 elseif x<0 then return -1 elseif x>0 then return 1 else return tonumber("nan")end end my_math.arg=function(x)if x >= 0 then return 0.0 else return math.pi end end my_math.re=function(z) return tonumber(z) or z.real or 0 end my_math.im=function(z) return (tonumber(z) and 0) or z.imag or 0 end my_math.conjugate=function(z) return tonumber(z) or z.real or 0 end my_math.root=function(z,n) return math.pow((tonumber(z)or 1.0), (1.0/(tonumber(n)or 1.0))) end my_math.nonRealPart=function(z) return (tonumber(z) and 0) or z.imag or 0 end my_math.tovector=function(z) return {tonumber(z) or z.real or 0} end my_math.trunc=function(z,digs) local x = tonumber(z) or z.real or 0 local n = tonumber(digs) or digs.real or 0 local _10_n = math.pow(10,n) local _10_n_x = _10_n * x return (x >= 0)and(math.floor(_10_n_x) / _10_n)or(math.ceil(_10_n_x) / _10_n) end my_math.div=function(op1,op2) return tonumber(op1) / tonumber(op2) end my_math.dot=function(x,y)return x*y end
--sin, cos, tan are already support my_math.cot=function(z)local theta = tonumber(z)return math.cos(theta) / math.sin(theta)end
--asin, acos, atan are already support my_math.acot=function(x)return p.cmath.acot(x).real end
--sinh, cosh, tanh are already support my_math.coth=function(x)return math.cosh(x) / math.sinh(x) end
my_math.asinh=function(x)return math.log( x + math.sqrt( x * x + 1 ) )end my_math.acosh=function(x)return math.log( x + math.sqrt( x * x - 1 ) )end my_math.atanh=function(x) local result = p.cmath.atanh(x):clean() if math.abs(result.imag) > 1e-12 then return tonumber('nan') else return result.real end end my_math.acoth=function(x) local result = p.cmath.acoth(x):clean() if math.abs(result.imag) > 1e-12 then return tonumber('nan') else return result.real end end
my_math.ele=function(id) if (tonumber(tostring(id))or -1) == 0 then return 1 end return 0 end
my_math.isReal = function(x) if type(x)==type(true) then return true else return tonumber(x)~=nil end end
my_math.numberType = sollib._numberType my_math.constructor = function(x) if type(x)==type(true) then return x and 1 or 0 else return tonumber(x) end end
my_math.elements = {1} return my_math end } p.bmath={ abs=function(_z) local z = p.bmath.toBoolean(_z) return (not not z.value) and 1 or 0 end, sgn=function(_z) local z = p.bmath.toBoolean(_z) return (not not z.value) and 1 or 0 end, as=function(op1, op2) local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false) b.value = a.value return b end, nonRealPart=function(bv) return p.bmath.toBoolean(0) end, BooleanNumberMeta = { __add = function (op1, op2) local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false) a.value = a.value or b.value return a end, __sub = function (op1, op2) local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false) a.value = a.value and (not b.value) return a end, __mul = function (op1, op2) local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false) a.value = a.value and b.value return a end, __tostring = function (this) return this.value_table[this.value] end, __unm = function (this)local that = p.bmath.toBoolean(this)that.value = not that.value return that end, __eq = function (op1, op2)return p.bmath.toBoolean(op1).value == p.bmath.toBoolean(op2).value end, }, value_table={ [1]={[true]=1,[false]=0},[0]={[true]=1,[false]=0}, ['1']={[true]=1,[false]=0},['0']={[true]=1,[false]=0}, ['yes']={[true]='yes',[false]='no'},['no']={[true]='yes',[false]='no'}, ['y']={[true]='Y',[false]='N'},['n']={[true]='Y',[false]='N'}, [true]={[true]=true,[false]=false},[false]={[true]=true,[false]=false}, ['true']={['true']=true,['false']=false},['false']={['true']=true,['false']=false}, ['t']={[true]='T',[false]='F'},['f']={[true]='T',[false]='F'}, ['on']={[true]='on',[false]='off'},['off']={[true]='on',[false]='off'}, ['是']={[true]='是',[false]='否'},['否']={[true]='是',[false]='否'}, ['真']={[true]='真',[false]='假'},['假']={[true]='真',[false]='假'}, ['有']={[true]='有',[false]='無'},['無']={[true]='有',[false]='無'},['无']={[true]='有',[false]='无'}, ['开']={[true]='开',[false]='关'},['关']={[true]='开',[false]='关'}, ['開']={[true]='開',[false]='關'},['關']={[true]='開',[false]='關'},}, toBoolean = function(num_str) local BooleanNumber = {} if (type(num_str) == type({}) and num_str.numberType == "boolean") then return num_str end if (type(num_str) == type({})) and num_str.value_table ~= nil and num_str.value ~= nil then BooleanNumber = {value_table=num_str.value_table,value=num_str.value} elseif (type(num_str) == type({}) and type(num_str.numberType)==type("string") and num_str.numberType ~= "boolean")then local data = tostring(num_str) ~= "0" BooleanNumber = {} BooleanNumber.value_table={[true]='T',[false]='F'} BooleanNumber.value=data elseif (type(num_str) == type(0))then local data = math.abs(num_str) > 1e-14 BooleanNumber = {} BooleanNumber.value_table={[true]='T',[false]='F'} BooleanNumber.value=data elseif (type(num_str) == type(true))then local data = num_str BooleanNumber = {} BooleanNumber.value_table={[true]='T',[false]='F'} BooleanNumber.value=data else if yesno == nil then yesno = require('Module:Yesno') end local input_str = mw.ustring.gsub(mw.text.trim(tostring(num_str)),"%s",) input_str = mw.ustring.gsub(input_str,"([真假有無无])",function(str) return( {['真']='是',['假']='否',['有']='是',['無']='否',['无']='否'})[str] or str end) local data = yesno(num_str) or yesno(input_str) if data == nil then return nil end BooleanNumber = {} BooleanNumber.value_table=p.bmath.value_table[num_str] or p.bmath.value_table[input_str] or {[true]='T',[false]='F'} BooleanNumber.value=data end setmetatable(BooleanNumber,p.bmath.BooleanNumberMeta) BooleanNumber.numberType = "boolean" return BooleanNumber end, init = function() p.bmath.zero = p.bmath.toBoolean(0) p.bmath.one = p.bmath.toBoolean(1) p.bmath[0],p.bmath[1] = p.bmath.zero,p.bmath.one p.bmath.is_bool_lib = true p.bmath.numberType = sollib._numberType p.bmath.constructor = p.bmath.toBoolean p.bmath.elements = {true} return p.bmath end } p.qmath = { abs=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) if imag == 0 and jpart == 0 and kpart == 0 then return math.abs(real) end return math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart ) end, floor=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) return p.qmath.getQuaternionNumber(math.floor(real), math.floor(imag), math.floor(jpart), math.floor(kpart)) end, ceil=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) return p.qmath.getQuaternionNumber(math.ceil(real), math.ceil(imag), math.ceil(jpart), math.ceil(kpart)) end, div=function(left,z) local lreal, limag, ljpart, lkpart = p.qmath.readPart(left) local real, imag, jpart, kpart = p.qmath.readPart(z) return p.qmath.getQuaternionNumber(lreal, limag, ljpart, lkpart) * (p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart ) / ( real*real + imag*imag + jpart*jpart + kpart*kpart )) end, round=function(op1,op2,op3) local number = p.qmath.getQuaternionNumber(tonumber(op1) or op1.real or 0, (tonumber(op1) and 0) or (op1.imag or 0) or 0, (tonumber(op1) and 0) or (op1.jpart or 0) or 0, (tonumber(op1) and 0) or (op1.kpart or 0) or 0) local digs = p.qmath.getQuaternionNumber(tonumber(op2) or (op2 or {}).real or 0, (tonumber(op2) and 0) or ((op2 or {}).imag or 0) or 0, (tonumber(op2) and 0) or ((op2 or {}).jpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) or 0 ) local base = p.qmath.getQuaternionNumber(tonumber(op3) or (op3 or {}).real or 10, (tonumber(op3) and 0) or ((op3 or {}).imag or 0) or 0, (tonumber(op3) and 0) or ((op3 or {}).jpart or 0) or 0, (tonumber(op3) and 0) or ((op3 or {}).kpart or 0) or 0 ) local round_rad = p.qmath.pow(base,digs) local check_number = number * round_rad check_number.real = check_number.real + 0.5; check_number.imag = check_number.imag + 0.5; check_number.jpart = check_number.jpart + 0.5; check_number.kpart = check_number.kpart + 0.5; return p.qmath.floor( check_number ) * p.qmath.inverse(round_rad) end, re=function(z)return tonumber(z) or z.real end, im=function(z) return (tonumber(z) and 0) or z.imag end, conjugate=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) return p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart ) end, inverse=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) return p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart ) / ( real*real + imag*imag + jpart*jpart + kpart*kpart ) end, tovector=function(z) return {p.qmath.readPart(z)} end, trunc=function(z,digs) local real, imag, jpart, kpart = p.qmath.readPart(z) local n = tonumber(digs) or digs.real or 0 return p.qmath.getQuaternionNumber( sollib._trunc(real,n), sollib._trunc(imag,n), sollib._trunc(jpart,n), sollib._trunc(kpart,n) ) end, sqrt=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) if jpart == 0 and kpart == 0 then local complex = p.cmath.sqrt(p.cmath.getComplexNumber(real, imag)) return p.qmath.getQuaternionNumber(complex.real, complex.imag, 0, 0) end return p.qmath.pow(z, 0.5) end, root=function(_z,_n,_num) local z = p.qmath.getQuaternionNumber(p.qmath.readPart(_z)) local n = p.qmath.getQuaternionNumber(p.qmath.readPart(_n or 2)) local num = p.qmath.getQuaternionNumber(p.qmath.readPart(_num or 1)) if num == p.qmath.one or num == p.qmath.zero or num == nil then return p.qmath.pow(z, p.qmath.inverse(n)) end local sgn_data = p.qmath.sgn(p.qmath.nonRealPart(z)) if math.abs(sgn_data.imag)<1e-14 and math.abs(sgn_data.jpart)<1e-14 and math.abs(sgn_data.kpart)<1e-14 then sgn_data=p.qmath.getQuaternionNumber(0,1,0,0) end local result = p.qmath.pow(p.qmath.abs(z), p.qmath.inverse(n)) * p.qmath.exp(sgn_data * (p.qmath.arg(z) + (num-1)*(2*math.pi) ) * p.qmath.inverse(n)) result:clean() return result end, sin=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart) return ( math.cosh(p.qmath.abs(u)) * math.sin(real) ) + ( p.qmath.sgn(u) * math.sinh(p.qmath.abs(u)) * math.cos(real) ) end, cos=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart) return ( math.cosh(p.qmath.abs(u)) * math.cos(real) ) - ( p.qmath.sgn(u) * math.sinh(p.qmath.abs(u)) * math.sin(real) ) end, tan=function(z) local theta = p.qmath.readComplexNumber(z) return p.qmath.sin(theta) * p.qmath.inverse( p.qmath.cos(theta) ) end, cot=function(z) local theta = p.qmath.readComplexNumber(z) return p.qmath.cos(theta) * p.qmath.inverse( p.qmath.sin(theta) ) end,
asin=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart) local sgnu = p.qmath.sgn(u); if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end return -sgnu * p.qmath.asinh( v * sgnu ) end, acos=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart) local sgnu = p.qmath.sgn(u); if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end return -sgnu * p.qmath.acosh( v ) end, atan=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart) local sgnu = p.qmath.sgn(u); if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end return -sgnu * p.qmath.atanh( v * sgnu ) end, acot=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart) local sgnu = p.qmath.sgn(u); if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end return sgnu * p.qmath.acoth( v * sgnu ) end,
sinh=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart) return ( math.cos(p.qmath.abs(u)) * math.sinh(real) ) + ( p.qmath.sgn(u) * math.sin(p.qmath.abs(u)) * math.cosh(real) ) end, cosh=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart) return ( math.cos(p.qmath.abs(u)) * math.cosh(real) ) + ( p.qmath.sgn(u) * math.sin(p.qmath.abs(u)) * math.sinh(real) ) end, tanh=function(z) local theta = p.qmath.readComplexNumber(z) return p.qmath.sinh(theta) * p.qmath.inverse( p.qmath.cosh(theta) ) end, coth=function(z) local theta = p.qmath.readComplexNumber(z) return p.qmath.cosh(theta) * p.qmath.inverse( p.qmath.sinh(theta) ) end,
asinh=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart) return p.qmath.log( u + p.qmath.sqrt( u * u + p.qmath.getQuaternionNumber(1,0,0,0) ) ) end, acosh=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart) return p.qmath.log( u + p.qmath.sqrt( u + p.qmath.getQuaternionNumber(1,0,0,0) ) * p.qmath.sqrt( u + p.qmath.getQuaternionNumber(-1,0,0,0) ) ) end, atanh=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart) return ( p.qmath.log( 1 + u ) - p.qmath.log( 1 - u ) ) / 2 end, acoth=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart) return ( p.qmath.log( 1 + p.qmath.inverse(u) ) - p.qmath.log( 1 - p.qmath.inverse(u) ) ) / 2 end,
dot = function (op1, op2) local a, t = tonumber(op1) or op1.real, tonumber(op2) or op2.real local b, x = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag local c, y = (tonumber(op1) and 0) or (op1.jpart or 0), (tonumber(op2) and 0) or (op2.jpart or 0) local d, z = (tonumber(op1) and 0) or (op1.kpart or 0), (tonumber(op2) and 0) or (op2.kpart or 0) return a * t + b * x + c * y + d * z end, outer = function (op1, op2) local a, t = tonumber(op1) or op1.real, tonumber(op2) or op2.real local b, x = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag local c, y = (tonumber(op1) and 0) or (op1.jpart or 0), (tonumber(op2) and 0) or (op2.jpart or 0) local d, z = (tonumber(op1) and 0) or (op1.kpart or 0), (tonumber(op2) and 0) or (op2.kpart or 0) return p.qmath.getQuaternionNumber(0, c*z-d*y, d*x-b*z, b*y-x*c ) end,
scalarPartQuaternion=function(z) return p.qmath.getQuaternionNumber(tonumber(z) or z.real, 0, 0, 0) end, nonRealPart=function(z) return p.qmath.getQuaternionNumber(0, (tonumber(z) and 0) or (z.imag or 0), (tonumber(z) and 0) or (z.jpart or 0), (tonumber(z) and 0) or (z.kpart or 0)) end, vectorPartQuaternion=function(z) return p.qmath.getQuaternionNumber(0, (tonumber(z) and 0) or (z.imag or 0), (tonumber(z) and 0) or (z.jpart or 0), (tonumber(z) and 0) or (z.kpart or 0)) end, sgn=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local length = math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart ) if length <= 0 then return p.qmath.getQuaternionNumber(0,0,0,0) end return z / length end, arg=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local length = math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart ) return math.acos( real / length ) end, cis=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart) return p.qmath.cos(u) + p.qmath.getQuaternionNumber(0,1,0,0) * p.qmath.sin(u) end, exp=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart) return ( (p.qmath.sgn(u) * math.sin(p.qmath.abs(u))) + math.cos(p.qmath.abs(u))) * math.exp(real) end, elog=function(z) local real, imag, jpart, kpart = p.qmath.readPart(z) local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart) return (p.qmath.sgn(u) * p.qmath.arg(v)) + math.log(p.qmath.abs(v)) end, log=function(z,basez) if basez~=nil then return p.qmath.elog(basez) * p.qmath.inverse(p.qmath.elog(z)) end return p.qmath.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.qmath.getQuaternionNumber(1,0,0,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.qmath.getQuaternionNumber(1,0,0,0) -- z^0 === 1, z ≠ 0 else return p.qmath.getQuaternionNumber(tonumber('nan'),0,0,0) end --0^0 Indeterminate elseif check_op1 == 0 then if check_op2 < 0 then return p.qmath.getQuaternionNumber(tonumber('inf'),0,0,0) end -- 0^(-n) Infinity return p.qmath.getQuaternionNumber(0,0,0,0) -- 0^z === 0, z ≠ 0 end --a ^ z local a = p.qmath.getQuaternionNumber( p.qmath.readPart(op1) ) local z = p.qmath.getQuaternionNumber( p.qmath.readPart(op2) ) a:clean();z:clean(); if a.jpart == 0 and z.jpart == 0 and a.kpart == 0 and z.kpart == 0 then local complex = p.cmath.pow(p.cmath.getComplexNumber(a.real, a.imag), p.cmath.getComplexNumber(z.real, z.imag)) return p.qmath.getQuaternionNumber(complex.real, complex.imag, 0, 0) end return p.qmath.exp(z * p.qmath.log(a)):clean() end,
random = function (op1, op2) if type(op1)==type(nil) and type(op2)==type(nil) then return p.qmath.getQuaternionNumber(math.random(), 0, 0, 0) end local a, t = tonumber(op1) or (op1 or {}).real or 0, tonumber(op2) or (op2 or{}).real or 0 local b, x = (tonumber(op1) and 0) or (op1 or {}).imag or 0, (tonumber(op2) and 0) or (op2 or{}).imag or 0 local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or{}).jpart or 0) local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or{}).kpart or 0) if type(op2)==type(nil) then return p.qmath.getQuaternionNumber(sollib._random(a), sollib._random(b), sollib._random(c), sollib._random(d)) end return p.qmath.getQuaternionNumber(sollib._random(math.min(a, t), math.max(a, t)), sollib._random(math.min(b, x), math.max(b, x)), sollib._random(math.min(c, y), math.max(c, y)), sollib._random(math.min(d, z), math.max(d, z))) end,
isReal=function(z) return p.qmath.abs(p.qmath.nonRealPart(z)) < 1e-14 end,
QuaternionNumberMeta = { __add = function (op1, op2) local a, t = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local b, x = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0) local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) return p.qmath.getQuaternionNumber(a + t, b + x, c + y, d + z) end, __sub = function (op1, op2) local a, t = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local b, x = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0) local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) return p.qmath.getQuaternionNumber(a - t, b - x, c - y, d - z) end, __mul = function (op1, op2) local a1, a2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local b1, b2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag local c1, c2 = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0) local d1, d2 = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) return p.qmath.getQuaternionNumber( a1 * a2 - b1 * b2 - c1 * c2 - d1 * d2, a1 * b2 + b1 * a2 + c1 * d2 - d1 * c2, a1 * c2 - b1 * d2 + c1 * a2 + d1 * b2, a1 * d2 + b1 * c2 - c1 * b2 + d1 * a2 ) end, __div = function (op1, op2) local r1, r2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real local i1, i2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag local j1, j2 = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0) local k1, k2 = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) if i2 ~= 0 or j2 ~= 0 or k2 ~= 0 then error( "Quaternion can not divide by non scalar value" ) end local op1_d, op2_d = r1*r1 + i1*i1 + j1*j1 + k1*k1, r2*r2 + i2*i2 + j2*j2 + k2*k2 if op2_d <= 0 then return op1_d / op2_d end return p.qmath.getQuaternionNumber(r1/r2, i1/r2, j1/r2, k1/r2) end, __mod = function (op1, op2) local x = p.qmath.getQuaternionNumber(tonumber(op1) or (op1 or {}).real, (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op1) and 0) or ((op1 or {}).kpart or 0) ) local y = p.qmath.getQuaternionNumber(tonumber(op2) or (op2 or {}).real, (tonumber(op2) and 0) or (op2 or {}).imag, (tonumber(op2) and 0) or ((op2 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) ) return x - y * p.qmath.floor(x / y) end, __tostring = function (this) local body = if this.real ~= 0 then body = tostring(this.real) end if this.imag ~= 0 then if body ~= and this.imag > 0 then body = body .. '+' end if this.imag == -1 then body = body .. '-' end if math.abs(this.imag) ~= 1 then body = body .. tostring(this.imag) end body = body .. 'i' end if this.jpart ~= 0 then if body ~= and this.jpart > 0 then body = body .. '+' end if this.jpart == -1 then body = body .. '-' end if math.abs(this.jpart) ~= 1 then body = body .. tostring(this.jpart) end body = body .. 'j' end if this.kpart ~= 0 then if body ~= and this.kpart > 0 then body = body .. '+' end if this.kpart == -1 then body = body .. '-' end if math.abs(this.kpart) ~= 1 then body = body .. tostring(this.kpart) end body = body .. 'k' end if sollib._isNaN(this.real) or sollib._isNaN(this.imag) or sollib._isNaN(this.jpart) or sollib._isNaN(this.kpart) then body = 'nan' end if body == then body = '0' end return body end, __unm = function (this) return p.qmath.getQuaternionNumber(-this.real, -this.imag, -this.jpart, -this.kpart) end, __eq = function (op1, op2) local diff_real = math.abs( (tonumber(op1) or (op1 or {}).real) - (tonumber(op2) or (op2 or {}).real) ) local diff_imag1 = math.abs( ( (tonumber(op1) and 0) or (op1 or {}).imag) - ( (tonumber(op2) and 0) or (op2 or {}).imag) ) local diff_jpart = math.abs( ( (tonumber(op1) and 0) or ((op1 or {}).jpart or 0)) - ( (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)) ) local diff_kpart = math.abs( ( (tonumber(op1) and 0) or ((op1 or {}).kpart or 0)) - ( (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)) ) return diff_real < 1e-12 and diff_imag1 < 1e-12 and diff_jpart < 1e-12 and diff_kpart < 1e-12 end, }, ele=function(id) local _zero = p.qmath.getQuaternionNumber(0, 0, 0, 0) local eles = (p.qmath.elements or {}) local id_msg = tonumber(tostring(id)) or 0 return eles[id_msg+1]or _zero end, readComplexNumber = function(z) if type(z) == type({}) then --if already be complex number, don't run string find. if z.numberType == "complex" then return p.qmath.getQuaternionNumber(z.real, z.imag, 0, 0) elseif z.numberType == "quaternion" then return z end elseif type(z) == type(0) then return p.qmath.getQuaternionNumber(z, 0, 0, 0) elseif type(z) == type(true) then return p.qmath.getQuaternionNumber(z and 1 or 0, 0, 0, 0) end return p.qmath.getQuaternionNumber(tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).imag or 0), ((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).jpart or 0), ((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).kpart or 0)) end, readPart = function(z) if type(z) == type({}) and (z.numberType == "complex" or z.numberType == "quaternion") then --if already be complex number, don't run string find. if z.numberType == "quaternion"then return z.real, z.imag, z.jpart, z.kpart else return z.real, z.imag, 0, 0 end elseif type(z) == type(0) then return z, 0, 0, 0 elseif type(z) == type(true) then return z and 1 or 0, 0, 0, 0 end return tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).imag or 0), ((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).jpart or 0), ((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).kpart or 0) end, getQuaternionNumber = function(real, imag, jpart, kpart) local QuaternionNumber = {} setmetatable(QuaternionNumber,p.qmath.QuaternionNumberMeta) function QuaternionNumber:update() self.argument = 0 self.length = math.sqrt( self.real * self.real + self.imag * self.imag + self.jpart * self.jpart + self.kpart * self.kpart ) end function QuaternionNumber:clean() if math.abs(self.real) <= 1e-12 then self.real = 0 end if math.abs(self.imag) <= 1e-12 then self.imag = 0 end if math.abs(self.jpart) <= 1e-12 then self.jpart = 0 end if math.abs(self.kpart) <= 1e-12 then self.kpart = 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.imag - math.floor(self.imag)) <= 1e-12 then self.imag = math.floor(self.imag) end if math.abs(self.jpart - math.floor(self.jpart)) <= 1e-12 then self.jpart = math.floor(self.jpart) end if math.abs(self.kpart - math.floor(self.kpart)) <= 1e-12 then self.kpart = math.floor(self.kpart) end return self end QuaternionNumber.real, QuaternionNumber.imag, QuaternionNumber.jpart, QuaternionNumber.kpart = real, imag, jpart, kpart QuaternionNumber.numberType = "quaternion" return QuaternionNumber end, toQuaternionNumber = function(num_str) local real, imag, jpart, kpart if num_str == nil then return nil end if type(num_str) == type({}) then --if already be complex number, don't run string find. if num_str.numberType == "quaternion" then return num_str elseif num_str.numberType == "complex" then return p.qmath.getQuaternionNumber(num_str.real, num_str.imag, 0, 0) end elseif type(num_str) == type(1) then return p.qmath.getQuaternionNumber(num_str, 0, 0, 0) elseif type(num_str) == type(true) then return p.qmath.getQuaternionNumber(num_str and 1 or 0, 0, 0, 0) end if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then real, imag, jpart, kpart = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or (num_str.imag or 0), (tonumber(num_str) and 0) or (num_str.jpart or 0), (tonumber(num_str) and 0) or (num_str.kpart or 0) else real, imag, jpart, kpart = p.qmath.toQuaternionNumberPart(tostring(num_str)) end if real == nil or imag == nil or jpart == nil or kpart == nil then return nil end return p.qmath.getQuaternionNumber(real, imag, jpart, kpart) end, toQuaternionNumberPart = 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, jpart, kpart = 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( tostring(num_str) or , '%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 if mw.ustring.find(num_text,"i") then imag = imag + num_part elseif mw.ustring.find(num_text,"j") then jpart = jpart + num_part elseif mw.ustring.find(num_text,"k") then kpart = kpart + num_part else real = real + num_part end end end return real, imag, jpart, kpart end, halfNumberParts = function(num) local real, imag, jpart, kpart = p.qmath.readPart(num) return {p.cmath.getComplexNumber(real, imag), p.cmath.getComplexNumber(jpart, kpart)} end, init = function() p.qmath.pi = p.qmath.getQuaternionNumber(math.pi, 0, 0, 0) p.qmath["π"] = p.qmath.getQuaternionNumber(math.pi, 0, 0, 0) p.qmath["°"] = p.qmath.getQuaternionNumber(math.pi/180, 0, 0, 0) p.qmath.e = p.qmath.getQuaternionNumber(math.exp(1), 0, 0, 0) p.qmath.nan = p.qmath.getQuaternionNumber(tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan")) p.qmath.infi = p.qmath.getQuaternionNumber(0, tonumber("inf"), 0, 0) p.qmath.infj = p.qmath.getQuaternionNumber(0, 0, tonumber("inf"), 0) p.qmath.infk = p.qmath.getQuaternionNumber(0, 0, 0, tonumber("inf")) p.qmath.zero = p.qmath.getQuaternionNumber(0, 0, 0, 0) p.qmath.one = p.qmath.getQuaternionNumber(1, 0, 0, 0) p.qmath[-1] = p.qmath.getQuaternionNumber(-1, 0, 0, 0) p.qmath.i = p.qmath.getQuaternionNumber(0, 1, 0, 0) p.qmath.j = p.qmath.getQuaternionNumber(0, 0, 1, 0) p.qmath.k = p.qmath.getQuaternionNumber(0, 0, 0, 1) p.qmath[0],p.qmath[1] = p.qmath.zero,p.qmath.one p.qmath.numberType = sollib._numberType p.qmath.constructor = p.qmath.toQuaternionNumber p.qmath.elements = { p.qmath.getQuaternionNumber(1, 0, 0, 0), p.qmath.getQuaternionNumber(0, 1, 0, 0), p.qmath.getQuaternionNumber(0, 0, 1, 0), p.qmath.getQuaternionNumber(0, 0, 0, 1), } return p.qmath end } p._efloor=function(z) local real, imag = tonumber(z) or z[eReal], (tonumber(z) and 0) or z[eImag] return p._eisenstein_integer(math.floor(real), math.floor(imag)) end p._eisenstein_meta={ __add = function (op1, op2) local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal] local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag] if not real2 or not imag2 then local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 end return p._eisenstein_integer(real1 + real2, imag1 + imag2) end, __sub = function (op1, op2) local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal] local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag] if not real2 or not imag2 then local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 end return p._eisenstein_integer(real1 - real2, imag1 - imag2) end, __mul = function (op1, op2) local a, c = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal] local b, d = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag] if not c or not d then local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag c, d = real3+sqrt33*imag3, 2*sqrt33*imag3 end return p._eisenstein_integer(a * c - b * d, b * c + a * d - b * d) end, __div = function (op1, op2) local a, c = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal] local b, d = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag] if not c or not d then local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag c, d = real3+sqrt33*imag3, 2*sqrt33*imag3 end if c==d or c*c == (c*d*d)/(c-d) then local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local pn, q = p.cmath.getComplexNumber(a-b/2, sqrt32 * b), p.cmath.getComplexNumber(c-d/2, sqrt32 * d) local p_q = pn/q local real1, imag1 = tonumber(p_q) or p_q.real, (tonumber(p_q) and 0) or p_q.imag return p._eisenstein_integer(real1+sqrt33*imag1, 2*sqrt33*imag1) end local op1_d, op2_d = c*d/(c-d), c*c + (c*d*d)/(c-d) return p._eisenstein_integer((a * c + b * op1_d) / op2_d, (b * c - a * op1_d + b * op1_d) / op2_d) end, __mod = function (op1, op2) local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal] local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag] if not real2 or not imag2 then local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 end local x = p._eisenstein_integer(real1, imag1) local y = p._eisenstein_integer(real2, imag2) return x - y * p._efloor(x / y) end, __tostring = function (this) local body = if this[eReal] ~= 0 then body = tostring(this[eReal]) end if this[eImag] ~= 0 then if body ~= and this[eImag] > 0 then body = body .. '+' end if this[eImag] == -1 then body = body .. '-' end if math.abs(this[eImag]) ~= 1 then body = body .. tostring(this[eImag]) end body = body .. eImag end if body == then body = '0' end return body end, __unm = function (this) return p._eisenstein_integer(-this[eReal], -this[eImag]) end, __eq = function (op1, op2) local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal] local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag] if not real2 or not imag2 then local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3 end local diff_real = math.abs( real1 - real2 ) local diff_imag1 = math.abs( imag1 - imag2 ) return diff_real < 1e-12 and diff_imag1 < 1e-12 end, }
function p._eisenstein_integer(int_a, int_b) local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) local eisenstein = p.cmath.getComplexNumber(int_a-int_b/2, sqrt32 * int_b) eisenstein[eReal], eisenstein[eImag] = int_a,int_b setmetatable(eisenstein,p._eisenstein_meta) eisenstein.isEisensteinNumber = true return eisenstein end function p._toEisensteinNumber(num_str) local real, imag 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, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag else real, imag = p._toEisensteinNumberPart(num_str) end if real == nil or imag == nil then return nil end return p._eisenstein_integer(real, imag) end function p._toEisensteinNumberPart(num_str) if type(num_str) == type(function()end) then return end local body = local real, imag, omg = 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( tostring(num_str) or , '%s+',),'%++([%d%.])',',+%1'),'%++([ijω])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijω])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijω])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijω])',',/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.ustring.gsub(mw.text.trim(v),'[ijω]+','i'),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ijω])','+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%.]+i?") if num_text ~= val then return end local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+")) if num_part == nil then return end if mw.ustring.find(num_text,"i") then imag = imag + num_part elseif mw.ustring.find(num_text,"ω") then omg = omg + num_part else real = real + num_part end end end local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3) return real+sqrt33*imag, 2*sqrt33*imag+omg end
return p