模組:Complex Number/Octonion
外观

本模組為基於Module:Complex Number的八元數運算系統,可提供其他模組呼叫使用,而若要直接在模板或條目中使用可透過Module:Complex Number/Calculate或{{複變運算}}來完成。
使用方法
LUA
- 初始化數學庫
local 自訂函數庫名稱 = require("Module:Complex Number/Octonion").omath.init()
- 例如:
local omath = require("Module:Complex Number/Octonion").omath.init()
- 例如:
- 初始化指定數學結構的數字
local 變數名稱 = 自訂函數庫名稱.constructor("描述數字的字串")
- 例如:
local num1 = omath.constructor("2+3i+l")
- 例如:
- 執行運算
- 例如:
local num1 = omath.constructor("2+3i+l") local num2 = omath.constructor("4+5j+kl") print(num1 * num2)
- 輸出:8+12i+10j+16k+4*l-2*jl+2*kl
- 或者使用函數庫內容:
local num1 = omath.constructor("1+i+j+k+l+il+jl+kl") print(omath.sqrt(num1))
- 輸出:1.3835510696657 + 0.36138890060691i+ 0.36138890060691j + 0.36138890060691k + 0.36138890060691*l + 0.36138890060691*il + 0.36138890060691*jl + 0.36138890060691*kl
- 例如:
模板
使用{{複變運算}}
- 語法:
{{複變運算|運算式|number class=Module:Complex Number/Octonion.函數庫名稱}}
使用{{計算結果}}
或生成八元數乘法表:
{{乘法表 |table class = class="wikitable" style="text-align: center; margin:0.5em auto;" |calculate = {{{left}}} * {{{right}}} |calculate title = <math>\times</math> |first number list = 1,i,j,k,l,il,jl,kl |second number list = 1,i,j,k,l,il,jl,kl |class=Module:Complex_Number/Octonion.omath |number css = css |use math=yes }}
參見
local p = {}
local qmath = require("Module:Complex_Number").qmath.init()
local toQnumber = qmath.constructor
function p._isNaN(x)
return (not (x==x)) and (x~=x)
end
p.omath={
abs=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
if nonL.imag == 0 and nonL.jpart == 0 and nonL.kpart == 0 and valL.real == 0 and
valL.imag == 0 and valL.jpart == 0 and valL.kpart == 0 then return math.abs(nonL.real) end
if valL.real == 0 and valL.imag == 0 and valL.jpart == 0 and valL.kpart == 0 then return qmath.abs(nonL) end
local nonL_len, valL_len = qmath.abs(nonL), qmath.abs(valL)
return math.sqrt( nonL_len * nonL_len + valL_len * valL_len )
end,
conjugate=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return p.omath.getOctonionNumberQ(qmath.conjugate(nonL), -valL)
end,
floor=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return p.omath.getOctonionNumberQ(qmath.floor(nonL), qmath.floor(valL))
end,
ceil=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return p.omath.getOctonionNumberQ(qmath.ceil(nonL), qmath.ceil(valL))
end,
div=function(op1, op2)
local op_div = p.omath.inverse(op2)
local _a, _b = p.omath.readOctonionNumberQpart(op1)
local _c, _d = p.omath.readOctonionNumberQpart(op_div)
local r_nonL = _a*_c - qmath.conjugate(_d)*_b
local r_valL = _d*_a + _b*qmath.conjugate(_c)
return p.omath.getOctonionNumberQ(r_nonL, r_valL)
end,
round=function(op1, op2, op3)
local nonL, valL = p.omath.readOctonionNumberQpart(op1)
local digs = p.omath.readOctonionNumberQpart(op2)
local base = p.omath.readOctonionNumberQpart(op2)
return p.omath.getOctonionNumberQ(qmath.round(nonL, digs, base), qmath.round(valL, digs, base))
end,
re=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return tonumber(z) or nonL.real
end,
im=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return (tonumber(z) and 0) or nonL.imag
end,
inverse=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local nonL_up, valL_up = qmath.conjugate(nonL), -valL
local nonL_len, valL_len = qmath.abs(nonL), qmath.abs(valL)
local div_down = ( nonL_len * nonL_len + valL_len * valL_len )
return p.omath.getOctonionNumberQ(nonL_up / div_down, valL_up / div_down)
end,
tovector=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return {nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart}
end,
trunc=function(op1, op2)
local nonL, valL = p.omath.readOctonionNumberQpart(op1)
local digs = p.omath.readOctonionNumberQpart(op2)
return p.omath.getOctonionNumberQ(qmath.trunc(nonL, digs), qmath.trunc(valL, digs))
end,
arg=function(z) --TODO: verify
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local nonL_len, valL_len = qmath.abs(nonL), qmath.abs(valL)
local length = math.sqrt( nonL_len * nonL_len + valL_len * valL_len )
return math.acos( nonL.real / length )
end,
exp=function(z) --Cayley-Dickson construction
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local cis_r, cis_i, exp_r = 1, 0, qmath.exp(nonL)
if valL ~= p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0) then cis_r, cis_i = qmath.cos(valL), qmath.sin(valL) end
return p.omath.getOctonionNumberQ(exp_r * cis_r, exp_r * cis_i)
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.omath.getOctonionNumber(1, 0, 0, 0, 0, 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.omath.getOctonionNumber(1, 0, 0, 0, 0, 0, 0, 0) -- z^0 === 1, z ≠ 0
else return p.omath.getOctonionNumber(tonumber('nan'), 0, 0, 0, 0, 0, 0, 0) end --0^0 Indeterminate
elseif check_op1 == 0 then return p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0) end -- 0^z === 0, z ≠ 0
--a ^ z
local _zero = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0)
local a = p.omath.getOctonionNumberQ(p.omath.readOctonionNumberQpart(op1))
local z = p.omath.getOctonionNumberQ(p.omath.readOctonionNumberQpart(op2))
a:clean();z:clean();
if a.valL == _zero and z.valL == _zero then
return qmath.pow(a.nonL, z.nonL)
end
--TODO : Log not define
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,
OctonionNumberMeta = {
__add = function (op1, op2)
local op1_a, op1_b = p.omath.readOctonionNumberQpart(op1)
local op2_a, op2_b = p.omath.readOctonionNumberQpart(op2)
return p.omath.getOctonionNumberQ(op1_a + op2_a, op1_b + op2_b)
end,
__sub = function (op1, op2)
local op1_a, op1_b = p.omath.readOctonionNumberQpart(op1)
local op2_a, op2_b = p.omath.readOctonionNumberQpart(op2)
return p.omath.getOctonionNumberQ(op1_a - op2_a, op1_b - op2_b)
end,
__mul = function (op1, op2)
local _a, _b = p.omath.readOctonionNumberQpart(op1)
local _c, _d = p.omath.readOctonionNumberQpart(op2)
local r_nonL = _a*_c - qmath.conjugate(_d)*_b
local r_valL = _d*_a + _b*qmath.conjugate(_c)
return p.omath.getOctonionNumberQ(r_nonL, r_valL)
end,
__div = function (op1, op2)
local op_div = p.omath.inverse(op2)
local _a, _b = p.omath.readOctonionNumberQpart(op1)
local _c, _d = p.omath.readOctonionNumberQpart(op_div)
local r_nonL = _a*_c - qmath.conjugate(_d)*_b
local r_valL = _d*_a + _b*qmath.conjugate(_c)
return p.omath.getOctonionNumberQ(r_nonL, r_valL)
end,
__mod = function (op1, op2)
local x = p.omath.readOctonionNumber(op1)
local y = p.omath.readOctonionNumber(op2)
return x - y * p.qmath.floor(x / y)
end,
__tostring = function (this)
local nonL, valL = p.omath.readOctonionNumberQpart(this)
local body = ''
if nonL.real ~= 0 then body = tostring(nonL.real) end
if nonL.imag ~= 0 then
if body ~= '' and nonL.imag > 0 then body = body .. '+' end
if nonL.imag == -1 then body = body .. '-' end
if math.abs(nonL.imag) ~= 1 then body = body .. tostring(nonL.imag) end
body = body .. 'i'
end
if nonL.jpart ~= 0 then
if body ~= '' and nonL.jpart > 0 then body = body .. '+' end
if nonL.jpart == -1 then body = body .. '-' end
if math.abs(nonL.jpart) ~= 1 then body = body .. tostring(nonL.jpart) end
body = body .. 'j'
end
if nonL.kpart ~= 0 then
if body ~= '' and nonL.kpart > 0 then body = body .. '+' end
if nonL.kpart == -1 then body = body .. '-' end
if math.abs(nonL.kpart) ~= 1 then body = body .. tostring(nonL.kpart) end
body = body .. 'k'
end
if valL.real ~= 0 then
if body ~= '' and valL.real > 0 then body = body .. '+' end
if valL.real == -1 then body = body .. '-' end
if math.abs(valL.real) ~= 1 then body = body .. tostring(valL.real) .. '*' end
body = body .. 'l'
end
if valL.imag ~= 0 then
if body ~= '' and valL.imag > 0 then body = body .. '+' end
if valL.imag == -1 then body = body .. '-' end
if math.abs(valL.imag) ~= 1 then body = body .. tostring(valL.imag) .. '*' end
body = body .. 'il'
end
if valL.jpart ~= 0 then
if body ~= '' and valL.jpart > 0 then body = body .. '+' end
if valL.jpart == -1 then body = body .. '-' end
if math.abs(valL.jpart) ~= 1 then body = body .. tostring(valL.jpart) .. '*' end
body = body .. 'jl'
end
if valL.kpart ~= 0 then
if body ~= '' and valL.kpart > 0 then body = body .. '+' end
if valL.kpart == -1 then body = body .. '-' end
if math.abs(valL.kpart) ~= 1 then body = body .. tostring(valL.kpart) .. '*' end
body = body .. 'kl'
end
if p._isNaN(nonL.real) or p._isNaN(nonL.imag) or p._isNaN(nonL.jpart) or p._isNaN(nonL.kpart) or
p._isNaN(valL.real) or p._isNaN(valL.imag) or p._isNaN(valL.jpart) or p._isNaN(valL.kpart) then body = 'nan' end
if body == '' then body = '0' end
return body
end,
__unm = function (this)
return p.omath.getOctonionNumberQ(-this.nonL, -this.valL)
end,
__eq = function (op1, op2)
return op1.nonL == op2.nonL and op1.valL == op2.valL
end,
},
readOctonionNumber = function(z)
if type(z) == type({}) then --if already be complex number, don't run string find.
if z.numberType == "complex" then
return p.omath.getOctonionNumber(z.real, z.imag, 0, 0, 0, 0, 0, 0)
elseif z.numberType == "quaternion" then
return p.omath.getOctonionNumberQ(z.real, z.imag, z.jpart, z.kpart, 0, 0, 0, 0)
elseif z.numberType == "octonion" then
return z
end
elseif type(z) == type(0) then
return p.omath.getOctonionNumber(z, 0, 0, 0, 0, 0, 0, 0)
end
end,
readOctonionNumberQpart = function(z)
if type(z) == type({}) then --if already be complex number, don't run string find.
if z.numberType == "complex" then
return qmath.getQuaternionNumber(z.real, z.imag, 0, 0), qmath.getQuaternionNumber(0, 0, 0, 0)
elseif z.numberType == "quaternion" then
return qmath.getQuaternionNumber(z.real, z.imag, z.jpart, z.kpart), qmath.getQuaternionNumber(0, 0, 0, 0)
elseif z.numberType == "octonion" then
return z.nonL, z.valL
end
elseif type(z) == type(0) then
return qmath.getQuaternionNumber(z, 0, 0, 0), qmath.getQuaternionNumber(0, 0, 0, 0)
end
end,
getOctonionNumberQ = function(nonL, valL)
return p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
end,
getOctonionNumber = function(real, imag, jpart, kpart, lpart, ilmag, jlpart, klpart)
OctonionNumber = {}
setmetatable(OctonionNumber,p.omath.OctonionNumberMeta)
function OctonionNumber:update()
self.nonL:update()
self.valL:update()
self.argument = 0
self.length = math.sqrt( self.nonL.length * self.nonL.length + self.valL.length * self.valL.length )
end
function OctonionNumber:clean()
self.nonL:clean()
self.valL:clean()
return self
end
OctonionNumber.nonL = qmath.getQuaternionNumber(real, imag, jpart, kpart)
OctonionNumber.valL = qmath.getQuaternionNumber(lpart, ilmag, jlpart, klpart)
OctonionNumber.numberType = "octonion"
return OctonionNumber
end,
}
function p.test()
--local my_num1 = {nonL=toQnumber("3i-k+2"),valL=toQnumber("5i+4+j")}
--local my_num2 = {nonL=toQnumber("2i-k+1"),valL=toQnumber("4i+3+j")}
--local my_num1 = {nonL=toQnumber("i"),valL=toQnumber("0"),numberType = "octonion"}
--local my_num2 = {nonL=toQnumber("i"),valL=toQnumber("0"),numberType = "octonion"}
local _e = p.omath.getOctonionNumberQ(toQnumber(math.exp(1)), toQnumber("0"))
local _i = p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0"))
local _pi = p.omath.getOctonionNumberQ(toQnumber(math.pi), toQnumber("0"))
mw.logObject(_e)
mw.logObject(_i)
mw.logObject(_pi)
mw.logObject(p.omath.exp(_i*_pi))
local my_num1 = p.omath.getOctonionNumberQ(toQnumber("0"), toQnumber("i"))
local my_num2 = p.omath.getOctonionNumberQ(toQnumber("j"), toQnumber("0"))
local my_num3 = my_num1 * my_num2
local my_num4 = my_num1 + my_num2
local my_num5 = p.omath.getOctonionNumberQ(toQnumber("1+2j"), toQnumber("2+3i"))
mw.logObject(my_num1)
mw.logObject(my_num2)
mw.logObject(my_num3)
mw.logObject(my_num4)
mw.logObject(my_num5)
mw.logObject(my_num5 + my_num4)
mw.logObject(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("2"), toQnumber("0")))
mw.logObject(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")))
mw.logObject(p.omath.re(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0"))))
mw.logObject(p.omath.im(p.omath.getOctonionNumberQ(toQnumber("i"), toQnumber("0")) / p.omath.getOctonionNumberQ(toQnumber("2"), toQnumber("0"))))
--conjugate
end
return p