模組: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 comp_lib = require("Module:Complex_Number")
local qmath = comp_lib.qmath.init()
local toQnumber = qmath.constructor
p.qmath = qmath
p.toQnumber = toQnumber
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,
sqrt=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local q_zero = qmath.getQuaternionNumber(0, 0, 0, 0)
local check_sign = qmath.readComplexNumber(valL)
check_sign:clean()
if valL == q_zero then
return p.omath.getOctonionNumberQ(qmath.sqrt(nonL), qmath.getQuaternionNumber(0, 0, 0, 0))
end
return p.omath.pow(z, 0.5)
end,
root=function(_z,_n,_num)
local z = p.omath.readComplexNumber(_z)
local n = p.omath.readComplexNumber(_n or 2)
local num = p.omath.readComplexNumber(_num or 1)
if num == p.omath.one or num == p.omath.zero or num == nil then
return p.omath.pow(z, p.omath.inverse(n))
end
local sgn_data = p.omath.sgn(p.omath.nonRealPart(z))
if p.omath.abs(p.omath.nonRealPart(z))<1e-14 then sgn_data=p.omath.getOctonionNumberQ(qmath.getQuaternionNumber(0, 1, 0, 0), qmath.getQuaternionNumber(0, 0, 0, 0)) end
local result = p.omath.pow(p.omath.abs(z), p.omath.inverse(n)) * p.omath.exp(sgn_data * (p.omath.arg(z) + (num-1)*(2*math.pi) ) * p.omath.inverse(n))
result:clean()
return result
end,
sin=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.vectorPartOctonion(z)
return ( math.cosh(p.omath.abs(u)) * math.sin(nonL.real) ) + ( p.omath.sgn(u) * math.sinh(p.omath.abs(u)) * math.cos(nonL.real) )
end,
cos=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.vectorPartOctonion(z)
return ( math.cosh(p.omath.abs(u)) * math.cos(nonL.real) ) - ( p.omath.sgn(u) * math.sinh(p.omath.abs(u)) * math.sin(nonL.real) )
end,
tan=function(z)
local theta = p.omath.readComplexNumber(z)
return p.omath.sin(theta) * p.omath.inverse( p.omath.cos(theta) )
end,
cot=function(z)
local theta = p.omath.readComplexNumber(z)
return p.omath.cos(theta) * p.omath.inverse( p.omath.sin(theta) )
end,
asin=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u, v = p.omath.vectorPartOctonion(z),
p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
local sgnu = p.omath.sgn(u)
if math.abs(sgnu.nonL.imag) < 1e-12 and math.abs(sgnu.nonL.jpart) < 1e-12 and math.abs(sgnu.nonL.kpart) < 1e-12 and math.abs(sgnu.valL.real) and
math.abs(sgnu.valL.imag) < 1e-12 and math.abs(sgnu.valL.jpart) < 1e-12 and math.abs(sgnu.valL.kpart) < 1e-12 then sgnu.nonL.imag = 1 end
return -sgnu * p.omath.asinh( v * sgnu )
end,
acos=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u, v = p.omath.vectorPartOctonion(z),
p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
local sgnu = p.omath.sgn(u)
if math.abs(sgnu.nonL.imag) < 1e-12 and math.abs(sgnu.nonL.jpart) < 1e-12 and math.abs(sgnu.nonL.kpart) < 1e-12 and math.abs(sgnu.valL.real) and
math.abs(sgnu.valL.imag) < 1e-12 and math.abs(sgnu.valL.jpart) < 1e-12 and math.abs(sgnu.valL.kpart) < 1e-12 then sgnu.nonL.imag = 1 end
return -sgnu * p.omath.acosh( v )
end,
atan=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u, v = p.omath.vectorPartOctonion(z),
p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
local sgnu = p.omath.sgn(u)
if math.abs(sgnu.nonL.imag) < 1e-12 and math.abs(sgnu.nonL.jpart) < 1e-12 and math.abs(sgnu.nonL.kpart) < 1e-12 and math.abs(sgnu.valL.real) and
math.abs(sgnu.valL.imag) < 1e-12 and math.abs(sgnu.valL.jpart) < 1e-12 and math.abs(sgnu.valL.kpart) < 1e-12 then sgnu.nonL.imag = 1 end
return -sgnu * p.omath.atanh( v * sgnu )
end,
acot=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u, v = p.omath.vectorPartOctonion(z),
p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
local sgnu = p.omath.sgn(u)
if math.abs(sgnu.nonL.imag) < 1e-12 and math.abs(sgnu.nonL.jpart) < 1e-12 and math.abs(sgnu.nonL.kpart) < 1e-12 and math.abs(sgnu.valL.real) and
math.abs(sgnu.valL.imag) < 1e-12 and math.abs(sgnu.valL.jpart) < 1e-12 and math.abs(sgnu.valL.kpart) < 1e-12 then sgnu.nonL.imag = 1 end
return sgnu * p.omath.acoth( v * sgnu )
end,
sinh=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.vectorPartOctonion(z)
return ( math.cos(p.omath.abs(u)) * math.sinh(nonL.real) ) + ( p.omath.sgn(u) * math.sin(p.omath.abs(u)) * math.cosh(nonL.real) )
end,
cosh=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.vectorPartOctonion(z)
return ( math.cos(p.omath.abs(u)) * math.cosh(nonL.real) ) + ( p.omath.sgn(u) * math.sin(p.omath.abs(u)) * math.sinh(nonL.real) )
end,
tanh=function(z)
local theta = p.omath.readComplexNumber(z)
return p.omath.sinh(theta) * p.omath.inverse( p.omath.cosh(theta) )
end,
coth=function(z)
local theta = p.omath.readComplexNumber(z)
return p.omath.cosh(theta) * p.omath.inverse( p.omath.sinh(theta) )
end,
asinh=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
return p.omath.elog( u + p.omath.sqrt( u * u + p.omath.getOctonionNumber(1,0,0,0,0,0,0,0) ) )
end,
acosh=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
return p.omath.elog( u + p.omath.sqrt( u + p.omath.getOctonionNumber(1,0,0,0,0,0,0,0) ) * p.omath.sqrt( u + p.omath.getOctonionNumber(-1,0,0,0,0,0,0,0) ) )
end,
atanh=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
return ( p.omath.elog( p.omath.getOctonionNumber(1,0,0,0,0,0,0,0) + u ) - p.omath.elog( p.omath.getOctonionNumber(1,0,0,0,0,0,0,0) - u ) ) / 2
end,
acoth=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
return ( p.omath.elog( p.omath.getOctonionNumber(1,0,0,0,0,0,0,0) + p.omath.inverse(u) ) - p.omath.elog( p.omath.getOctonionNumber(1,0,0,0,0,0,0,0) - p.omath.inverse(u) ) ) / 2
end,
dot = function (op1, op2)
local nonL1, valL1 = p.omath.readOctonionNumberQpart(op1)
local nonL2, valL2 = p.omath.readOctonionNumberQpart(op2)
return nonL1.real * nonL2.real + nonL1.imag * nonL2.imag + nonL1.jpart * nonL2.jpart + nonL1.kpart * nonL2.kpart +
valL1.real * valL2.real + valL1.imag * valL2.imag + valL1.jpart * valL2.jpart + valL1.kpart * valL2.kpart
end,
outer = function (op1, op2)
local nonL1, valL1 = p.omath.readOctonionNumberQpart(op1)
local nonL2, valL2 = p.omath.readOctonionNumberQpart(op2)
local x1, x2, x3, x4, x5, x6, x7 = nonL1.imag, nonL1.jpart, nonL1.kpart, valL1.real, valL1.imag, valL1.jpart, valL1.kpart
local y1, y2, y3, y4, y5, y6, y7 = nonL2.imag, nonL2.jpart, nonL2.kpart, valL2.real, valL2.imag, valL2.jpart, valL2.kpart
return p.omath.getOctonionNumber(0,
x2*y4 - x4*y2 + x3*y7 - x7*y3 + x5*y6 - x6*y5,
x3*y5 - x5*y3 + x4*y1 - x1*y4 + x6*y7 - x7*y6,
x4*y6 - x6*y4 + x5*y2 - x2*y5 + x7*y1 - x1*y7,
x5*y7 - x7*y5 + x6*y3 - x3*y6 + x1*y2 - x2*y1,
x6*y1 - x1*y6 + x7*y4 - x4*y7 + x2*y3 - x3*y2,
x7*y2 - x2*y7 + x1*y5 - x5*y1 + x3*y4 - x4*y3,
x1*y3 - x3*y1 + x2*y6 - x6*y2 + x4*y5 - x5*y4
)
end,
scalarPartQuaternion=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return qmath.getQuaternionNumber(nonL.real, 0, 0, 0)
end,
scalarPartOctonion=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return p.omath.getOctonionNumber(nonL.real, 0, 0, 0, 0, 0, 0, 0)
end,
nonRealPart=function(z)
return p.omath.vectorPartOctonion(z)
end,
vectorPartOctonion=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
return p.omath.getOctonionNumber(0, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
end,
sgn=function(z)
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 )
if length <= 0 then return p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0) end
return z / length
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,
cis=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.vectorPartOctonion(z)
return p.omath.cos(u) + p.omath.getOctonionNumber(0, 1, 0, 0, 0, 0, 0, 0) * p.omath.sin(u)
end,
exp=function(z) --Cayley-Dickson construction
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u = p.omath.vectorPartOctonion(z)
return ( (p.omath.sgn(u) * math.sin(p.omath.abs(u))) + math.cos(p.omath.abs(u))) * math.exp(nonL.real)
end,
elog=function(z)
local nonL, valL = p.omath.readOctonionNumberQpart(z)
local u, v = p.omath.vectorPartOctonion(z),
p.omath.getOctonionNumber(nonL.real, nonL.imag, nonL.jpart, nonL.kpart, valL.real, valL.imag, valL.jpart, valL.kpart)
return (p.omath.sgn(u) * p.omath.arg(v)) + math.log(p.omath.abs(v))
end,
log=function(z,basez)
if basez~=nil then return p.omath.elog(basez) * p.omath.inverse(p.omath.elog(z)) end
return p.omath.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.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
if check_op2 < 0 then return p.omath.getOctonionNumber(tonumber('inf'), 0, 0, 0, 0, 0, 0, 0) end -- 0^(-n) Infinity
return p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0) -- 0^z === 0, z ≠ 0
end
--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 p.omath.getOctonionNumberQ(qmath.pow(a.nonL, z.nonL), qmath.getQuaternionNumber(0, 0, 0, 0))
end
return p.omath.exp(z * p.omath.elog(a)):clean()
end,
CayleyDickson=function(this) --Cayley-Dickson construction
local nonL, valL = p.omath.readOctonionNumberQpart(this)
local q_zero = qmath.getQuaternionNumber(0, 0, 0, 0)
local body = ''
local function zero_flag(num)
return num ~= 0 and 1 or 0
end
local check_sign = qmath.readComplexNumber(valL)
check_sign:clean()
if nonL ~= q_zero then body = tostring(nonL) end
local lmag_body = ''
if valL ~= q_zero then
if(zero_flag(check_sign.real)+zero_flag(check_sign.imag)+zero_flag(check_sign.jpart)+zero_flag(check_sign.kpart) >= 2)then
lmag_body = '+('.. tostring(valL) ..')'
else
if (
(check_sign.real > 0) or
(check_sign.real == 0 and check_sign.imag > 0) or
(check_sign.real == 0 and check_sign.imag == 0 and check_sign.jpart > 0) or
(check_sign.real == 0 and check_sign.imag == 0 and check_sign.jpart == 0 and check_sign.kpart > 0)
) then lmag_body = '+' .. lmag_body end
if check_sign.real == 1 and check_sign.imag == 0 and check_sign.jpart == 0 and check_sign.kpart == 0 then
else
lmag_body = lmag_body..tostring(valL)
end
end
if lmag_body ~= '' then
body = body .. lmag_body .. '*l'
end
end
if p._isNaN(nonL.real) or p._isNaN(nonL.imag) or p._isNaN(nonL.imag) or p._isNaN(nonL.imag) or
p._isNaN(check_sign.real) or p._isNaN(check_sign.imag) or p._isNaN(check_sign.imag) or p._isNaN(check_sign.imag)then body = 'nan' end
if body == '' then body = '0' end
return body
end,
random=function(op1, op2)
if type(op1)==type(nil) and type(op2)==type(nil) then return p.omath.getOctonionNumberQ(qmath.random(), qmath.getQuaternionNumber(0, 0, 0, 0)) end
local op1_a, op1_b = p.omath.readOctonionNumberQpart(op1)
local op2_a, op2_b = p.omath.readOctonionNumberQpart(op2)
if type(op2)==type(nil) then return p.omath.getOctonionNumberQ(qmath.random(op1_a), qmath.random(op1_b)) end
return p.omath.getOctonionNumberQ(qmath.random(op1_a, op2_a), qmath.random(op1_b, op2_b))
end,
isReal=function(z) return p.omath.abs(p.omath.nonRealPart(z)) < 1e-14 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.readComplexNumber(op1)
local y = p.omath.readComplexNumber(op2)
return x - y * 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,
},
ele=function(id)
local _zero = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0)
local eles = (p.omath.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.omath.getOctonionNumber(z.real, z.imag, 0, 0, 0, 0, 0, 0)
elseif z.numberType == "quaternion" then
return p.omath.getOctonionNumber(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)
elseif type(z) == type(true) then
return p.omath.getOctonionNumber(z and 1 or 0, 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)
elseif type(z) == type(true) then
return qmath.getQuaternionNumber(z and 1 or 0, 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)
local 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,
toOctonionNumber = function(num_str)
local real, imag, jpart, kpart, lpart, ilpart, jlpart, klpart
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 == "complex" then
return p.omath.getOctonionNumber(
num_str.real, num_str.imag, 0, 0, 0, 0, 0, 0
)
elseif num_str.numberType == "quaternion" then
return p.omath.getOctonionNumber(
num_str.real, num_str.imag, num_str.jpart, num_str.kpart, 0, 0, 0, 0
)
elseif num_str.numberType == "octonion" then
return num_str
end
elseif type(num_str) == type(0) then
return p.omath.getOctonionNumber(num_str, 0, 0, 0, 0, 0, 0, 0)
elseif type(num_str) == type(true) then
return p.omath.getOctonionNumber(num_str and 1 or 0, 0, 0, 0, 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, lpart, ilpart, jlpart, klpart = 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), 0, 0, 0, 0
elseif ( (num_str.nonL or {}).numberType == "quaternion" ) then
real, imag, jpart, kpart, lpart, ilpart, jlpart, klpart = qmath.readPart(num_str.nonL), qmath.readPart(num_str.valL or qmath.getQuaternionNumber(0,0,0,0))
else
real, imag, jpart, kpart, lpart, ilpart, jlpart, klpart = p.omath.toOctonionNumberPart(tostring(num_str))
end
if real == nil or imag == nil or jpart == nil or kpart == nil or lpart == nil or ilpart == nil or jlpart == nil or klpart == nil then return nil end
return p.omath.getOctonionNumber(real, imag, jpart, kpart, lpart, ilpart, jlpart, klpart)
end,
toOctonionNumberPart = 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,0,0,0,0 else return 0,0,0,0,0,0,0,0 end end
local body = ''
local real, imag, jpart, kpart, lpart, ilpart, jlpart, klpart = 0, 0, 0, 0, 0, 0, 0, 0
local split_str = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(
mw.ustring.gsub(num_str or '','(%d)%s*%*%s*([ijkl])','%1%2'),
'%s+',''),'%++([%d%.])',',+%1'),'%++([ijkl])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijkl])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijkl])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijkl])',',/1%1'),',')
local first = true
local continue = false
for k,v in pairs(split_str) do
continue = false
local val = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.text.trim(v),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ijkl]+)','+1%1')
if mw.ustring.find(val,"%/") or mw.ustring.find(val,"%*") then return end
if val == nil or val == '' then if first == true then first = false continue = true else return end end
if not continue then
local num_text = mw.ustring.match(val,"[%+%-][%d%.]+[ijkl]*")
if num_text ~= val then return end
local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
if num_part == nil then return end
local f_start, f_end = mw.ustring.find(num_text,"[ijkl]+")
local part_str = ''
if f_start then part_str = mw.ustring.sub(num_text, f_start, f_end) end
if part_str == "" then real = real + num_part -- +1.0
elseif part_str == "i" then imag = imag + num_part -- +i
elseif part_str == "j" then jpart = jpart + num_part -- +j
elseif part_str == "k" then kpart = kpart + num_part -- +k
elseif part_str == "l" then lpart = lpart + num_part -- +l
elseif part_str == "ij" then kpart = kpart + num_part -- +ij == +k
elseif part_str == "ik" then jpart = jpart - num_part -- +ik == -j
elseif part_str == "il" then ilpart = ilpart + num_part -- +il == +il
elseif part_str == "ji" then kpart = kpart - num_part -- +ji == -k
elseif part_str == "jk" then imag = imag + num_part -- +jk == +i
elseif part_str == "jl" then jlpart = jlpart + num_part -- +jl == +jl
elseif part_str == "ki" then jpart = jpart + num_part -- +ki == +j
elseif part_str == "kj" then imag = imag - num_part -- +kj == -i
elseif part_str == "kl" then klpart = klpart + num_part -- +kl == +kl
elseif part_str == "li" then ilpart = ilpart - num_part -- +li == -il
elseif part_str == "lj" then jlpart = jlpart - num_part -- +lj == -jl
elseif part_str == "lk" then klpart = klpart - num_part -- +lk == -kl
end
end
end
return real, imag, jpart, kpart, lpart, ilpart, jlpart, klpart
end,
halfNumberParts = function(num)
local nonL, valL = p.omath.readOctonionNumberQpart(num)
return {nonL, valL}
end,
init = function()
p.omath.pi = p.omath.getOctonionNumber(math.pi, 0, 0, 0, 0, 0, 0, 0)
p.omath["π"] = p.omath.getOctonionNumber(math.pi, 0, 0, 0, 0, 0, 0, 0)
p.omath["°"] = p.omath.getOctonionNumber(math.pi/180, 0, 0, 0, 0, 0, 0, 0)
p.omath.e = p.omath.getOctonionNumber(math.exp(1), 0, 0, 0, 0, 0, 0, 0)
p.omath.nan = p.omath.getOctonionNumber(tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan"))
p.omath.zero = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 0)
p.omath.one = p.omath.getOctonionNumber(1, 0, 0, 0, 0, 0, 0, 0)
p.omath[-1] = p.omath.getOctonionNumber(-1, 0, 0, 0, 0, 0, 0, 0)
p.omath.i = p.omath.getOctonionNumber(0, 1, 0, 0, 0, 0, 0, 0)
p.omath.j = p.omath.getOctonionNumber(0, 0, 1, 0, 0, 0, 0, 0)
p.omath.k = p.omath.getOctonionNumber(0, 0, 0, 1, 0, 0, 0, 0)
p.omath.l = p.omath.getOctonionNumber(0, 0, 0, 0, 1, 0, 0, 0)
p.omath.ij = p.omath.getOctonionNumber(0, 0, 0, 1, 0, 0, 0, 0)-- +k
p.omath.ik = p.omath.getOctonionNumber(0, 0,-1, 0, 0, 0, 0, 0)-- -j
p.omath.il = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 1, 0, 0)-- +il
p.omath.ji = p.omath.getOctonionNumber(0, 0, 0,-1, 0, 0, 0, 0)-- -k
p.omath.jk = p.omath.getOctonionNumber(0, 1, 0, 0, 0, 0, 0, 0)-- +i
p.omath.jl = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 1, 0)-- +jl
p.omath.ki = p.omath.getOctonionNumber(0, 0, 1, 0, 0, 0, 0, 0)-- +j
p.omath.kj = p.omath.getOctonionNumber(0,-1, 0, 0, 0, 0, 0, 0)-- -i
p.omath.kl = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 1)-- +kl
p.omath.li = p.omath.getOctonionNumber(0, 0, 0, 0, 0,-1, 0, 0)-- -il
p.omath.lj = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0,-1, 0)-- -jl
p.omath.lk = p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0,-1)-- -kl
p.omath[0],p.omath[1] = p.omath.zero,p.omath.one
p.omath.numberType = comp_lib._numberType
p.omath.constructor = p.omath.toOctonionNumber
p.omath.elements = {
p.omath.getOctonionNumber(1, 0, 0, 0, 0, 0, 0, 0),
p.omath.getOctonionNumber(0, 1, 0, 0, 0, 0, 0, 0),
p.omath.getOctonionNumber(0, 0, 1, 0, 0, 0, 0, 0),
p.omath.getOctonionNumber(0, 0, 0, 1, 0, 0, 0, 0),
p.omath.getOctonionNumber(0, 0, 0, 0, 1, 0, 0, 0),
p.omath.getOctonionNumber(0, 0, 0, 0, 0, 1, 0, 0),
p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 1, 0),
p.omath.getOctonionNumber(0, 0, 0, 0, 0, 0, 0, 1),
}
return p.omath
end
}
return p