模組:Complex Number
此模块被引用於約5,100個頁面。 為了避免造成大規模的影響,所有對此模块的編輯應先於沙盒或測試樣例上測試。 測試後無誤的版本可以一次性地加入此模块中,但是修改前請務必於討論頁發起討論。 模板引用數量會自動更新。 |
本模組為Lua定義了一套複數(如虚数、四元數)運算的系統,可提供其他模組呼叫使用,而若要直接在模板或條目中使用可透過Module:Complex Number/Calculate或{{複變運算}}來完成。
關於本模組創建動機詳見Module:TemplateParameters#設計緣由(亦可參考Template_talk:Root)。
模組內容
本模組有4套數學資料結構的定義以及對應的數學運算庫:
使用方法
- 初始化數學庫
local 自訂函數庫名稱 = require("Module:Complex Number").函數庫名稱.init()
- 例如:
local cmath = require("Module:Complex Number").cmath.init()
- 例如:
- 初始化指定數學結構的數字
local 變數名稱 = 自訂函數庫名稱.constructor("描述數字的字串")
- 例如:
local num1 = cmath.constructor("2+3i")
- 例如:
- 執行運算
- 例如:
local num1 = cmath.constructor("2+3i") local num2 = cmath.constructor("4+5i") print(num1 * num2)
- 輸出:-7+22i
- 或者使用函數庫內容:
local num1 = cmath.constructor("i") print(cmath.sqrt(num1))
- 輸出:0.70710678118655+0.70710678118655i
- 例如:
- 若需要在模板中使用,請參閱{{複變運算}}
原理
複數可分為實部和虛部,此特性可以透過Lua的table功能({real=..., imag=...,}
)來實現,同時透過複寫Metatables來完成其各運算子(如+
、-
、*
、/
)來實現複變的基本運算:
p.ComplexNumberMeta = {
__add = function (op1, op2)
return p.ComplexNumber(op1.real + op2.real, imag = op1.imag + op2.imag)
end,
--...
}
function p.ComplexNumber(real, imag)
local complexNumber = {real = op1.real + op2.real, imag = op1.imag + op2.imag}
setmetatable(complexNumber,p.ComplexNumberMeta)
return complexNumber
end
如此一來,只要是設定過Metatables的含實部和虛部的table都可以直接進行複變數的運算。
剩下的部分就是完善數學函數庫math.xxx
的各函數。
比較
函數庫 | 預設的math
|
.cmath
|
.qmath
|
.math
|
.bmath
|
.tagmath 位於Module:Complex Number/Calculate | |
---|---|---|---|---|---|---|---|
說明 | Lua預設提供的math程式庫 | 複數()專用程式庫 | 四元數()專用程式庫 | 預設math 的擴充,定義了上方兩個程式庫中的功能
|
簡單的布林代數 | 會運算成<math></math> 的程式庫
| |
函式庫初始化方式 | 無須初始化 | cmath = require("Module:Complex Number").cmath.init();
|
qmath = require("Module:Complex Number").qmath.init();
|
math = require("Module:Complex Number").math.init();
|
bmath = require("Module:Complex Number").bmath.init();
|
tagmath = require("Module:Complex Number/Calculate").tagmath.init();
| |
數字建構/初始化方式 | tonumber("10"); 10
|
cmath.toComplexNumber("1+i"); cmath.getComplexNumber(1,1);
|
qmath.toQuaternionNumber("i+j+k"); qmath.getQuaternionNumber(0,1,1,1);
|
tonumber("10"); 10
|
bmath.toBoolean("yes");
|
tagmath.toTagMath("a");
| |
四則運算 | 加法a + b
|
lua原生支援 | 邏輯或 | 輸出 | |||
減法a - b
|
lua原生支援 | 輸出 | |||||
乘法a * b
|
lua原生支援 | 邏輯與 | 輸出 | ||||
除法a / b
|
只能除實數 | lua原生支援 | 不存在 | 輸出 | |||
模除a % b
|
以高斯符號定義 | lua原生支援 | 不存在 | ||||
一元運算 | 相反數-a
|
lua原生支援 | 邏輯非 | 輸出 | |||
tostring | lua原生支援 | ||||||
e常數e
|
輸出 | ||||||
圓周率pi
|
lua原生支援 | 輸出 | |||||
虛數單位i
|
輸出 | ||||||
j單位j
|
輸出 | ||||||
k單位k
|
輸出 | ||||||
絕對值abs(a)
|
lua原生支援 | 回傳1或0 | 輸出 | ||||
符号函数sgn(a)
|
回傳1或0 | 輸出 | |||||
共轭复数conjugate(a)
|
原式輸出。 | 輸出 | |||||
輻角arg(a)
|
輸出 | ||||||
平方根sqrt(a)
|
輸出 | ||||||
倒數inverse(a)
|
輸出 | ||||||
分數div(a,b)
|
輸出 | ||||||
數字部件 | 實部re(a)
|
輸出 | |||||
虛部im(a)
|
恆為0 | 輸出 | |||||
非實部nonRealPart(a)
|
恆為0 | 恆為0 | 即将到来 | ||||
純量部 | |||||||
向量部 | |||||||
部件向量tovector(a)
|
單一元素向量 | ||||||
內積dot(a,b)
|
與乘法相同 | 輸出 | |||||
外積outer(a,b)
|
不存在 | 恆為0 | 不存在 | 不存在 | 即将到来 | ||
冪a ^ b
|
只能pow(a,b) | 只能pow(a,b) | lua原生支援 | 只能pow(a,b) | |||
指對數函數 | 指數pow(a,b)
|
lua原生支援 | 輸出 | ||||
自然對數log(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
自然指數exp(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
ciscis(a)
|
不存在 | 輸出 | |||||
高斯符號 | 地板floor(a)
|
lua原生支援 | 不存在 | 輸出 | |||
天花板ceil(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
数值修约round(a)
|
不存在 | 即将到来 | |||||
截尾函數trunc(a,b)
|
不存在 | 輸出 | |||||
三角函數 | 正弦sin(a)
|
lua原生支援 | 不存在 | 輸出 | |||
餘弦cos(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
正切tan(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
餘切cot(a)
|
不存在 | 輸出 | |||||
反三角函數 | 反正弦asin(a)
|
lua原生支援 | 不存在 | 輸出 | |||
反餘弦acos(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
反正切atan(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
反餘切acot(a)
|
不存在 | 輸出 | |||||
雙曲函數 | 雙曲正弦sinh(a)
|
lua原生支援 | 不存在 | 輸出 | |||
雙曲餘弦cosh(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
雙曲正切tanh(a)
|
lua原生支援 | 不存在 | 輸出 | ||||
雙曲餘切coth(a)
|
不存在 | 輸出 | |||||
反雙曲函數 | 雙曲反正弦asinh(a)
|
不存在 | 輸出 | ||||
雙曲反餘弦acosh(a)
|
不存在 | 輸出 | |||||
雙曲反正切atanh(a)
|
不存在 | 輸出 | |||||
雙曲反餘切acoth(a)
|
不存在 | 輸出 |
擴充函數
本模組僅為這些數學結構定義一些基本運算(見上表)。一些較複雜的運算可透過調用Module:Complex_Number/Functions來完成。本模組提供的3個部分(cmath、qmath、math)皆支援Module:Complex_Number/Functions。
- 使用方法
-
mathlib = require("Module:Complex Number/Functions")._init(mathlib, numberConstructer)
- 其中,
mathlib
為已初始化的數學函數庫(如cmath、qmath、math),numberConstructer
為對應該數學函數庫數字結構的建構子函數。 - 所回傳的新mathlib將會包含Module:Complex_Number/Functions中已定義的所有擴充函數。
- 註:詳細使用條件參見Module:Complex_Number/Functions/doc#使用條件,說明了函數庫須具備那些條件方能使用此擴充功能。
定義新的數學庫
Module:Complex Number是一系列數學運算庫,並可以相互兼容。當然也能定義其他兼容的程式庫,但需要符合特定條件,例如需要實作一些需求函數。詳細內容可以參考範例數學庫Module:Complex Number/Example。
若要定義一個新的Module:Complex Number系列函數庫需要實作一個新的物件,並實作其Metatables中的運算子。
定義數學資料結構
數學資料結構需要定義成一個table,並以table來定義或表達所需要的數字。即使數字只有單一物件,也許使用table因為這樣才能透過實作Metatables來完成Module:Complex Number系列函數庫所需的相關功能。
- numberType:本數學資料結構的類型名稱(字串),用於Module:Complex Number系列函數庫的識別(參閱Example的第92行)
- update():更新結構數值的成員函數(參閱Example的第89行)
- clean():去除過小值或誤差值的成員函數,並返回結果。若無此需求,直接返回自身即可。(參閱Example的第90行)
實作metatable
需定義Metatables的 __add(加法)、 __sub(減法)、 __mul(乘法)、 __div(除法)、 __mod(取餘數)、 __unm(相反數)、 __eq(相等判斷)、 __tostring(以字串表達本物件)
定義數學資料結構的建構子
由於數學資料結構需要定義為table因此需要有建構子來賦予該結構初值。建構子需要完成以下步驟:
- 讀取輸入的物件或字串將其存入table物件中(參閱Example的第91行)
- 設定table的metatable為剛才定義的metatable(參閱Example的第88行)
- 定義其他所需的成員變數或函數
定義數學庫的初始化函數
數學庫必須是一個獨立物件,所有的函數皆需定義在數學函數庫物件下(包括數學資料結構的建構子)。初始化數學庫的函數名稱必為init,當中需要定義以下內容:
- 各項常數的定義(參閱Example的第102行)
- numberType成員函數定義為Module:Complex Number中的_numberType(參閱Example的第106行)
- constructor成員函數設定為數學結構的建構子(參閱Example的第107行)
- elements成員變數設定為單位元素的清單(參閱Example的第108行)
完成數學庫的定義
視情況定義列於Module:Complex_Number/doc#比較中的各項函數(如需支援Module:Complex_Number/Functions的情況)。
其他函數庫
require("Module:Complex Number").cmath
- 複變函數庫
require("Module:Complex Number").qmath
- 四元數函數庫
require("Module:Complex Number").math
- 實數函數庫擴充
require("Module:Complex Number").bmath
- 布林代數函數庫
require("Module:Complex Number/Calculate").tagmath
- 輸出為
<math></math>
的運算庫 require("Module:Complex Number/Matrix").mmath
- 矩陣函數庫
require("Module:Complex Number/Dual Number").dumath
- 二元數函數庫
require("Module:Complex Number/Dual Number").ducmath
- 二元複數函數庫
require("Module:Complex Number/Octonion").omath
- 八元數函數庫
require("Module:Complex Number/CayleyDickson").cdmath.init(math_lib)
- 將指定的函數庫
math_lib
套用凯莱-迪克森结构形成新的函數庫(無法自我嵌套) require("Module:Complex Number/CayleyDickson").sdmath
- 八元數套用凯莱-迪克森结构後的形成新的十六元數函數庫
require("Module:Complex Number/CayleyDickson").cdmathOctonion
- 預先套用凯莱-迪克森结构的八元數後的函數庫(可作為十六元數使用)
require("Module:Complex Number/CayleyDickson").cdmathSedenion
- 預先套用凯莱-迪克森结构的十六元數後的函數庫(可作為三十二元數使用)
相關頁面
- Module:Complex_Number/Solver:求解器和部分共用的函數。
--'
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