Module:Complex Number
此模块的文档可以在Module:Complex Number/doc创建
--'
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