模組:Complex Number/Calculate
此模块被引用於約12,000個頁面。 為了避免造成大規模的影響,所有對此模块的編輯應先於沙盒或測試樣例上測試。 測試後無誤的版本可以一次性地加入此模块中,但是修改前請務必於討論頁發起討論。 模板引用數量會自動更新。 |
此模块使用Lua语言: |
本模組定義了一些數學運算的結構與邏輯。
使用方法
項目 | 語法 | 說明 | 範例 |
---|---|---|---|
數字的表達 |
|
數字的表達可分為實數表達、科學記號和含單位的數。
|
|
四則運算與冪運算 | 運算式運算符運算式
|
依序以中綴表示法表達運算式即可。 | 2+3*5^2 →77
|
函數 | 函數 (參數1,參數2 ...)
|
调用现有函数。所有函數都至少要傳入一個參數。 | factorial(5) →120
|
多組運算 | 運算式1;運算式2
|
僅會顯示最後一組運算的結果 | 2+3;2*3 →6
|
變數定義 | 變數名稱←運算式
|
給特定名稱的變數賦值。需特別注意所有變數的範圍(Scope)皆相同(可想像所有變數皆為全域變數),包括函數中的參數,因此若函數外層已經定義了變數x則函數內部需避免使用同名變數x。 | x←5;x →5
|
函數定義 | 函數名稱:參數1,參數2 ...↦函數運算式;
|
函數的語法為以名稱起始並以冒號區隔函數名稱與定義(函數名稱可留空,但冒號不能省去),整個語法要以分號(; )結尾。位於映射符號(↦ )前方為函數的變數或參數,後方為函數主體定義,即 f : x ↦ f (x) ; 。函數可以有多個變數,但僅能有單個輸出,即或。同時函數語法不建議寫成嵌套結構,即不建議將函數定義內包含另一個函數的定義,但可以分開定義再行組合;此外,函數定義內不能包含分號,因為分號會視為函數的結尾。
|
f:x↦x^2+1;(0);f(5) →26
|
運算符優先序調整 | (運算式要優先計算的運算符運算式)運算符運算式
|
使用括號來令特定運算優先進行。 |
|
運算符
語法 | 名稱 | 元數 | 說明 | 優先 | 範例 | 效果 | math輸出 |
---|---|---|---|---|---|---|---|
基礎算术 | |||||||
+ |
2 | 計算兩數之和 |
9 | 7 + 3 |
10 |
||
- |
2 | 計算兩數之差 |
9 | 7 - 3 |
4 |
||
* |
2 | 計算兩數之乘積 |
10 | 7 * 3 |
21 |
||
× |
2 | 計算兩數之乘積 |
10 | 7 × 3 |
21 |
||
/ |
2 | 計算兩數相除之商 |
10 | 7 / 3 |
2.3333333333333 |
||
÷ |
2 | 計算兩數相除之商 |
10 | 7 ÷ 3 |
2.3333333333333 |
||
% |
2 | 計算兩數相除之餘數 |
10 | 7 % 3 |
1 |
||
^ |
2 | 計算兩數之冪運算 |
12 | 7 ^ 3 |
343 |
||
e |
2 | 當e左鄰一實數、右鄰一整數時,則為科學記號,以 256e-3 為例,其代表的結果為。要注意的是左邊的數必為單一實數、右邊的數必為整數,可為負數,且中間不能有空格。 |
∞ | 12.3e4 |
123000 |
||
() |
1 | 改變運算優先順序 |
∞ | 2*(2+3) |
10 |
||
数论 | |||||||
+ |
1 | 表達一正數 |
14 | +7 |
7 |
||
- |
1 | 計算一數的相反數 |
14 | -7 |
-7 |
||
% |
2 | 計算兩數相除之餘數 |
10 | 7 % 3 |
1 |
||
布尔代数 | |||||||
& |
2 | 兩邏輯是否皆為真 |
5 | (1=1) & (1=2) |
0 |
||
↑ |
2 | 兩邏輯是否不全為真 |
5 | (1=1) ↑ (1=2) |
1 |
||
| |
2 | 兩邏輯是否有一者為真 |
4 | (1=1) | (1=2) |
1 |
||
↓ |
2 | 兩邏輯是否全為假 |
4 | (1=1) ↓ (1=2) |
0 |
||
⊕ |
2 | 兩邏輯是否相異 |
4 | (1=1) ⊕ (1=2) |
1 |
||
⇔ |
2 | 兩邏輯是否相同 |
4 | (1=1) ⇔ (1=2) |
0 |
||
~ |
1 | 邏輯否定 |
13 | ~(1=2) |
1 |
||
and |
2 | 邏輯且的字母模式。使用時須與前後文各間隔至少一個空格 |
5 | (1=1) and (1=2) |
0 |
||
nand |
2 | 邏輯與非的字母模式。使用時須與前後文各間隔至少一個空格 |
5 | (1=1) nand (1=2) |
1 |
||
or |
2 | 邏輯或的字母模式。使用時須與前後文各間隔至少一個空格 |
4 | (1=1) or (1=2) |
1 |
||
nor |
2 | 邏輯或非的字母模式。使用時須與前後文各間隔至少一個空格 |
4 | (1=1) nor (1=2) |
0 |
||
xor |
2 | 邏輯異或的字母模式。使用時須與前後文各間隔至少一個空格 |
4 | (1=1) xor (1=2) |
1 |
||
xnor |
2 | 邏輯若且唯若的字母模式。使用時須與前後文各間隔至少一個空格 |
4 | (1=1) xnor (1=2) |
0 |
||
not |
1 | 邏輯非的字母模式。使用時須與前後文各間隔至少一個空格 |
13 | not (1=2) |
1 |
||
数值修约 | |||||||
round |
2 | round 的運算子模式,會將一數四捨五入到指定的位數。使用時須與前後文各間隔至少一個空格 |
8 | π round 6 |
3.141593 |
||
代数 | |||||||
⋅ |
2 | 表達一數的係數 |
10 | 2⋅π |
6.2831853071796 |
||
← |
2 | 給予變數數值 |
7 | x ← 7;x |
7 |
||
↦ |
2 | 給予函數定義 |
12 | :x,y↦x^2+y^2;(5,2) |
29 |
||
: |
構成函數
|
2 | 冒號( : )為定義函數時區隔函數的名稱與函數的主體,而冒號(: )與分號(; )的區間構成一個函數的定義。在冒號左邊的內容為函數的名稱,在冒號右邊的內容為函數的內容。若函數沒有名稱也需要輸寫冒號。 |
7 | f:x↦x^2;(5) |
25 |
|
, |
2 | 產生數組供多元函數使用 |
1 | 7, 3 |
7, 3 |
||
複變 | |||||||
* |
1 | 計算一數的共軛複數 |
14 | *(7+3i) |
7-3i |
||
i |
1 | 表達純虛數 |
∞ | 3i |
3i |
||
二元关系 | |||||||
> |
2 | 比較兩數大小 |
6 | 7 > 3 |
1 |
||
< |
2 | 比較兩數大小 |
6 | 7 < 3 |
0 |
||
≥ |
2 | 比較兩數大小 |
6 | 7 ≥ 3 |
1 |
||
≤ |
2 | 比較兩數大小 |
6 | 7 ≤ 3 |
0 |
||
= |
2 | 兩數是否相等 |
3 | 7 = 3 |
0 |
||
≠ |
2 | 兩數是否不相等 |
3 | 7 ≠ 3 |
1 |
||
技術性 | |||||||
; |
2 | 分隔兩運算式,結果將取最後一個分號後的結果 |
1 | 7 ; 3 |
3 |
||
return |
1 | 返回數值。需注意return後方必須跟著一個數值或表達式,否則會變成未定義行為而出現預期外的結果。 |
2 | return 7;8 |
7 |
||
三角函数 | |||||||
° |
1 | 用於表示角度單位的符號。 |
10 | 180° |
3.1415926535898 |
||
π |
1 | 表示圓周率。 |
10 | 3π |
9.4247779607694 |
- 註:另有
>=
、<=
、==
(相等判斷)、~=
(不相等判斷)、!=
(不相等判斷)、@=
(數值指派)、+=
(相加指派)、-=
(相減指派)、*=
(相乘指派)、/=
(相除指派)、^=
(冪指派)、&=
(邏輯與指派)、|=
(邏輯或指派)可供使用,其會自動替換為上表中對應的運算元。指派運算元須注意等號左邊必須是一個單一變數詞語,不可以是括弧或函數變換的結果。
常數和數值
語法 | 名稱 | 別名 | 說明 | 數值 | math輸出 |
---|---|---|---|---|---|
e |
自然底數 | 自然對數函數的底數 | 2.718281828459 | ||
i |
虛數單位 | 表達純虛數 | i | ||
j |
四元數單位j | 表達純四元數虛數j | j | ||
k |
四元數單位k | 表達純四元數虛數k | k | ||
nan |
非數 | 用於表示數學上未定義的數值,或計算發生錯誤的數值。 | nan | ||
nil |
空值 | null |
空值。在math模式下顯示為空白,用於表達或傳遞無參數的函數之參數。請注意,由於此值為空值,因此請勿將此值參與運算,以免發生錯誤。 | nil | |
° |
角度單位 | 用於表示角度單位的符號。 | 0.017453292519943 | ||
π |
圓周率 | pi |
表示圓周率。 | 3.1415926535898 | |
ω |
艾森斯坦整数單位 | 表達艾森斯坦整数單位。 | -0.5+0.86602540378444i |
函數
語法 | 名稱 | 參數 數量 |
說明 | 範例 | 效果 | math輸出 |
---|---|---|---|---|---|---|
基礎算术 | ||||||
div |
2 | 用於在math輸出時,以分數的形式顯示 |
div(7,3) |
2.3333333333333 |
||
dot |
2 | 計算兩數的內積。 |
dot(7,3) |
21 |
||
pow |
2 | 計算兩數之冪運算 |
pow(7,3) |
343 |
||
数论 | ||||||
gcd |
不定 | 計算多個數的最大公因數。 |
gcd(7,21) |
7 |
||
lcm |
不定 | 計算多個數的最小公倍數。 |
lcm(7,3,21) |
21 |
||
digits |
1 | 取得整數的位數個數 |
digits(7321) |
4 |
||
divisor |
2 | 取得某數的第n個正因數 |
divisor(6,1),divisor(6,2),divisor(6,3),divisor(6,4) |
1, 2, 3, 6 |
||
primedivisor |
2 | 取得某數的第n個質因數 |
primedivisor(210,1),primedivisor(210,2),primedivisor(210,3),primedivisor(210,4) |
2, 3, 5, 7 |
||
divisorsigma |
2 | 計算特定整數的除數函數 |
divisorsigma(1,6) |
12 |
||
eulerphi |
1 | 取得小於等於n的正整數中與n互質的數的數目 |
eulerphi(8) |
4 |
||
findnext |
向後尋找
|
2 | 尋找下一個符合條件的整數 |
findnext(:x↦x % 6 = 0;,6) |
12 |
|
findlast |
向前尋找
|
2 | 尋找前一個符合條件的整數 |
findlast(:x↦x % 6 = 0;,10) |
6 |
|
初等函數 | ||||||
abs |
1 | 計算一數與原點的歐幾里得距離 |
abs(-3) |
3 |
||
log |
1 | log(e) |
1 |
|||
log |
2 | log(2,16) |
4 |
|||
sgn |
1 | sgn(-7) |
-1 |
|||
sqrt |
1 | 計算一數的主平方根值 |
sqrt(16) |
4 |
||
inverse |
1 | inverse(7) |
0.14285714285714 |
|||
exp |
1 | exp(π⋅i) |
-1 |
|||
数值修约 | ||||||
floor |
1 | 向下取整 |
floor(7.3) |
7 |
||
ceil |
1 | 向上取整 |
ceil(7.3) |
8 |
||
round |
3 | 對一數進行四捨五入。第一參數為欲四捨五入的數字;第二參數為欲四捨五入的位數;第三參數為當數值修約底數非十進制時的底數。 |
round(π,6) |
3.141593 |
||
trunc |
2 | 對一數取截尾函數。第一參數為欲截尾的數字;第二參數為欲截尾的位數。 |
trunc(π,6) |
3.141592 |
||
特殊函數 | ||||||
binomial |
2 | 計算二項式係數。亦可以被理解為從n個相異元素中取出k個元素的方法數。 |
binomial(7,3) |
35 |
||
factorial |
1 | 計算一數的階乘 |
factorial(7) |
5040 |
||
gamma |
1 | 計算一數的Γ函数 |
gamma(7) |
720 |
||
LambertW |
2 | 計算一數的朗伯W函数 |
LambertW(1) |
0.56714329040978 |
||
代数 | ||||||
norm |
2 | 計算一數或向量的範數 |
norm(3+4i,2) |
5 |
||
summation |
3 | 計算以函數表達之數列的總和。第一參數為數列首項;第二參數為數列末項;第三參數為用以表達數列的函數 |
summation(1,5,:x↦x^2;) |
55 |
||
product |
3 | 計算以函數表達之數列的連乘積。第一參數為數列首項;第二參數為數列末項;第三參數為用以表達數列的函數 |
product(1,5,:it↦it;) |
120 |
||
<不定> |
不定 | 调用自行定义的函数,這些函數通常是或。以 f:x↦x^2;;f(5) 為例,其中f:x↦x^2; 定義了函數,並调用了函数。函數的語法為以名稱起始並以冒號區隔函數名稱與定義(函數名稱可留空,但冒號不能省去),整個語法要以分號(; )結尾。位於映射符號(↦ )前方為函數的變數或參數,後方為函數主體定義。函數可以有多個變數,但僅能有單個輸出;同時函數語法不建議使用嵌套結構,即不建議將函數定義內包含另一個函數的定義,但可以分開定義再行組合;此外,函數定義內不能包含分號,因為分號會被視為函數結尾。 |
f:x↦x^2;,f(5) |
f, 25 |
||
ele |
1 | 取得特定代數空間(如四元數)的第n個單位元,如ele(2)即e₂=j |
ele(2) |
j |
||
微積分 | ||||||
limit |
3 | 計算一函數在x=x₀的極限。需注意此運算為估計,運算精度約僅有7位有效數字。第一參數為x₀;第二參數為逼近方向,1表示右極限、-1表示左極限、0表示一般的極限,此時若極限不存在則返回nan;第三參數為欲求極限的函數。 |
limit(0,1,:x↦div(x,x);) |
1 |
||
diff |
2 | 計算一函數在x=x₀的導數。需注意此運算為估計,運算精度約僅有7位有效數字。第一參數為欲求導數x=x₀的函數;第二參數為x₀。 |
diff(cos,div(2⋅pi,3)) |
-0.86602540379001 |
||
integral |
4 | 計算一函數在從a到b的定積分。需注意此運算為估計,運算精度約僅有7位有效數字,且積分範圍(a和b的距離)越大,精確度會越低。第一參數為a、第一參數為b、第三參數為欲求定積分的函數、第四參數為取樣數,若未填寫則使用預設值2000。 |
integral(0,π,:x↦sin(x);) |
2 |
||
複變 | ||||||
re |
1 | 取得一數的實數部分。 |
re(7+3i) |
7 |
||
im |
1 | 取得一數的虛數部分 |
im(7+3i) |
3 |
||
nonRealPart |
1 | 取得一數的非實數部分 |
nonRealPart(7+3i+2j+k) |
3i+2j+k |
||
scalarPartQuaternion |
1 | 取得四元數的純量部分 |
scalarPartQuaternion(7+3i+2j+k) |
7 |
||
vectorPartQuaternion |
1 | 取得四元數的向量部分 |
vectorPartQuaternion(7+3i+2j+k) |
3i+2j+k |
||
arg |
1 | 計算一複數的輻角 |
arg(3+7i) |
1.1659045405098 |
||
cis |
1 | 計算一數的純虛指數函數值 |
cis(π) |
-1 |
||
conjugate |
1 | conjugate(7+3i) |
7-3i |
|||
統計 | ||||||
average |
不定 | 計算數組的算術平均數。 |
average(7,3,2,1) |
3.25 |
||
geoaverage |
不定 | 計算數組的幾何平均數 |
geoaverage(7,3,2,1) |
2.5457298950218 |
||
maximum |
不定 | 計算數組的最大值 |
maximum(7,3,2,1) |
7 |
||
minimum |
不定 | 計算數組的最小值 |
minimum(7,3,2,1) |
1 |
||
selectlist |
不定 | 輸出數組中指定位置的元素。第一參數為要輸出的元素序號,第二參數之後為數組 |
selectlist(2,7,3,2,1) |
3 |
||
σ |
不定 | 計算數組的標準差 |
σ(7,3,2,1) |
2.2776083947861 |
||
技術性 | ||||||
hide |
隱藏運算式
|
不定 | 在math模式下隱藏指定運算式。本函數的結果為最後一個參數。可作為連續運算式的表達,所有已輸入的運算式皆會計算,但結果會隱藏。亦可用於自訂函數中的多運算式表達。 |
hide(y←5,x←7,x⋅y),5 |
35, 5 |
|
exprs |
一系列運算式
|
不定 | 在math模式時顯示所有運算式,運算結果為最後一則運算式。可作為連續運算式的表達,所有已輸入的運算式皆會計算。 |
exprs(y←5,x←7,x⋅y),5 |
35, 5 |
|
lastexpr |
最後一則運算式
|
不定 | 在math模式時顯示最後一則運算式,運算結果也為最後一則運算式。可作為連續運算式的表達,所有已輸入的運算式皆會計算。 |
lastexpr(y←5,x←7,x⋅y),5 |
35, 5 |
|
equalexpr |
連續等式
|
不定 | 生成連續等式。 |
equalexpr(2+2,2*2) |
4 |
|
call |
呼叫函數
|
不定 | 呼叫一個函數。用於處理匿名函數或返回值是函數的情況。 |
call((:x,y↦sin(x)+cos(y);),π,0) |
1 |
|
<functionName>AtModule<ModulePageName> |
不定 | 调用其他模块的函数。須注意函數名稱必須是純英文、模組名稱也必須是純英文,不能有空格或其他符號。例如若需要呼叫Module:Element中的 getAtomicWeight 函數,則須表示為getAtomicWeightAtModuleElement 。 |
getAtomicWeightAtModuleElement(10) |
20.1797 |
||
range |
指定範圍
|
3 | 指定一範圍,當一數落在該範圍外則視為非數(NaN)。第一參數為要判定的數,第二和第三參數分別為範圍的最小和最大值。 |
range(7,1,5),range(4,1,5) |
nan, 4 |
|
if |
3 | 指定特定條件下時的運算式。第一參數為條件、第二參數為條件為真時的運算式、第三參數為條件為假時的運算式。 |
if(3>2,1,0) |
1 |
||
iff |
函數型條件運算式
|
3 | 同if,不過參數可以是函數,條件成立時才會呼叫。 |
iff(3>2,:nil↦1;,:nil↦2;) |
1 |
|
ifelse |
條件運算式 if...else
|
不定 | 類似if,用法為ifelse(條件1, 條件1為真的結果, 條件2, 條件2為真的結果, ... , 條件n, 條件n為真的結果, 條件皆為假的結果) |
ifelse(3>2,10,3<2,20,30) |
10 |
|
ifelsef |
函數型條件運算式 if...else
|
不定 | 同ifelse,不過參數可以是函數,條件成立時才會呼叫。 |
ifelsef(3>2,:nil↦10;,3<2,:nil↦20;,:nil↦30;) |
10 |
|
random |
2 | 取一個隨機數。若無指定參數,或參數中包含非數(NaN),則取0-1之間的隨機實數;若指定了參數1,則取1到參數1之間的隨機數;若指定了參數1與參數2,則取參數1到參數2之間的隨機數 |
random(1,10) |
10 |
||
randomseed |
設定隨機種子碼
|
1 | 將隨機數的種子碼設定為輸入的參數,並返回實際設定的種子碼。若輸入的參數非實數則用當前時間隨機產生種子碼。 |
randomseed(10) |
10 |
|
三角函数 | ||||||
sin |
1 | 計算一數的正弦值 |
sin(π) |
0 |
||
cos |
1 | 計算一數的餘弦值 |
cos(π) |
-1 |
||
tan |
1 | 計算一數的正切值 |
tan(π) |
0 |
||
cot |
1 | 計算一數的餘切值 |
cot(div(π,2)) |
0 |
||
sec |
1 | 計算一數的正割值 |
sec(π) |
-1 |
||
csc |
1 | 計算一數的餘割值 |
csc(div(π,2)) |
1 |
||
asin |
1 | 計算一數的反正弦值 |
asin(1) |
1.5707963267949 |
||
acos |
1 | 計算一數的反餘弦值 |
acos(1) |
0 |
||
atan |
1 | 計算一數的反正切值 |
atan(1) |
0.78539816339745 |
||
acot |
1 | 計算一數的反餘切值 |
acot(1) |
0.78539816339745 |
||
asec |
1 | 計算一數的反正割值 |
asec(1) |
0 |
||
acsc |
1 | 計算一數的反餘割值 |
acsc(1) |
1.5707963267949 |
||
sinh |
1 | 計算一數的雙曲正弦值 |
sinh(π) |
11.548739357258 |
||
cosh |
1 | 計算一數的雙曲餘弦值 |
cosh(π) |
11.591953275522 |
||
tanh |
1 | 計算一數的雙曲正切值 |
tanh(π) |
0.99627207622075 |
||
coth |
1 | 計算一數的雙曲餘切值 |
coth(π) |
1.0037418731973 |
||
sech |
1 | 計算一數的雙曲正割值 |
sech(π) |
0.086266738334054 |
||
csch |
1 | 計算一數的雙曲餘割值 |
csch(π) |
0.086589537530047 |
||
asinh |
1 | 計算一數的雙曲反正弦值 |
asinh(1) |
0.88137358701954 |
||
acosh |
1 | 計算一數的雙曲反餘弦值 |
acosh(1) |
0 |
||
atanh |
1 | 計算一數的雙曲反正切值 |
atanh(0.5) |
0.54930614433405 |
||
acoth |
1 | 計算一數的雙曲反餘切值 |
acoth(1.5) |
0.80471895621705 |
||
asech |
1 | 計算一數的雙曲反正割值 |
asech(1) |
0 |
||
acsch |
1 | 計算一數的雙曲反餘割值 |
acsch(1) |
0.88137358701954 |
||
cis |
1 | 計算一數的純虛指數函數值 |
cis(π) |
-1 |
||
gd |
1 | 計算一數的古德曼函數值 |
gd(e) |
1.4390113159637 |
||
arcgd |
1 | 計算一數的反古德曼函數值 |
arcgd(1) |
1.2261911708835 |
||
cogd |
1 | 計算一數的餘古德曼函數值 |
cogd(π) |
0.08648169656714 |
local p = {}
local getArgs = require('Module:Arguments').getArgs
local ext_mathlib = require("Module:Complex Number/Functions")._init
local comp_number = nil
local TrackingCategory = require('Module:TrackingCategory')
local Operators = require('Module:Complex_Number/Calculate/Operators')
local strip_marker_temp, strip_marker_temp_len = {}, 0
local noop_func = function()end
p.use_other_module = false
p.symbol_table=Operators.symbol_table
--======== public tools ========
function p._remove_strip_marker(str)return mw.text.decode(mw.text.unstrip(str)) end
function p._load_strip_marker(str)return mw.ustring.gsub(mw.text.decode(mw.text.unstripNoWiki(str)),"\127'\"`UNIQ.-QINU`\"'\127",function(strip)
strip_marker_temp_len = strip_marker_temp_len + 1
local idx_az = numberToAZ(strip_marker_temp_len)
strip_marker_temp[idx_az] = strip
return ' UNQ' .. idx_az .. ' '
end)end
function p._function_preprocessing(input_str,math_lib, number_Constructer, debug_flag, jsut_load)
local input_fo, ftable = Operators.function_preload(input_str,{},math_lib, number_Constructer, debug_flag, p.nocalc, jsut_load)
if type(ftable)~=type({"table"})then return input_fo, {} end
local final_scope=Operators.fill_function(ftable,{})
final_scope=Operators.fill_scope(final_scope, math_lib, number_Constructer, debug_flag, p.calc_by_postfix)
return input_fo, final_scope
end
function p._re_math_output(unmathstr)
return tostring(p._preCalculate({tostring(unmathstr):gsub('%*','⋅'),class="mathtag"}))
end
function p._adj_math_output(unmathstr)
return mw.text.trim(mw.ustring.gsub(" "..unmathstr.." ","ω","\\omega "):gsub("ε","\\varepsilon ")
:gsub("([^%a])inf([^%a])","%1\\infty %2"):gsub("([^%a])nan([^%a])","%1\\mathrm{NaN}%2")
:gsub("([%+%-]?)(%d*%.?%d+)e([%+%-]?%d+)","%1%2\\times 10^{%3}"))
end
function p._randomseed()math.randomseed(math.floor(os.time() * os.clock()))end
function p._getNumString(input_string, exp_flag)
local str, shift_digits = p.scientific2number(mw.ustring.upper(input_string), exp_flag)
local int_digits, float_digits = {}, {}
if mw.ustring.find(input_string, "[;:]") then
str = mw.ustring.gsub(str, "[^;:,%d%.]", "")
local pre_digits = mw.text.split(str, "[,:]")
local doing_int = true
for i=1,#pre_digits do
if doing_int then
local find_point = mw.ustring.find(pre_digits[i], "[;%.]")
if find_point then
doing_int = false
int_digits[#int_digits + 1] = tonumber( ({mw.ustring.gsub(mw.ustring.sub(pre_digits[i], 1, find_point-1), "[;%.]", "")})[1] ) or 0
float_digits[#float_digits + 1] = tonumber( ({mw.ustring.gsub(mw.ustring.sub(pre_digits[i], find_point+1, -1), "[;%.]", "")})[1] ) or 0
else
int_digits[#int_digits + 1] = tonumber( ({mw.ustring.gsub(pre_digits[i], "[;%.]", "")})[1] ) or 0
end
else
float_digits[#float_digits + 1] = tonumber( ({mw.ustring.gsub(pre_digits[i], "[;%.]", "")})[1] ) or 0
end
end
if #int_digits == 0 then int_digits[1] = 0 end
if #float_digits == 0 then float_digits[1] = 0 end
else
str = mw.ustring.gsub(str, "[^%.%d%a]", "")
local point_pos = mw.ustring.find(str, "%.")
local int_str, float_str = ((point_pos or 2) <= 1) and "0" or mw.ustring.sub(str, 1, (point_pos or 0)-1), point_pos and mw.ustring.sub(str, point_pos+1, -1) or ''
float_str = mw.ustring.gsub(float_str, "%.", "")
local char_0 = mw.ustring.codepoint('0')
local char_A = mw.ustring.codepoint('A')
local char_Z = mw.ustring.codepoint('Z')
local int_strlen, float_strlen = mw.ustring.len(int_str), mw.ustring.len(float_str)
for i=1,int_strlen do
local code_point = mw.ustring.codepoint(mw.ustring.sub(int_str,i,i))
if code_point < char_A and code_point >= char_0 then code_point = code_point - char_0
elseif code_point <= char_Z then code_point = code_point - char_A + 10 end
int_digits[i] = code_point
end
for i=1,float_strlen do
local code_point = mw.ustring.codepoint(mw.ustring.sub(float_str,i,i))
if code_point < char_A and code_point >= char_0 then code_point = code_point - char_0
elseif code_point <= char_Z then code_point = code_point - char_A + 10 end
float_digits[i] = code_point
end
end
return int_digits, float_digits
end
--======== local tools ========
local function numberToAZ(num)
local body = ''
local s = tostring(math.floor(tonumber(num)))
for i = 1, mw.ustring.len(s) do
local char_id = tonumber(mw.ustring.sub(s, i, i)) + 65
char_id = char_id + ((char_id >= 73) and 3 or 0)
body = body .. mw.ustring.char(char_id)
end
return body
end
local function _subst_strip(str)
local UNIQ mw.ustring.gsub(str, "UNQ(%a+)$", function(num) UNIQ = UNIQ or num end)
return strip_marker_temp[UNIQ or -1] or str
end
local function _subst_error_strip(str)
local UNIQ mw.ustring.gsub(str, "UNQ(%a+)$", function(num) UNIQ = UNIQ or num end)
return mw.ustring.gsub(strip_marker_temp[UNIQ or -1] or str, "\127'\"`UNIQ%-%-(%a+).-QINU`\"'\127", "<%1></%1>")
end
local function stringToTable(s) --字串轉陣列
local t, i = {}, 1
while i <= mw.ustring.len(s) do
if mw.ustring.sub(s, i, i) ~= ' ' then
local j, k = mw.ustring.find(s,"[%d%a]+",i)
if (j or (i+1)) > i then
t[#t + 1] = mw.ustring.sub(s, i, i)
else
t[#t + 1] = mw.ustring.sub(s, j, k)
i = k
end
end
i = i + 1
end
return t
end
local function print_sk(sk,sp)
local body, sp_checker = '', mw.text.trim(sp or '')
for i = 1,#sk do
local checker = ((type(sk[i]) == type({})) and sk[i].name or nil) or sk[i]
if type(checker) == type({}) then
local cats = ""
for cati=1,#checker do if cats ~= "" then cats = cats .. ',' end cats = cats .. tostring(checker[cati])end checker = cats
end
if mw.text.trim( (type(checker)==type(noop_func))and "function" or checker ) ~= sp_checker then
if body ~= '' then body = body .. (sp or ' ') end
if type(sk[i]) == type({}) and sk[i].name then
if sk[i].name == "$END" then body = body .. '$' else body = body .. sk[i].name end
else
if tostring(sk[i]) == 'table' and sk[i].assign=="assign" then body = body .. (tostring(sk[i][1])=="$END" and "${字串結尾}" or _subst_error_strip(tostring(sk[i][1])))
else body = body .. _subst_error_strip(tostring(sk[i])) end
end
end
end
return body
end
--======== template tools ========
function p.checkModuleClass(cls)
local class = ((type(cls)==type({}))and( ((cls.args or {})[1]) or cls[1] or '')or( (type(cls)==type("string")) and cls or ''))or''
if mw.ustring.sub(class,1,7):upper()=="MODULE:" then
local data = mw.ustring.sub(class, 8, -1)
local func = mw.ustring.find(data,"%.")
local modu = mw.ustring.sub(data, 1, func -1)
func = mw.ustring.sub(data, func + 1, -1)
return mw.text.trim(modu), mw.text.trim(func)
end
return ''
end
function p.scientific2number(input_str, exp_flag)
local inputstr = input_str
if type(input_str) == type({"table"}) then
inputstr = (input_str.args or {})[1] or input_str[1] or ''
elseif type(input_str) ~= type("string") then
inputstr = tostring(input_str)
end
local input_numstr = mw.text.trim(inputstr)
local numstr, flag = input_numstr
local exp_num = 0
local sign_str = mw.ustring.sub(numstr,1,1)
if not (sign_str=='+' or sign_str=='-' or sign_str=='−') then
sign_str=''
else
numstr = mw.ustring.sub(numstr,2,-1)
end
numstr, flag = mw.ustring.gsub(numstr, "^%s*([%d%.]+)%s*[Ee]%s*([+-−]"..(exp_flag and '' or '-').."%d+)%s*$", function(number_name, dig_str)
local digits = mw.ustring.gsub(dig_str, "%+", "")
digits = mw.ustring.gsub(digits, "[-−]+", "-")
exp_num = tonumber(digits) or 0
return number_name
end)
numstr = numstr ..'.'
if flag <= 0 then return input_numstr end
numstr = mw.ustring.gsub(numstr, "[^%d%.]", "")
local pti, ptat = 0, (({mw.ustring.find(numstr, "%.")})[1]or 2)-1
numstr = mw.ustring.gsub(numstr, "%.", "")
local numlen = mw.ustring.len(numstr)
if ptat + exp_num > 0 then
if numlen < ptat + exp_num then
numstr = numstr .. string.rep( '0', ptat + exp_num - numlen )
elseif numlen > ptat + exp_num then
numstr = mw.ustring.sub(numstr, 1, ptat + exp_num)..'.'..mw.ustring.sub(numstr, ptat + exp_num+1, -1)
end
elseif ptat + exp_num <= 0 then
numstr = '0.' .. ((ptat + exp_num==0) and '' or string.rep( '0', - ptat - exp_num )) .. numstr
end
return sign_str .. numstr
end
--======== main ========
function p._preCalculate(frame, error_func)
local args
local can_math = false
local should_math = false
if frame == mw.getCurrentFrame() then
-- We're being called via #invoke. The args are passed through to the module
-- from the template page, so use the args that were passed into the template.
args = getArgs(frame) --frame.args
local yesno = require('Module:Yesno')
can_math = yesno(args['use math'] or args['use_math'])
should_math = yesno(args['should math'] or args['should_math'])
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local yesno = require('Module:Yesno')
if yesno(args.useOtherModule or 'no') == true then p.use_other_module = true end
if comp_number == nil then comp_number = require("Module:Complex Number") end
local cmath, qmath, bmath = comp_number.cmath.init(), comp_number.qmath.init(), comp_number.bmath.init()
local mathtag = p.tagmath.init()
local math_class = args['class']or''
if mw.text.trim(math_class) == '' then math_class = "cmath" end
local mymath = cmath
local mytomath = cmath.toComplexNumber
if mw.ustring.sub(math_class,1,7):upper()=="MODULE:" then
local module_name, math_lib_name = p.checkModuleClass(math_class)
xpcall(function()
local load_module = require("Module:"..module_name)
if load_module ~= nil then
local load_math_lib = load_module[math_lib_name]
if load_module ~= nil then
local func_type = type(noop_func)
local my_math_lib = (type(load_math_lib.init) == func_type) and load_math_lib.init() or load_math_lib
if type(my_math_lib.constructor) == func_type then
math_class = "mymath"
mymath = my_math_lib
mytomath = my_math_lib.constructor
end
end
end
end,noop_func)
end
local input_math_lib = ( {
cmath = cmath,
qmath = qmath,
bmath = bmath,
mathtag = mathtag,
mymath = mymath
} ) [ math_class ]
local input_to_number = (( {
cmath = cmath.toComplexNumber,
qmath = qmath.toQuaternionNumber,
bmath = bmath.toBoolean,
mathtag = mathtag.toTagMath,
mymath = mytomath
} ) [ math_class ] )
return p.calc(p._load_strip_marker(args[1] or args['1'] or ''), input_math_lib , input_to_number, nil, nil, error_func ),
can_math, should_math, input_math_lib, input_to_number, args
end
function p.templateCalculate(frame)
p._randomseed()
local body, can_math, should_math, input_math_lib, input_to_number, args = p._preCalculate(frame)
if type(body) == type("string") then
if body:find("function") then
body = body:gsub("function([A-Z]+)",function(func_id)
local result = func_id:gsub("[A-Z]",function(char_it)
local char_id = char_it:byte(1,1)
local num_id = char_id - 65
return tostring(num_id - ((num_id>=10) and 3 or 0))
end)
return "function"..result
end)
end
end
if should_math or can_math then
local yesno = require('Module:Yesno')
if args.class ~= "mathtag" and yesno(args['show math'] or args['shw_math']) then
body = p._re_math_output(body)
end
body = p._adj_math_output(tostring(body))
end
if can_math then body = frame:callParserFunction{name = "#tag:math", args = {tostring(body)}} end
return body
end
function p.calculate(frame)
p._randomseed()
local body, can_math, should_math = p._preCalculate(frame)
if should_math or can_math then body = p._adj_math_output(tostring(body)) end
if can_math then body = frame:callParserFunction{name = "#tag:math", args = {tostring(body)}} end
return body
end
function p.toPostfix(frame)--單純印出字串,不運算
local args
if frame == mw.getCurrentFrame() then
-- We're being called via #invoke. The args are passed through to the module
-- from the template page, so use the args that were passed into the template.
args = getArgs(frame, {
trim = false,
removeBlanks = false
}) --frame.args
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local format = mw.text.decode(args.format or"{{{1}}} ");
format = mw.ustring.gsub(format, "%{%{%{.-%}%}%}", "%%s" );
local it = mw.ustring.find(format, "%%s", 1)
format = mw.ustring.gsub(format, "\\n", "\n")
local expr_geter = p._function_preprocessing(p._load_strip_marker(args[1] or args['1'] or ''),{}, nil, nil, true)
local result, body = p.infixToPostfix( expr_geter ), ''
for i, result_str in pairs( result ) do
if type(result_str)==type({}) and mw.text.trim(result_str.name) ~= '|' and result_str.propetry ~= "func start" then
body = body .. mw.ustring.gsub(format, "%%s", _subst_strip(mw.text.trim(tostring(result_str.name))))
elseif type(result_str)==type("string") then
body = body .. mw.ustring.gsub(format, "%%s", _subst_strip(mw.text.trim(tostring(result_str))))
end
end
return body
end
function p.toPrefix(frame)--單純印出字串,不運算
local args
if frame == mw.getCurrentFrame() then
-- We're being called via #invoke. The args are passed through to the module
-- from the template page, so use the args that were passed into the template.
args = getArgs(frame, {
trim = false,
removeBlanks = false
}) --frame.args
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local format = mw.text.decode(args.format or"{{{1}}} ");
format = mw.ustring.gsub(format, "%{%{%{.-%}%}%}", "%%s" );
local it = mw.ustring.find(format, "%%s", 1)
format = mw.ustring.gsub(format, "\\n", "\n")
local expr_geter = p._function_preprocessing(p._load_strip_marker(args[1] or args['1'] or ''),{}, nil, nil, true)
local postfix, body = p.infixToPostfix( expr_geter ), ''
local pre_stack = {}
local cmt_str = ""
local cmt_count = 0
local function _item_tostring(item)return _subst_strip((type(item)==type({"table"}))and(item.name or tostring(item))or tostring(item))end
local function tail_process()
if cmt_str ~= "" then
local oper_out_format = (cmt_count==2) and "%s , %s" or ((cmt_count==1) and "%s %s" or "%s (, %s)")
pre_stack[#pre_stack<=0 and 1 or #pre_stack] = mw.ustring.format(oper_out_format,
_item_tostring(pre_stack[#pre_stack]and(pre_stack[#pre_stack]..' ')or''),
_item_tostring(cmt_str)
)
cmt_str = ""
else
local new_top = ''
for i=1,#pre_stack do
if new_top ~= '' then new_top = new_top .. ' ' end
new_top = new_top .. _item_tostring(pre_stack[i])
end
for i=#pre_stack,1,-1 do pre_stack[i] = nil end
pre_stack[1] = new_top
end
end
for i = 1,#postfix do
local it = postfix[i]
local opdata = (it.propetry == "operator") and p.symbol_table[it.name] or {count=0}
if it.name == "," then
--case 逗號
if cmt_str == "" then
if #pre_stack >= 2 then
cmt_str = mw.ustring.format("%s %s",
_item_tostring(pre_stack[#pre_stack-1]),
_item_tostring(pre_stack[#pre_stack]))
cmt_count = 2
pre_stack[#pre_stack] = nil
else
cmt_str = _item_tostring(pre_stack[#pre_stack]or ' ')
cmt_count = mw.test.trim(cmt_str)=='' and 0 or 1
end
else
local new_cmt = (pre_stack[#pre_stack]and(' '.._item_tostring(pre_stack[#pre_stack])))or ''
cmt_str = cmt_str .. new_cmt
cmt_count = cmt_count + (mw.text.trim(new_cmt)=='' and 0 or 1)
end
pre_stack[#pre_stack] = nil
elseif it.propetry == "func start" then
pre_stack[#pre_stack+1] = "$function_start\127"
elseif it.propetry == "func" then
local par_count = 0
local find_func_head = #pre_stack while not mw.ustring.find(_item_tostring(pre_stack[find_func_head]),"%$function_start\127") do
if find_func_head < 1 then par_count = 0 break end
par_count = par_count + 1
find_func_head = find_func_head - 1
end
local par_data = _item_tostring(pre_stack[find_func_head]or'$function_start\127')
find_func_head = find_func_head <= 0 and #pre_stack or find_func_head
local mark_start, mark_end = mw.ustring.find(par_data,"%$function_start\127")
par_data = mw.text.split(mark_start and par_data or "$function_start\127","%$function_start\127")
local tail_data = ''
if cmt_str ~= "" then
tail_data = mw.ustring.format("%s %s",_item_tostring(par_data[2]),_item_tostring(cmt_str))
par_count = par_count + cmt_count
end
local par_it = find_func_head+1 while par_it <= #pre_stack do
tail_data = mw.ustring.format("%s %s",tail_data,_item_tostring(pre_stack[par_it]))
par_it = par_it + 1
end
tail_data = mw.ustring.format((par_count==2) and "%s %s" or "(%s %s)",_item_tostring(it),tail_data)
local head_data = mw.text.trim(par_data[1])
pre_stack[find_func_head] = (head_data=='' and '' or head_data..' ')..tail_data
par_it = find_func_head+1 while par_it <= #pre_stack do pre_stack[par_it]=nil end
cmt_str = ""
cmt_count=0
elseif opdata.count == 1 then
if opdata.count == 1 or cmt_str == "" then
pre_stack[#pre_stack] = mw.ustring.format("(%s %s)",
_item_tostring(it),_item_tostring(pre_stack[#pre_stack])
)
else
local oper_out_format = (cmt_count==2) and "%s %s" or "(%s %s)"
pre_stack[(#pre_stack<=0 and 0 or #pre_stack) + 1] = mw.ustring.format(oper_out_format,
_item_tostring(it),_item_tostring(cmt_str)
)
end
cmt_str = ""
cmt_count=0
elseif opdata.count == 2 then
--case 2元運算子
if #pre_stack == 1 and cmt_str ~= "" then
local oper_out_format = (cmt_count==2) and "%s %s , %s" or ((cmt_count==1) and "%s %s %s" or "%s %s (, %s)")
pre_stack[#pre_stack] = mw.ustring.format(oper_out_format,
_item_tostring(it),
_item_tostring(pre_stack[#pre_stack]),
_item_tostring(cmt_str)
)
cmt_str = ""
cmt_count=0
else
pre_stack[#pre_stack-1] = mw.ustring.format("%s %s %s",
_item_tostring(it),
_item_tostring(pre_stack[#pre_stack-1]),
_item_tostring(pre_stack[#pre_stack])
)
pre_stack[#pre_stack] = nil
end
elseif it.propetry == "operator" then
elseif it.name == "$END" then
--case 結尾
tail_process()
else--otherwise
pre_stack[#pre_stack+1] = it
end
end
tail_process()
local result = mw.text.trim(_item_tostring(pre_stack[1]) or _item_tostring(pre_stack[0]))
if mw.ustring.sub(result,1,1) == '(' and mw.ustring.sub(result,-1,-1) == ')' then result = mw.ustring.sub(result,2,-2) end
result = mw.text.split(mw.ustring.gsub(result,'%s+',' '),'%s+')
for i, result_str in pairs( result ) do
if mw.text.trim(result_str) ~= '|' then
body = body .. mw.ustring.gsub(format, "%%s", result_str)
end
end
body = mw.ustring.gsub(body,"⇽","←")
return body
end
--mw.log(p.calc("45*5+(1+5-9+((12-5)+5i+(9)/4)*sqrt(-6))*-8",require("Module:Complex Number").cmath.init(),require("Module:Complex Number").cmath.init().toComplexNumber,true,true,function(msg)mw.log("錯誤! "..msg)end))
-- 346.97959 - 181.262241 i
--mw.log(p.calc("45*5+(1+5-9+((12-5)+5+(9)/4)*sin(-6))*-8",nil,nil,true,true,function(msg)mw.log("錯誤! "..msg)end))
-- 217.146633205
--mw.log(p.calc("(i*j*k)",require("Module:Complex Number").qmath.init(),require("Module:Complex Number").qmath.init().toQuaternionNumber,true,true,function(msg)mw.log("錯誤! "..msg)end))
-- (-1)
function p.calc(input_str, math_lib, number_Constructer, debug_flag, should_use_other_module, error_func)
if comp_number == nil then comp_number = require("Module:Complex Number") end
if should_use_other_module ~= nil then
p.use_other_module = not (not should_use_other_module)
end
math = comp_number.math.init()
local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
local adj_input_str = input_str
if math_lib and math_lib.is_bool_lib == true then adj_input_str = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(' ' .. input_str .. ' ',"%s+and%s+"," * "),"[&∧]","*"),"%s+or%s+"," + "),"∨","+"),"%s+not%s+"," - "),"¬","-") end
local pre_expr, pre_scope = p._function_preprocessing(adj_input_str, math_lib, number_Constructer, debug_flag)
local postfix = p.infixToPostfix(pre_expr, debug_flag)
if pre_scope then postfix.scope = pre_scope end
return p.calc_by_postfix(postfix, {}, math_lib, number_Constructer, debug_flag, error_func)
end
function p.nocalc(input_str, math_lib, number_Constructer, debug_flag)
if comp_number == nil then comp_number = require("Module:Complex Number") end
math = comp_number.math.init()
local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
local adj_input_str = input_str
if math_lib and math_lib.is_bool_lib == true then adj_input_str = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(' ' .. input_str .. ' ',"%s+and%s+"," * "),"[&∧]","*"),"%s+or%s+"," + "),"∨","+"),"%s+not%s+"," - "),"¬","-") end
return p.infixToPostfix(adj_input_str, debug_flag)
end
local returnMeta = {
__tostring = function (this)
return tostring(this.value)
end
}
local keep_string = {object=true, ['string']=true, frameArg=true}
local without_load = {object=true, ['string']=true, symbols=true}
function p.calc_by_postfix(postfix, scope, math_lib, number_Constructer, debug_flag, _error_func)
local error_func = error
if type(_error_func)==type(noop_func) then error_func = _error_func end
if comp_number == nil then comp_number = require("Module:Complex Number") end
math = comp_number.math.init()
local mathlib, numberConstructer = math_lib or math, number_Constructer or tonumber
local local_scope = {}
local call_stack = {{}}
local calc_stack = {}
local dbg_func, do_dbg = mw.log, true
if debug_flag ~= true then dbg_func, do_dbg = noop_func,false end
if type(postfix.scope) == type({}) then for pk, pv in pairs(postfix.scope) do scope[pk] = scope[pk] or postfix.scope[pk]end end
if postfix.is_error == true then error_func("計算失敗:"..postfix.error_message, 2) end
for i = 1,#postfix do
local it = postfix[i]
if it.propetry == "func start" then
call_stack[#call_stack + 1] = {}
elseif it.propetry == "operator" then
local opdata = p.symbol_table[it.name]
local to_ass
local if_return = false
xpcall(function()
if it.name == ',' then
if calc_stack[#calc_stack-1] ~= ',' and calc_stack[#calc_stack] ~= ',' and #(call_stack[#call_stack]) > 0 then call_stack[#call_stack+1]={} end
if calc_stack[#calc_stack-1] == ',' and calc_stack[#calc_stack] == ',' then
local call_stack_top_left,call_stack_top_right = {},{}
for ij = 1, #(call_stack[#call_stack-1]) do call_stack_top_left[#call_stack_top_left + 1] = (call_stack[#call_stack-1])[ij] end
for ij = 1, #(call_stack[#call_stack]) do call_stack_top_right[#call_stack_top_right + 1] = (call_stack[#call_stack])[ij] end
local cma_result_left,cma_result_right = p.symbol_table[','].calc( mathlib, unpack( call_stack_top_left ) ), p.symbol_table[','].calc( mathlib, unpack( call_stack_top_right ) )
call_stack[#call_stack] = nil
call_stack[#call_stack] = nil
local call_stack_count = #call_stack
for queue_it = call_stack_count,1,-1 do call_stack[queue_it+1]=call_stack[queue_it]end
call_stack[1] = { cma_result_left, cma_result_right }
else
if calc_stack[#calc_stack-1] ~= ',' then
local call_stack_count = #(call_stack[#call_stack])
for queue_it = call_stack_count,1,-1 do (call_stack[#call_stack])[queue_it+1]=(call_stack[#call_stack])[queue_it]end
(call_stack[#call_stack])[1] = calc_stack[#calc_stack-1]
--(call_stack[#call_stack])[#(call_stack[#call_stack]) + 1] = calc_stack[#calc_stack-1]
end
if calc_stack[#calc_stack] ~= ',' then (call_stack[#call_stack])[#(call_stack[#call_stack]) + 1] = calc_stack[#calc_stack] end
end
calc_stack[#calc_stack] = nil; calc_stack[#calc_stack] = ','
elseif opdata.count == 1 then
if calc_stack[#calc_stack] == ',' and #call_stack > 0 then
local call_stack_top = {}
for ij = 1, #(call_stack[#call_stack]) do call_stack_top[#call_stack_top + 1] = (call_stack[#call_stack])[ij] end
local cma_result = p.symbol_table[','].calc( mathlib, unpack( call_stack_top ) )
calc_stack[#calc_stack] = opdata.calc(cma_result,mathlib,numberConstructer)
call_stack[#call_stack] = calc_stack[#calc_stack]
elseif it.name == '⟵' and type(mathlib.mathdef) ~= type(noop_func) then
calc_stack = { {
['return'] = true,
value=opdata.calc(calc_stack[#calc_stack],mathlib,numberConstructer)
} }
setmetatable(calc_stack[1],returnMeta)
if_return = true
else
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
error_func("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" ",2) end
end
calc_stack[#calc_stack] = opdata.calc(calc_stack[#calc_stack],mathlib,numberConstructer)
end
else
if it.name ~= '←' then
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
else
local try_scope_obj = calc_stack[#calc_stack][1]
local try_scope_name = tostring(try_scope_obj)
local try_scope = mathlib[try_scope_name]
if type(try_scope_obj) == type({}) and try_scope_obj.isObject then try_scope = try_scope_obj.value or try_scope end
if try_scope==nil then try_scope = scope[try_scope_name] end
if try_scope==nil then try_scope = _G[try_scope_name] end
if try_scope==nil and mathlib.noncalculate ~= true and mathlib.ext_loaded ~= true then
mathlib = ext_mathlib(mathlib, numberConstructer)
try_scope = mathlib[try_scope_name]
if use_ext_mathlib ~= true then use_ext_mathlib = true end
end
if try_scope~=nil then
if type(try_scope)==type(noop_func) then calc_stack[#calc_stack] = try_scope_name
else calc_stack[#calc_stack] = try_scope end
else error_func("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" " ,2) end
end
end
if ((type(calc_stack[#calc_stack - 1]) == type({})) and calc_stack[#calc_stack - 1] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack - 1][1]]
if get_data then calc_stack[#calc_stack - 1] = local_scope[calc_stack[#calc_stack - 1][1]]
else
local try_scope_obj = calc_stack[#calc_stack - 1][1]
local try_scope_name = tostring(try_scope_obj)
local try_scope = mathlib[try_scope_name]
if type(try_scope_obj) == type({}) and try_scope_obj.isObject then try_scope = try_scope_obj.value or try_scope end
if try_scope==nil then try_scope = scope[try_scope_name] end
if try_scope==nil then try_scope = _G[try_scope_name] end
if try_scope==nil and mathlib.noncalculate ~= true and mathlib.ext_loaded ~= true then
mathlib = ext_mathlib(mathlib, numberConstructer)
try_scope = mathlib[try_scope_name]
if use_ext_mathlib ~= true then use_ext_mathlib = true end
end
if try_scope~=nil then calc_stack[#calc_stack - 1] = try_scope
else error_func("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack - 1][1])) .. "\" ",2) end
end
end
else
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
else get_data = (scope or {})[calc_stack[#calc_stack][1]] or _G[calc_stack[#calc_stack][1]] or mathlib[calc_stack[#calc_stack][1]]
if type(get_data) == type(noop_func) then calc_stack[#calc_stack] = get_data
else error_func("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" ",2) end
end
end
to_ass = calc_stack[#calc_stack - 1]
end
if (calc_stack[#calc_stack] == ',' or calc_stack[#calc_stack-1] == ',') and #call_stack > 0 then
local cma_result_left,cma_result_right
if calc_stack[#calc_stack-1] == ',' and calc_stack[#calc_stack] == ',' then
local call_stack_top_left,call_stack_top_right = {},{}
for ij = 1, #(call_stack[#call_stack-1]) do call_stack_top_left[#call_stack_top_left + 1] = (call_stack[#call_stack-1])[ij] end
for ij = 1, #(call_stack[#call_stack]) do call_stack_top_right[#call_stack_top_right + 1] = (call_stack[#call_stack])[ij] end
cma_result_left,cma_result_right = p.symbol_table[','].calc( mathlib, unpack( call_stack_top_left ) ), p.symbol_table[','].calc( mathlib, unpack( call_stack_top_right ) )
calc_stack[#calc_stack - 1] = opdata.calc(cma_result_left ,cma_result_right, mathlib,numberConstructer)
call_stack[#call_stack] = nil call_stack[#call_stack] = nil
local call_stack_count = #call_stack
for queue_it = call_stack_count,1,-1 do call_stack[queue_it+1]=call_stack[queue_it]end
call_stack[1] = calc_stack[#calc_stack - 1]
else
cma_result_left,cma_result_right = calc_stack[#calc_stack - 1]or 0, calc_stack[#calc_stack]or 0
local call_stack_top = {}
for ij = 1, #(call_stack[#call_stack]) do call_stack_top[#call_stack_top + 1] = (call_stack[#call_stack])[ij] end
local cma_result = p.symbol_table[','].calc( mathlib, unpack( call_stack_top ) )
if calc_stack[#calc_stack-1] == ',' then cma_result_left = cma_result
elseif calc_stack[#calc_stack] == ',' then cma_result_right = cma_result end
calc_stack[#calc_stack - 1] = opdata.calc(cma_result_left ,cma_result_right, mathlib,numberConstructer)
call_stack[#call_stack] = nil
local call_stack_count = #call_stack
for queue_it = call_stack_count,1,-1 do call_stack[queue_it+1]=call_stack[queue_it]end
call_stack[1] = calc_stack[#calc_stack - 1]
end
else
calc_stack[#calc_stack - 1] = opdata.calc(calc_stack[#calc_stack - 1]or 0 ,calc_stack[#calc_stack]or 0,mathlib,numberConstructer)
end
calc_stack[#calc_stack] = nil
end
end, function(message)
error_func("計算失敗:套用運算子 \"" .. _subst_error_strip(mw.text.trim(it.name)) .. "\" 發生錯誤 \"" .. message .. "\" ",2)
end)
xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
if it.name == '←' and type(mathlib.mathdef) ~= type(noop_func)then
local cantass = "計算失敗:套用運算子 \"" .. _subst_error_strip(mw.text.trim(it.name)) .. "\" 發生錯誤:無法將 \"".. tostring(to_ass[1] or to_ass) .."\" 的值設定為 \"" .. tostring(calc_stack[#calc_stack] ) .. "\" "
local check_num = numberConstructer(to_ass[1] or to_ass)
if check_num then error_func(cantass,2) elseif local_scope then local_scope[to_ass[1]] = calc_stack[#calc_stack] else error_func(cantass,2)end
end
if do_dbg == true then dbg_func(it.name, '\t', print_sk(calc_stack,', ') ) end
if if_return then break end
elseif it.propetry == "func" then
local calfunc, functype = mathlib[it.name], type(noop_func)
if type(calfunc) ~= functype and type((scope or {})[it.name]) == functype then calfunc = scope[it.name] end
if type(calfunc) ~= functype and type(_G[it.name]) == functype then calfunc = _G[it.name] end
if type(calfunc) ~= functype and mathlib.noncalculate ~= true and mathlib.ext_loaded ~= true then
mathlib = ext_mathlib(mathlib, numberConstructer)
calfunc = mathlib[it.name]
if use_ext_mathlib ~= true and type(calfunc) == functype then use_ext_mathlib = true end
end
if type(calfunc) ~= functype and type((local_scope or {})[it.name]) == functype then calfunc = local_scope[it.name] end
local is_other_module = false
if type(calfunc) ~= functype and p.use_other_module == true then
local check_func = mw.text.split(it.name,"AtModule")
if #check_func > 1 then
xpcall(function()
local load_module = require( "Module:" .. check_func[2])
calfunc = load_module[check_func[1]]
is_other_module = true
end, function(message)
error_func("計算失敗:執行函數 \"" .. "Module:" .. check_func[2] .. '#' .. check_func[1] .. "\" 發生錯誤 \"" .. message .. "\" ",2)
end)
end
end
local callstr = it.name
local ifreturn = false
if type(calfunc) == functype then
xpcall(function()
local call_stack_top = {}
for j = 1, #(call_stack[#call_stack]) do
if ((type((call_stack[#call_stack])[j] ) == type({})) and (call_stack[#call_stack])[j] or {}).assign == "assign" then
local get_data = (local_scope or {})[(call_stack[#call_stack])[j][1]]
if get_data then (call_stack[#call_stack])[j] = local_scope[(call_stack[#call_stack])[j][1]]
else
local try_scope_obj = (call_stack[#call_stack])[j][1]
local try_scope_name = tostring(try_scope_obj)
local try_scope = mathlib[try_scope_name]
if without_load[callstr] then try_scope = try_scope_obj end
if type(try_scope_obj) == type({}) and try_scope_obj.isObject then try_scope = try_scope_obj.value or try_scope end
if try_scope==nil then try_scope = scope[try_scope_name] end
if try_scope==nil then try_scope = _G[try_scope_name] end
if try_scope==nil and mathlib.noncalculate ~= true and mathlib.ext_loaded ~= true then
mathlib = ext_mathlib(mathlib, numberConstructer)
try_scope = mathlib[try_scope_name]
if use_ext_mathlib ~= true then use_ext_mathlib = true end
end
if try_scope~=nil then (call_stack[#call_stack])[j] = try_scope
else error_func("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring((call_stack[#call_stack])[j][1])) .. "\" ",2) end
end
end
call_stack_top[#call_stack_top + 1] = (call_stack[#call_stack])[j]
end
if call_stack_top == ',' or call_stack_top == '' or call_stack_top == nil then
call_stack_top[#call_stack_top + 1] = calc_stack[#calc_stack]
end
if #call_stack_top > 0 then
if do_dbg == true then callstr = callstr .. '(' .. print_sk(call_stack_top,',') .. ')' end
local wrap_call_stack_top = call_stack_top
if is_other_module then
wrap_call_stack_top = {}
for k,v in pairs(call_stack_top) do wrap_call_stack_top[k] = tostring(v) end
end
local calc_result = calfunc( unpack( wrap_call_stack_top ) )
if type(calc_result) == type({}) and calc_result['return'] then
calc_result = calc_result.value
if type(mathlib.mathdef) ~= type(noop_func) then
calc_stack = {calc_result}
ifreturn = true
end
end
if type(calc_result) == type('') and (not keep_string[callstr]) then
calc_result = numberConstructer(calc_result) or calc_result
end
calc_stack[#calc_stack] = calc_result
else
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
local get_data = (local_scope or {})[calc_stack[#calc_stack][1]]
if get_data then calc_stack[#calc_stack] = local_scope[calc_stack[#calc_stack][1]]
else
local try_scope_obj = calc_stack[#calc_stack][1]
local try_scope_name = tostring(try_scope_obj)
local try_scope = mathlib[try_scope_name]
if without_load[callstr] then try_scope = try_scope_obj end
if type(try_scope_obj) == type({}) and try_scope_obj.isObject then try_scope = try_scope_obj.value or try_scope end
if try_scope==nil then try_scope = scope[try_scope_name] end
if try_scope==nil then try_scope = _G[try_scope_name] end
if try_scope==nil and mathlib.noncalculate ~= true and mathlib.ext_loaded ~= true then
mathlib = ext_mathlib(mathlib, numberConstructer)
try_scope = mathlib[try_scope_name]
if use_ext_mathlib ~= true then use_ext_mathlib = true end
end
if try_scope~=nil then calc_stack[#calc_stack] = try_scope
else error_func("計算失敗:未知的變數 \"" .. _subst_error_strip(tostring(calc_stack[#calc_stack][1])) .. "\" ",2) end
end
end
local wrap_call_stack_top = calc_stack[#calc_stack]
if is_other_module then wrap_call_stack_top = tostring(wrap_call_stack_top) end
local calc_result = calfunc( wrap_call_stack_top )
if type(calc_result) == type({}) and calc_result['return'] then
calc_result = calc_result.value
if type(mathlib.mathdef) ~= type(noop_func) then
calc_stack = {calc_result}
ifreturn = true
end
end
if type(calc_result) == type('') and (not keep_string[callstr]) then
calc_result = numberConstructer(calc_result) or calc_result
end
calc_stack[#calc_stack] = calc_result
end
call_stack[#call_stack] = nil
end, function(message)
error_func("計算失敗:執行函數 \"" .. _subst_error_strip(it.name) .. "\" 發生錯誤 \"" .. message .. "\" ",2)
end)
else
if it.name == '(' then error_func("計算失敗:未封閉的括號",2) end
error_func("計算失敗:無法執行函數 \"" .. _subst_error_strip(it.name) .. "\" ",2)
end
xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
if do_dbg == true then dbg_func(callstr, '\t', print_sk(calc_stack,', ') ) end
if ifreturn then break end
else
local get_data = numberConstructer(it.name)
if get_data == nil then get_data = numberConstructer((scope or {})[it.name]) or numberConstructer(_G[it.name]) or numberConstructer(mathlib[it.name]) or numberConstructer(it.name) end
if get_data == nil then get_data={it.name,assign="assign"}end
calc_stack[#calc_stack + 1] = get_data
xpcall(function() (calc_stack[#calc_stack]):clean() end,function(_)end)
if do_dbg == true then dbg_func(it.name, '\t', print_sk(calc_stack,', ') ) end
end
end
if #calc_stack == 1 then
local checker = calc_stack[#calc_stack]
if ((type(calc_stack[#calc_stack]) == type({})) and calc_stack[#calc_stack] or {}).assign == "assign" then
checker = tostring(calc_stack[#calc_stack][1])
end
if checker == ',' then
for call_i=#call_stack,1,-1 do
for call_j=1,#(call_stack[call_i]) do
if ((type(call_stack[call_i][call_j]) == type({})) and call_stack[call_i][call_j] or {}).assign == "assign" then
local get_data = (local_scope or {})[call_stack[call_i][call_j][1]]
if get_data then call_stack[call_i][call_j] = local_scope[call_stack[call_i][call_j][1]]
else call_stack[call_i][call_j] = tostring(call_stack[call_i][call_j][1]) end
end
if checker == ',' then checker = '' else checker = checker..', ' end
checker = checker .. tostring(call_stack[call_i][call_j])
end
end
end
return checker
elseif #calc_stack > 1 then
local check_number_data = print_sk(calc_stack,', ')
if mw.text.trim(check_number_data) == '' then
error_func("計算失敗:缺少運算子和運算數,無法運算",2)
elseif not mw.ustring.find(check_number_data,',') then
--"缺少運算子且只有一個運算數" 那就返回運算數,不視為錯誤
--error_func("計算失敗:預期為二元運算,但缺少運算子且只有一個運算數 \"".. check_number_data .."\",無法運算",2)
return numberConstructer(check_number_data)
else
error_func("計算失敗:缺少運算子,數字 [" .. check_number_data .. "] 無法運算",2)
end
end
return numberConstructer(0)
end
function p.infixToPostfix(input_str, debug_flag)
local str, index, num_list = input_str, 0, {};
local dbg_func, do_dbg = mw.log, true
if debug_flag ~= true then dbg_func, do_dbg = noop_func,false end
local flag_logging = {}
local flag_logging_list = {
logic_func = "replace logic operators...",
round_and_return = "replace round and return operators...",
equal_operator = "replace equal operators...",
scientific = "replace scientific symbols...",
imaginary_unit = "replace imaginary units..."
}
if mw.ustring.find(str,"[xXnN]?[aAoOnN][nNrRoO][dDtTrR]?([^%a%(])") then
str = mw.ustring.gsub(str,"([%A])[aA][nN][dD]([^%a%(])","%1 & %2")
str = mw.ustring.gsub(str,"([%A])[nN][aA][nN][dD]([^%a%(])","%1 ↑ %2")
str = mw.ustring.gsub(str,"([%A])[oO][rR]([^%a%(])","%1 | %2")
str = mw.ustring.gsub(str,"([%A])[nN][oO][rR]([^%a%(])","%1 ↓ %2")
str = mw.ustring.gsub(str,"([%A])[xX][oO][rR]([^%a%(])","%1 ⊕ %2")
str = mw.ustring.gsub(str,"([%A])[xX][nN][oO][rR]([^%a%(])","%1 ⇔ %2")
str = mw.ustring.gsub(str,"([%A])[nN][oO][tT]([^%a%(])","%1 ~ %2")
str = mw.ustring.gsub(str,"^not([^%a%(])","~ %1")
flag_logging.logic_func = true
end
if mw.ustring.find(str,"[rR][oOeE][uUtT][nNuU][dDrR][nN]?([^%a%(])") then
str = mw.ustring.gsub(str,"([%A])[rR][oO][uU][nN][dD]([^%a%(])","%1 ≃ %2")
str = mw.ustring.gsub(str,"([%A])[rR][eE][tT][uU][rR][nN]([^%a%(])","%1 ⟵ %2")
str = mw.ustring.gsub(str,"^%s*[rR][eE][tT][uU][rR][nN]([^%a%(])","⟵ %1")
flag_logging.round_and_return = true
end
local feq1,feq2,fsci,fsi,fsj,fsk,fpi,fpj,fpk = 0,0,0,0,0,0,0,0,0
str, feq1 = mw.ustring.gsub(str,"([><=!~@])=",function(str) return ({['>']='≥',['<']='≤',['~']='≠',['!']='≠',['=']='=',['@']='←'})[str] end)
str, feq2 = mw.ustring.gsub(str,"([%a%d]+)%s*([%+%-−%*×⋅/÷%%%^&↑%|↓⊕⇔])=", "%1 ← %1 %2 ")
str, fsci = mw.ustring.gsub(str,"([%+%-]?)(%d*%.?%d+)e([%+%-]?%d+)([ijk]?)",function(n_sign,n_num,n_pow,ijk) return n_sign.."("..n_num.."*10^("..n_pow.."))"..((ijk~=nil and ijk~='')and(' ˙ '..ijk) or'') end)
if mw.ustring.find(str,"[ijk]") then
str, fsi = mw.ustring.gsub(str,"(%a)i","%1I")
str, fsj = mw.ustring.gsub(str,"(%a)j","%1J")
str, fsk = mw.ustring.gsub(str,"(%a)k","%1K")
str, fpi = mw.ustring.gsub(str,"i(%a)","I%1")
str, fpj = mw.ustring.gsub(str,"j(%a)","J%1")
str, fpk = mw.ustring.gsub(str,"k(%a)","K%1")
end
local result = mw.ustring.gsub(str,"%d*%.?%d*%s*[ijk]?",
function(b)
if b ~= nil and mw.text.trim(b) ~= '' then
index = index + 1
num_list[#num_list + 1] = b
return ' ' .. tostring(index)
end
return ''
end
);
if ((fpi or 0)+(fsi or 0)) ~= 0 then result = mw.ustring.gsub(result,"I","i") end
if ((fpj or 0)+(fsj or 0)) ~= 0 then result = mw.ustring.gsub(result,"J","j") end
if ((fpk or 0)+(fsk or 0)) ~= 0 then result = mw.ustring.gsub(result,"K","k") end
--------------------------------------------------------
if do_dbg then
if ((feq1 or 0)+(feq2 or 0)) ~= 0 then flag_logging.equal_operator = true end
if (fsci or 0) ~= 0 then flag_logging.scientific = true end
if ((fpi or 0)+(fsi or 0)+(fpj or 0)+(fsj or 0)+(fpk or 0)+(fsk or 0)) ~= 0 then flag_logging.imaginary_unit = true end
for flag_name,flag in pairs(flag_logging)do if flag == true and flag_logging_list[flag_name] then dbg_func(flag_logging_list[flag_name])end end
end
--------------------------------------------------------
local str2, index, azid, func_list = result, 0, '', {};
local result = mw.ustring.gsub(str2,"[π°]",
function(b)
if b ~= nil and mw.text.trim(b) ~= '' then
num_list[#num_list + 1] = b
return ' ˙ ' .. tostring(#num_list) .. ' '
end
end
);
result = mw.ustring.gsub(result,"%a[%a%d]*%s*%(?",
function(b)
if b ~= nil and mw.text.trim(b) ~= '' then
if mw.ustring.find(b,"%(") then
local func_name = mw.ustring.match(b,"%a[%a%d]*")
if func_name ~= nil and mw.text.trim(func_name) ~= '' then
index, azid = index + 1, numberToAZ(index)
func_list[azid] = func_name
return ' ' .. azid .. ' '
end
else
num_list[#num_list + 1] = b
return ' ' .. tostring(#num_list) .. ' '
end
end
return ''
end
);
for i=1,#num_list do num_list[i] = mw.ustring.gsub(num_list[i],"%s+",'') end
if do_dbg then dbg_func(mw.ustring.format('result string is "%s"', result)) end
local mid_expr = stringToTable(result)
mid_expr[#mid_expr + 1] = "$END"
local stack, postfix = {{name="$END",elements=0}}, {}
for i = 1,#mid_expr do
local it = mid_expr[i]
if it == "$END" then
while #stack > 0 and stack[#stack].name ~= "$END" do
local psymbol_tablestackstacknamecount,_fl = -1
_fl,psymbol_tablestackstacknamecount = xpcall(function()return p.symbol_table[stack[#stack].name].count end,noop_func)
if (stack[#stack] or {elements=0}).elements < (psymbol_tablestackstacknamecount or -1) then
local error_message = p.symbol_table[stack[#stack].name].name.."運算子需要"..p.symbol_table[stack[#stack].name].count.."個運算數,但只找到"..stack[#stack].elements.."個運算數"
if do_dbg == true then dbg_func("== \""..stack[#stack].name.."\" "..error_message) end
return {is_error=true, error_message=error_message}
end
postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
stack[#stack] = nil --pop
if stack[#stack] then stack[#stack].elements = (stack[#stack].elements or 0) + 1 end
end
if do_dbg == true then dbg_func("結束",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
elseif mw.ustring.match(it,"[%a%(]") then
stack[#stack + 1] = {name=it,elements=0,propetry='func'}
if do_dbg == true then dbg_func(it, "括號開始",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
if func_list[it] ~= nil then postfix[#postfix + 1] = {name=' ', propetry="func start"} end
elseif p.symbol_table[it] ~= nil and p.symbol_table[it].propetry == "op" then
local op_it = p.symbol_table[it]
local op_ls = p.symbol_table[mid_expr[i-1]]
local flag = mw.ustring.match(mid_expr[i-1] or '',"[%a%(]") if (mid_expr[i-1] or '娜娜奇') == '娜娜奇' then flag = false end
if ( op_ls or (i == 1) or flag ) and op_it.multp == true then
stack[#stack + 1] = {name=it .. ' ',elements=0,propetry='operator'}
else
while p.symbol_table[(stack[#stack]or{name=noop_func}).name] and p.symbol_table[(stack[#stack]or{name=noop_func}).name].priority and
p.symbol_table[stack[#stack].name].ppriority >= p.symbol_table[it].priority do
if stack[#stack].elements < p.symbol_table[stack[#stack].name].count then
local error_message = p.symbol_table[stack[#stack].name].name.."運算子需要"..p.symbol_table[stack[#stack].name].count.."個運算數,但只找到"..stack[#stack].elements.."個運算數"
if do_dbg == true then dbg_func("== \""..stack[#stack].name.."\" "..error_message) end
return {is_error=true, error_message=error_message}
end
postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
stack[#stack] = nil --pop
stack[#stack].elements = (stack[#stack].elements or 0) + 1
end
stack[#stack + 1] = {name=it,elements=1, propetry='operator'}
end
if do_dbg == true then dbg_func(it, "運算子",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
elseif mw.ustring.match(it,"%d+") then
postfix[#postfix + 1] = {name=num_list[tonumber(it)] or ("N" .. it), propetry="number"}
stack[#stack].elements = (stack[#stack].elements or 0) + 1
if do_dbg == true then dbg_func(it, "數字",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack)) end
elseif it == ')' then
local flag = mw.ustring.match(stack[#stack].name,"[%a%(]")
while flag == nil do --遇 ) 輸出至 (
if stack[#stack].name ~= "$END" then
if stack[#stack].elements < p.symbol_table[stack[#stack].name].count then
local error_message = p.symbol_table[stack[#stack].name].name.."運算子需要"..p.symbol_table[stack[#stack].name].count.."個運算數,但只找到"..stack[#stack].elements.."個運算數"
if do_dbg == true then dbg_func("== \""..stack[#stack].name.."\" "..error_message) end
return {is_error=true, error_message=error_message}
end
postfix[#postfix + 1] = {name=stack[#stack].name, propetry=stack[#stack].propetry}
stack[#stack] = nil --pop
stack[#stack].elements = (stack[#stack].elements or 0) + 1
end
flag = mw.ustring.match(stack[#stack].name,"[%a%(]")
end
if mw.ustring.match(stack[#stack].name,"%a") then
if stack[#stack].name ~= "$END" then
postfix[#postfix + 1] = {name=func_list[stack[#stack].name] or stack[#stack].name, propetry=stack[#stack].propetry}
end
end
if stack[#stack].name == "$END" then
local error_message = "未預料的反括號"
if do_dbg == true then dbg_func("=="..error_message) end
postfix.is_error=true
postfix.error_message = error_message
else
stack[#stack] = nil --pop
end
if stack[#stack] then stack[#stack].elements = ((stack[#stack] or {}).elements or 0) + 1 end
if do_dbg == true then dbg_func(it, "結束括號",'\t', print_sk(postfix,' ') ,'\t',print_sk(stack))end
end
end
return postfix
end
function p.ifNumeric(frame)
local result, can_math, should_math, input_math_lib, input_to_number
local error_count = 0
local error_flag = xpcall(function()
result, can_math, should_math, input_math_lib, input_to_number = p._preCalculate(frame, function()error_count = error_count + 1 end)
end,noop_func)
error_flag = (not error_flag) or (error_count > 0)
local args
if frame == mw.getCurrentFrame() then
-- We're being called via #invoke. The args are passed through to the module
-- from the template page, so use the args that were passed into the template.
args = getArgs(frame) --frame.args
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local body = ''
if args[2]==nil and args[3]==nil then return error_flag and '' or '1' end
if error_flag then
body = args[3] or body
else
body = args[2] or body
end
return body
end
function p.calcExpr(frame)
local result, can_math, should_math, input_math_lib, input_to_number
local error_count = 0
local bool_value = 0
local error_message
local error_flag = xpcall(function()
result, can_math, should_math, input_math_lib, input_to_number = p._preCalculate(frame, function(msg)
error_message = error_message or msg
error_count = error_count + 1
end)
bool_value = input_math_lib.abs(result)
end,noop_func)
error_flag = (not error_flag) or (error_count > 0)
local args
if frame == mw.getCurrentFrame() then
-- We're being called via #invoke. The args are passed through to the module
-- from the template page, so use the args that were passed into the template.
args = getArgs(frame) --frame.args
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local body = ''
if args[2]==nil and args[3]==nil then
if error_message~=nil and error_flag then error(error_message, 2) end
return result
end
if bool_value > 1e-14 and (not error_flag) then
body = args[2] or body
else
body = args[3] or body
end
return body
end
function p.isReal(frame)
local args
local result, can_math, should_math, input_math_lib, input_to_number
local error_count = 0
local non_real_value = 0
local error_flag = xpcall(function()
result, can_math, should_math, input_math_lib, input_to_number = p._preCalculate(frame, function()error_count = error_count + 1 end)
non_real_value = input_math_lib.abs(input_math_lib.nonRealPart(result))
end,noop_func)
error_flag = (not error_flag) or (error_count > 0)
if frame == mw.getCurrentFrame() then
-- We're being called via #invoke. The args are passed through to the module
-- from the template page, so use the args that were passed into the template.
args = getArgs(frame) --frame.args
else
-- We're being called from another module or from the debug console, so assume
-- the args are passed in directly.
args = frame
end
local body = ''
if non_real_value > 1e-14 or error_flag then
body = args[3] or body
else
body = args[2] or body
end
return body
end
--表達式輸出為<math></math>支援
p.tagmath={
matheq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'=','=')
end,
mathneq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'≠','\\neq')
end,
mathdef=function(op1,op2)
local that, oper_id = p.tagmath.toTagMath(op2), ''
if op2.lowoperator ~= '(' and op2.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
return p.tagmath.apply_binary_operator(op1,that,'←','\\overset{\\underset{\\mathrm{def}}{}}{=}')
end,
mathmapsto=function(op1,op2)
local that_op1, oper_id = p.tagmath.toTagMath(op1), ''
if op1.lowoperator ~= '(' and op1.lowoperator ~= '' then that_op1.value = "\\left( " .. that_op1.value .. "\\right) "end
that_op1.lowoperator = oper_id
return p.tagmath.apply_binary_operator(that_op1,op2,'↦','\\mapsto')
end,
mathfuncdef=function(op1,op2)
local that_op1, oper_id = p.tagmath.toTagMath(op1), ''
that_op1.lowoperator = oper_id
return p.tagmath.apply_binary_operator(that_op1,op2,':',':')
end,
mathset=function(op1,op2)
local that_op1, oper_id, that = p.tagmath.toTagMath(op1), ''
if op1.lowoperator ~= '(' and op1.lowoperator ~= '' then that_op1.value = "\\left( " .. that_op1.value .. "\\right) "end
that_op1.lowoperator = oper_id
that, oper_id = p.tagmath.toTagMath(op2), ''
if op2.lowoperator ~= '(' and op2.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
return p.tagmath.apply_binary_operator(that_op1,that,'⇽','\\gets')
end,
mathcomma=function(...)
local get_all_arg = {...}
if #get_all_arg == 1 then return get_all_arg[1] end
if #get_all_arg == 0 then return '' end
local merge_data = ''
for itj=1,#get_all_arg do
if merge_data ~= '' then merge_data = merge_data .. ' ,\\, ' end
merge_data = merge_data .. tostring(get_all_arg[itj])
end
local that_op1, oper_id = p.tagmath.toTagMath(merge_data), ''
that_op1.value = "\\left( " .. that_op1.value .. "\\right) "
that_op1.lowoperator = oper_id
return that_op1
end,
mathsemicolon=function(op1,op2)
local check_empty = mw.ustring.gsub(tostring(op1),'%s','')
if check_empty =="{}" or check_empty == '' then return op2 end
return p.tagmath.apply_binary_operator(op1,op2,';',';\\,')
end,
mathtimes=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'⋅','\\, ')
end,
mathlt=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'<','<')
end,
mathgt=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'>','>')
end,
mathlteq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'≤','\\leq')
end,
mathgteq=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'≥','\\geq')
end,
mathand=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'&','\\land')
end,
mathnand=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'↑','\\uparrow')
end,
mathor=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'|','\\lor')
end,
mathnor=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'↓','\\downarrow')
end,
mathxor=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'⊕','\\oplus')
end,
mathxnor=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'⇔','\\leftrightarrow')
end,
mathnot=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "\\lnot" .. that.value
return that
end,
mathreturn=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\text{return}\\," .. that.value
return that
end,
pow=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'^','^',false,true)
end,
div=function(op1,op2)
local left, right = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
left.lowoperator = ''
left.value = "\\frac{ " .. left.value .. " }{ " .. right.value .. "}"
return left
end,
sqrt=function(op1,op2)
local left = p.tagmath.toTagMath(op1)
if op2 ~= nil then
local right = p.tagmath.toTagMath(op2)
left.value = "\\sqrt[ " .. right.value .. " ]{ " .. left.value .. "}"
else
left.value = "\\sqrt{ " .. left.value .. " }"
end
left.lowoperator = ''
return left
end,
dot=function(op1,op2)
return p.tagmath.apply_binary_operator(op1,op2,'*','\\cdot')
end,
exp=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = " e^{ " .. that.value .. "} "
return that
end,
log=function(op1,op2)
local left, right, vals, log_symbol
if op2 ~= nil then
right, left = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
vals = "_{" .. right.value .. "}"
log_symbol = "log "
else
left, vals = p.tagmath.toTagMath(op1), ''
log_symbol = "ln "
end
if left.lowoperator ~= '(' and left.lowoperator ~= '' then left.value = "\\left( " .. left.value .. "\\right) "end
left.lowoperator = ''
left.value = '\\' .. log_symbol .. vals .. left.value
return left
end,
abs=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\left\\vert " .. that.value .. "\\right\\vert "
return that
end,
conjugate=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\overline{ " .. that.value .. " } "
return that
end,
floor=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\left\\lfloor " .. that.value .. "\\right\\rfloor "
return that
end,
ceil=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "\\left\\lceil " .. that.value .. "\\right\\rceil "
return that
end,
binomial=function(n,k)
local that, oper_id = p.tagmath.toTagMath(n), ''
local that_k = p.tagmath.toTagMath(k) or {value=''}
that.lowoperator = oper_id
that.value = "\\binom {" .. that.value .. "}{" .. that_k.value .. '}'
return that
end,
min=function(...)
local this_list, oper_id = {...}, ''
local that = p.tagmath.toTagMath(this_list[1])
for i=2,#this_list do
local it_item = p.tagmath.toTagMath(this_list[i])
that.value = that.value .. ', \\,' .. it_item.value
end
that.value = "\\left( " .. that.value .. "\\right) "
that.lowoperator = oper_id
that.value = "\\min {" .. that.value .. '}'
return that
end,
factorial=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = that.value .. "!"
return that
end,
ele=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "\\,e_{" .. that.value .. "}"
return that
end,
norm=function(n,_p)
local that, oper_id = p.tagmath.toTagMath(n), ''
local that_p = p.tagmath.toTagMath(_p) or {value=''}
that.lowoperator = oper_id
that.value = "\\left \\|" .. that.value .. "\\right \\|"
if _p then that.value = that.value .."_{" .. that_p.value .. '}' end
return that
end,
transpose=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = that.value .. "^{\\mathrm{T}}"
return that
end,
identity=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
that.lowoperator = oper_id
that.value = "I_{" .. that.value .. "}"
return that
end,
row=function(...)
local get_all_arg = {...}
if #get_all_arg == 1 then return get_all_arg[1] end
if #get_all_arg == 0 then return '' end
local merge_data = ''
for itj=1,#get_all_arg do
if merge_data ~= '' then merge_data = merge_data .. ' & ' end
merge_data = merge_data..'{'..tostring(get_all_arg[itj])..'}'
end
local that_op1, oper_id = p.tagmath.toTagMath(merge_data), ''
that_op1.lowoperator = oper_id
return that_op1
end,
matrix=function(...)
local get_all_arg = {...}
if #get_all_arg == 1 then
local that_op1, oper_id = p.tagmath.toTagMath(get_all_arg[1]), ''
that_op1.value = "\\begin{bmatrix} " .. that_op1.value .. "\\end{bmatrix} "
that_op1.lowoperator = oper_id
return that_op1
end
if #get_all_arg == 0 then return '' end
local merge_data = ''
for itj=1,#get_all_arg do
if merge_data ~= '' then merge_data = merge_data .. ' \\\\\n' end
merge_data = merge_data .. tostring(get_all_arg[itj])
end
local that_op1, oper_id = p.tagmath.toTagMath(merge_data), ''
that_op1.value = "\\begin{bmatrix} " .. that_op1.value .. "\\end{bmatrix} "
that_op1.lowoperator = oper_id
return that_op1
end,
mathform=function(inputdata)
return inputdata
end,
cofactor=function(this, p_i, q_j)
local that, oper_id = p.tagmath.toTagMath(this), '('
if (this.lowoperator ~= '(') and (this.lowoperator ~= '') then
that.value = "\\left( " .. that.value .. "\\right) "
end
that.lowoperator = oper_id
that.value = '\\mathrm{cof} ' .. that.value
if p_i~= nil and q_j~= nil then
local pi_math = p.tagmath.toTagMath(p_i)
local qj_math = p.tagmath.toTagMath(q_j)
that.value = "\\left( " .. that.value .. "\\right) _ {{"..pi_math.value.."},\\,{"..qj_math.value.."}}"
end
return that
end,
cof=function(this, p_i, q_j)return p.tagmath.cofactor(this, p_i, q_j)end,
["if"]=function(expr, true_expr, false_expr)
return p.tagmath._ifelse_func(false, expr, true_expr, false_expr)
end,
iff=function(expr, true_expr, false_expr)
return p.tagmath._ifelse_func(true, expr, true_expr, false_expr)
end,
ifelse=function(...)
return p.tagmath._ifelse_func(false, ...)
end,
ifelsef=function(...)
return p.tagmath._ifelse_func(true, ...)
end,
_ifelse_func=function(is_func, ...)
local exprlist = {...}
local last_else = #exprlist % 2 == 1
local max_num = (last_else and (#exprlist - 1) or #exprlist) / 2
local that, oper_id = p.tagmath.toTagMath(''), ''
for i=1,max_num do
if i > 1 then that.value = that.value .. ' \\\\ ' end
local expr = p.tagmath.toTagMath(exprlist[i * 2 - 1])
local expr_true = p.tagmath.toTagMath(exprlist[i * 2])
if is_func then
expr.value = expr.value:gsub("\\mapsto","")
expr_true.value = expr_true.value:gsub("\\mapsto","")
end
that.value = that.value .. mw.ustring.format("{%s}, & \\text{if }{%s}", expr_true.value, expr.value)
end
if last_else then
local expr_false = p.tagmath.toTagMath(exprlist[#exprlist])
if is_func then
expr_false.value = expr_false.value:gsub("\\mapsto","")
end
that.value = that.value .. mw.ustring.format(" \\\\ {%s}, & \\text{otherwise}", expr_false.value)
end
that.lowoperator = oper_id
that.value = mw.ustring.format("\\begin{cases} %s \\end{cases}", that.value)
return that
end,
symbols=function(name)
local symbolname = p.tagmath.toTagMath(name)
local symbolresult = require('Module:Complex_Number/Functions')._symbols(mw.text.trim(symbolname.value,"%{%}\t\r\n\f "))
if symbolresult then
return p.tagmath.toTagMath(symbolresult)
end
return p.tagmath.apply_function("symbols", name)
end,
object=function(obj,...)
local objlist = {...}
local objname = p.tagmath.toTagMath(obj)
for i=1,#objlist do
local to_add = p.tagmath.toTagMath(objlist[i]).value
if objlist[i].lowoperator ~= '(' and objlist[i].lowoperator ~= '' then to_add = "\\left( " .. to_add .. "\\right) "end
objname.value = objname.value .. '.' .. to_add
end
objname.value = "\\text{" .. objname.value .. "}"
return objname
end,
['string']=function(...)
local strlist = {...}
local str = p.tagmath.toTagMath('')
for i=1,#strlist do
str.value = str.value .. p.tagmath.toTagMath(strlist[i]).value
end
str.value = "{}^\\shortparallel\\text{" .. str.value .. "}^\\shortparallel"
return str
end,
call=function(_func, ...)
local that_func = p.tagmath.toTagMath(_func)
local that_args = p.tagmath.mathcomma(...)
local is_inner_func = mw.ustring.find(tostring(that_func.value),"\\mapsto")
if #({...}) <= 1 and type(is_inner_func) == type(nil) then that_args.value = "\\left( " .. that_args.value .. "\\right) "end
if type(is_inner_func) ~= type(nil) then
that_func.value = that_func.value .. ' \\gets '
end
that_args.value = that_func.value..that_args.value
return that_args
end,
diff=function(_expr, _value)
local that, oper_id = p.tagmath.toTagMath(_value), 'MINOP'
local that_expr = p.tagmath.toTagMath(_expr)
local data_start, data_end = mw.ustring.find(tostring(that_expr.value),"\\mapsto")
local var_data = mw.ustring.sub(tostring(that_expr.value),1,(data_start or 1)-1)
local expr_data = mw.ustring.sub(tostring(that_expr.value),(data_end or 0)+1,-1)
var_data = mw.ustring.gsub(var_data,"^%s*%{","")
expr_data = mw.ustring.gsub(expr_data,"%}%s*$","")
local group_flag = mw.ustring.find(expr_data,"[%+%-]")
if not group_flag then
expr_data = mw.ustring.gsub(expr_data,"\\right%)%s*%}%s*$","")
expr_data = mw.ustring.gsub(expr_data,"^%s*%{\\left%(","")
end
local check_ijk = mw.ustring.find(tostring(var_data),"[ijkIJK]t")
if (not data_start) or check_ijk then
var_data = mw.text.trim(var_data) == '' and "x" or var_data
var_data = mw.ustring.gsub(var_data,"([ijkIJK])t","%1")
expr_data = mw.ustring.gsub(expr_data,"([ijkIJK])t","%1")
end
that.value = mw.ustring.format("\\left.\\frac{d\\,{%s}}{d{%s}}\\right|_{{%s}={%s}}",
expr_data, var_data, var_data, that.value)
that.lowoperator = oper_id
return that
end,
integral=function(_value, _b, _expr)
local that, b, oper_id = p.tagmath.toTagMath(_value), p.tagmath.toTagMath(_b), 'MINOP'
local that_expr = p.tagmath.toTagMath(_expr)
local data_start, data_end = mw.ustring.find(tostring(that_expr.value),"\\mapsto")
local var_data = mw.ustring.sub(tostring(that_expr.value),1,(data_start or 1)-1)
local expr_data = mw.ustring.sub(tostring(that_expr.value),(data_end or 0)+1,-1)
var_data = mw.ustring.gsub(var_data,"^%s*%{","")
expr_data = mw.ustring.gsub(expr_data,"%}%s*$","")
local group_flag = mw.ustring.find(expr_data,"[%+%-]")
if not group_flag then
expr_data = mw.ustring.gsub(expr_data,"\\right%)%s*%}%s*$","")
expr_data = mw.ustring.gsub(expr_data,"^%s*%{\\left%(","")
end
local check_ijk = mw.ustring.find(tostring(var_data),"[ijkIJK]t")
if (not data_start) or check_ijk then
var_data = mw.text.trim(var_data) == '' and "x" or var_data
var_data = mw.ustring.gsub(var_data,"([ijkIJK])t","%1")
expr_data = mw.ustring.gsub(expr_data,"([ijkIJK])t","%1")
end
that.value = mw.ustring.format("\\int_{%s}^{%s} %s\\,d{%s}",
that.value, b.value, expr_data, var_data)
that.lowoperator = oper_id
return that
end,
['∫']=function(_value, _b, _expr)
return p.tagmath.integral(_value, _b, _expr)
end,
limit=function(_value, _way, _expr)
local that, oper_id = p.tagmath.toTagMath(_value), 'MINOP'
local check_way = mw.ustring.gsub(tostring(_way),'[\{\}%s]','')
check_way = tonumber(check_way)
local way_text = check_way > 1e-8 and "+" or ( check_way < -1e-8 and "-" or '')
local that_expr = p.tagmath.toTagMath(_expr)
local data_start, data_end = mw.ustring.find(tostring(that_expr.value),"\\mapsto")
local var_data = mw.ustring.sub(tostring(that_expr.value),1,(data_start or 1)-1)
local expr_data = mw.ustring.sub(tostring(that_expr.value),(data_end or 0)+1,-1)
var_data = mw.ustring.gsub(var_data,"^%s*%{","")
expr_data = mw.ustring.gsub(expr_data,"%}%s*$","")
local group_flag = mw.ustring.find(expr_data,"[%+%-]")
if not group_flag then
expr_data = mw.ustring.gsub(expr_data,"\\right%)%s*%}%s*$","")
expr_data = mw.ustring.gsub(expr_data,"^%s*%{\\left%(","")
end
local check_ijk = mw.ustring.find(tostring(var_data),"[ijkIJK]t")
if (not data_start) or check_ijk then
var_data = mw.text.trim(var_data) == '' and "x" or var_data
var_data = mw.ustring.gsub(var_data,"([ijkIJK])t","%1")
expr_data = mw.ustring.gsub(expr_data,"([ijkIJK])t","%1")
end
that.value = mw.ustring.format("\\lim_{{%s} \\to {%s}^{%s}}{%s}", var_data, that.value, way_text, expr_data)
that.lowoperator = oper_id
return that
end,
summation=function(_begin, _end, _expr)
local that, oper_id = p.tagmath.toTagMath(_begin), 'MINOP'
local that_begin = p.tagmath.toTagMath(_begin)
local that_end = p.tagmath.toTagMath(_end)
local that_expr = p.tagmath.toTagMath(_expr)
local data_start, data_end = mw.ustring.find(tostring(that_expr.value),"\\mapsto")
local var_data = mw.ustring.sub(tostring(that_expr.value),1,(data_start or 1)-1)
local expr_data = mw.ustring.sub(tostring(that_expr.value),(data_end or 0)+1,-1)
var_data = mw.ustring.gsub(var_data,"^%s*%{","")
expr_data = mw.ustring.gsub(expr_data,"%}%s*$","")
local group_flag = mw.ustring.find(expr_data,"[%+%-]")
if not group_flag then
expr_data = mw.ustring.gsub(expr_data,"\\right%)%s*%}%s*$","")
expr_data = mw.ustring.gsub(expr_data,"^%s*%{\\left%(","")
end
local check_ijk = mw.ustring.find(tostring(var_data),"[ijkIJK]t")
if (not data_start) or check_ijk then
var_data = mw.text.trim(var_data) == '' and "i" or var_data
var_data = mw.ustring.gsub(var_data,"([ijkIJK])t","%1")
expr_data = mw.ustring.gsub(expr_data,"([ijkIJK])t","%1")
end
that.value = mw.ustring.format("\\sum_{{%s}={%s}}^{%s} {%s}", var_data, that_begin.value, that_end.value, expr_data)
that.lowoperator = oper_id
return that
end,
product=function(_begin, _end, _expr)
local that, oper_id = p.tagmath.toTagMath(_begin), 'MINOP'
local that_begin = p.tagmath.toTagMath(_begin)
local that_end = p.tagmath.toTagMath(_end)
local that_expr = p.tagmath.toTagMath(_expr)
local data_start, data_end = mw.ustring.find(tostring(that_expr.value),"\\mapsto")
local var_data = mw.ustring.sub(tostring(that_expr.value),1,(data_start or 1)-1)
local expr_data = mw.ustring.sub(tostring(that_expr.value),(data_end or 0)+1,-1)
var_data = mw.ustring.gsub(var_data,"^%s*%{","")
expr_data = mw.ustring.gsub(expr_data,"%}%s*$","")
local group_flag = mw.ustring.find(expr_data,"[%+%-]")
if not group_flag then
expr_data = mw.ustring.gsub(expr_data,"\\right%)%s*%}%s*$","")
expr_data = mw.ustring.gsub(expr_data,"^%s*%{\\left%(","")
end
local check_ijk = mw.ustring.find(var_data,"[ijkIJK]t")
if (not data_start) or check_ijk then
var_data = mw.text.trim(var_data) == '' and "i" or var_data
var_data = mw.ustring.gsub(var_data,"([ijkIJK])t","%1")
expr_data = mw.ustring.gsub(expr_data,"([ijkIJK])t","%1")
end
that.value = mw.ustring.format("\\prod_{{%s}={%s}}^{%s} {%s}", var_data, that_begin.value, that_end.value, expr_data)
that.lowoperator = oper_id
return that
end,
divisorsigma=function(op1,op2)
local left, right, vals, sigma_symbol
right, left = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
if op2 == nil then
left = p.tagmath.toTagMath("")
vals = ""
else
vals = "_{" .. right.value .. "}"
end
sigma_symbol = "sigma "
left.value = "\\left( " .. ((op2 == nil) and right.value or left.value) .. "\\right) "
left.lowoperator = ''
left.value = '\\' .. sigma_symbol .. vals .. left.value
return left
end,
hide=function(this)return""end,
exprs=function(...)
local input_args = {...}
return p.tagmath.mathcomma(unpack(input_args))
end,
lastexpr=function(...)
local input_args = {...}
return input_args[#input_args]
end,
equalexpr=function(...)
local get_all_arg = {...}
if #get_all_arg == 1 then return get_all_arg[1] end
if #get_all_arg == 0 then return '' end
local merge_data = ''
for itj=1,#get_all_arg do
if merge_data ~= '' then merge_data = merge_data .. '=' end
merge_data = merge_data .. tostring(get_all_arg[itj])
end
local that_op1, oper_id = p.tagmath.toTagMath(merge_data), ''
that_op1.lowoperator = oper_id
return that_op1
end,
inverse=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = that.value .. "^{-1}"
return that
end,
re=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "\\operatorname{Re}" .. that.value
return that
end,
im=function(this)
local that, oper_id = p.tagmath.toTagMath(this), ''
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "\\operatorname{Im}" .. that.value
return that
end,
apply_function=function(func_name, ...)
local para_info = {...}
local this = #para_info == 1 and para_info[1] or p.tagmath.mathcomma(...)
local that, oper_id = p.tagmath.toTagMath(this), '('
local math_ext_funcs={["minimum"]="\\min",["maximum"]="\\max",["sin"]="\\sin",["cos"]="\\cos",["tan"]="\\tan",["sec"]="\\sec",["csc"]="\\csc",["cot"]="\\cot",
["asin"]="\\arcsin",["acos"]="\\arccos",["atan"]="\\arctan",["asec"]="\\operatorname{arcsec}",["acsc"]="\\operatorname{arccsc}",["acot"]="\\operatorname{arccot}",
["sinh"]="\\sinh",["cosh"]="\\cosh",["tanh"]="\\tanh",["sech"]="\\operatorname{sech}",["csch"]="\\operatorname{csch}",["coth"]="\\coth",
["asinh"]="\\operatorname{arcsinh}",["acosh"]="\\operatorname{arccosh}",["atanh"]="\\operatorname{arctanh}",["asech"]="\\operatorname{arcsech}",["acsch"]="\\operatorname{arccsch}",["acoth"]="\\operatorname{arccoth}",
["scalarPartQuaternion"]="\\operatorname{Scalar}",["vectorPartQuaternion"]="\\operatorname{Vector}",
["sgn"]="\\sgn",["gamma"]="\\Gamma",["cis"]="\\operatorname{cis}",["eulerphi"]="\\varphi",["LambertW"]="W",
["gcd"]="\\gcd",["lcm"]="\\operatorname{lcm}",["round"]="\\operatorname{round}",["arg"]="\\arg",["trunc"]="\\operatorname{trunc}",
["gd"]="\\operatorname{gd}",["arcgd"]="\\operatorname{arcgd}",["cogd"]="\\operatorname{cogd}",
["diag"]="\\operatorname{diag}",["det"]="\\det",["determinant"]="\\det",
["adj"]="\\operatorname{adj}",["adjoint"]="\\operatorname{adj}"
}
local need_comm={["gamma"]=true,["eulerphi"]=true,["LambertW"]=true}
local math_format_funcs={
["factorial"]="%s!"
}
if ((#para_info == 1) and (this.lowoperator ~= '(') and (this.lowoperator ~= '')) or
((#para_info == 1) and (math_ext_funcs[func_name] == nil or need_comm[func_name] == true) and (this.lowoperator == ''))then
that.value = "\\left( " .. that.value .. "\\right) "
end
that.lowoperator = oper_id
if math_format_funcs[func_name] then
that.value = mw.ustring.format(math_format_funcs[func_name], that.value)
else
that.value = (math_ext_funcs[func_name] or func_name) .. ' ' .. that.value
end
return that
end,
apply_binary_operator = function(op1, op2, oper_id, oper_math,left_no,right_no)
local left, right = p.tagmath.toTagMath(op1), p.tagmath.toTagMath(op2)
if left.lowoperator ~= '(' and left.lowoperator ~= '' and
((p.symbol_table[left.lowoperator] and p.symbol_table[left.lowoperator].ppriority and
p.symbol_table[left.lowoperator].ppriority < p.symbol_table[oper_id].priority)) then
if not left_no then
left.value = "\\left( " .. left.value .. "\\right) "
end left.lowoperator = '('
end
if right.lowoperator ~= '(' and right.lowoperator ~= '' and
((p.symbol_table[right.lowoperator] and p.symbol_table[right.lowoperator].ppriority and
p.symbol_table[right.lowoperator].ppriority < p.symbol_table[oper_id].priority)) then
if not right_no then
right.value = "\\left( " .. right.value .. "\\right) "
end right.lowoperator = '('
end
local low_operator = oper_id
if ((p.symbol_table[left.lowoperator] or {ppriority=0}).ppriority or 0) ~= 0 then
if p.symbol_table[left.lowoperator].ppriority < p.symbol_table[low_operator].ppriority then
low_operator = left.lowoperator
end
end
if ((p.symbol_table[right.lowoperator] or {ppriority=0}).ppriority or 0) ~= 0 then
if p.symbol_table[right.lowoperator].ppriority < p.symbol_table[low_operator].ppriority then
low_operator = right.lowoperator
end
end
left.lowoperator = low_operator
left.value = "{ {" .. left.value .. '}' .. oper_math .. '{' .. right.value .. "} }"
return left
end,
TagMathMeta = {
__add = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'+','+')
end,
__sub = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'-','-')
end,
__mul = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'*',"\\times ")
end,
__div = function (op1, op2)
return p.tagmath.apply_binary_operator(op1,op2,'/',"\\div ")
end,
__tostring = function (this) return this.value end,
__unm = function (this)
local that, oper_id = p.tagmath.toTagMath(this), "- "
if this.lowoperator ~= '(' and this.lowoperator ~= '' then that.value = "\\left( " .. that.value .. "\\right) "end
that.lowoperator = oper_id
that.value = "-{ " .. that.value .. "}"
return that
end,
__eq = function (op1, op2)return p.tagmath.tagMathString(op1).value == p.tagmath.tagMathString(op2).value end,
},
toTagMath = function(tagMathString)
if type(tagMathString) == type({}) and tagMathString.numberType == "latex" then return tagMathString end
if type(tagMathString) == type(nil) then return nil end
local math_ext_const={["pi"]="\\pi",["π"]="\\pi",["°"]="{}^{\\circ}",["inf"]="\\infty",["nan"]="\\mathrm{NaN}",["nil"]="",["null"]=""}
local TagMath = {}
if (type(tagMathString) == type({})) and tagMathString.value ~= nil and tagMathString.lowoperator ~= nil then
TagMath = {value=tagMathString.value,lowoperator=tagMathString.lowoperator}
else
TagMath = {}
TagMath.value = math_ext_const[tagMathString] or tagMathString
TagMath.lowoperator = ''
end
setmetatable(TagMath,p.tagmath.TagMathMeta)
TagMath.numberType = "latex"
return TagMath
end,
init = function()
if comp_number == nil then comp_number = require("Module:Complex Number") end
p.tagmath.zero = p.tagmath.toTagMath(0)
p.tagmath.one = p.tagmath.toTagMath(1)
p['nil'] = p.tagmath.toTagMath("")
p.tagmath.noncalculate=true
p.tagmath[0],p.tagmath[1] = p.tagmath.zero,p.tagmath.one
new_meta = getmetatable( p.tagmath ) or {}
new_meta.__index = function (this, func_name)
return function(...)return p.tagmath.apply_function(func_name, ...)end
end
setmetatable(p.tagmath,new_meta)
p.tagmath.numberType = comp_number._numberType
p.tagmath.constructor = p.tagmath.toTagMath
return p.tagmath
end
}
return p