模組:Complex Number
![]() | 此模块被引用於約5,300個頁面。 為了避免造成大規模的影響,所有對此模块的編輯應先於沙盒或測試樣例上測試。 測試後無誤的版本可以一次性地加入此模块中,但是修改前請務必於討論頁發起討論。 模板引用數量會自動更新。 |
本模組為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")
p.cmath = {
abs=function(z)
local real, imag = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
if imag == 0 then return math.abs(real) end
return math.sqrt(real * real, imag * imag)
end,
is_prime=function(z)
local real, imag = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
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 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+2})
return p.PrimeTable.lists[real] ~= nil
end
end
local value = imag*imag + real*real
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 = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
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,
cos=function(z)
local real, imag = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
return p.cmath.getComplexNumber(math.cos(real) * math.cosh(imag), -math.sin(real) * math.sinh(imag))
end,
sin=function(z)
local real, imag = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
return p.cmath.getComplexNumber(math.sin(real) * math.cosh(imag), math.cos(real) * math.sinh(imag))
end,
cis=function(z)
local real, imag = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
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 = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
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,
log=function(z)
local real, imag = tonumber(z) or z.real, (tonumber(z) and 0) or z.imag
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,
pow=function(op1,op2)
--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,
ComplexNumberMeta = {
__add = function (op1, op2)
local real1, real2 = tonumber(op1) or op1.real, tonumber(op2) or op2.real
local imag1, imag2 = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
return p.cmath.getComplexNumber(real1 + real2, imag1 + imag2)
end,
__sub = function (op1, op2)
local real1, real2 = tonumber(op1) or op1.real, tonumber(op2) or op2.real
local imag1, imag2 = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
return p.cmath.getComplexNumber(real1 - real2, imag1 - imag2)
end,
__mul = 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
return p.cmath.getComplexNumber(a * c - b * d, b * c + a * d)
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,
__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 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.real) - (tonumber(op2) or op2.real) )
local diff_imag1 = math.abs( ( (tonumber(op1) and 0) or op1.imag) - ( (tonumber(op2) and 0) or op2.imag) )
return diff_real < 1e-12 and diff_imag1 < 1e-12
end,
},
getComplexNumber = function(real,imag)
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
return ComplexNumber
end,
toComplexNumber = function(num_str)
local real, imag = p.cmath.toComplexNumberPart(num_str)
if real == nil or imag == nil then return nil end
return p.cmath.getComplexNumber(real, imag)
end,
toComplexNumberPart = function(num_str)
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(
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,
init = function()
p.cmath.pi = p.cmath.getComplexNumber(math.pi, 0)
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.i = p.cmath.getComplexNumber(0, 1)
p.cmath[0],p.cmath[1] = p.cmath.zero,p.cmath.one
return p.cmath
end
}
return p