模块:Complex Number
此模块被引用于约5,200个页面。 为了避免造成大规模的影响,所有对此模块的编辑应先于沙盒或测试样例上测试。 测试后无误的版本可以一次性地加入此模块中,但是修改前请务必于讨论页发起讨论。 模板引用数量会自动更新。 |
本模块为Lua定义了一套复数(如虚数、四元数)运算的系统,可提供其他模块调用使用,而若要直接在模板或条目中使用可通过Module:Complex Number/Calculate或{{复变运算}}来完成。
关于本模块创建动机详见Module:TemplateParameters#设计缘由(亦可参考Template_talk:Root)。
模块内容
本模块有4套数学数据结构的定义以及对应的数学运算库:
使用方法
- 初始化数学库
local 自定义函数库名称 = require("Module:Complex Number").函数库名称.init()
- 例如:
local cmath = require("Module:Complex Number").cmath.init()
- 例如:
- 初始化指定数学结构的数字
local 变量名称 = 自定义函数库名称.constructor("描述数字的字符串")
- 例如:
local num1 = cmath.constructor("2+3i")
- 例如:
- 执行运算
- 例如:
local num1 = cmath.constructor("2+3i") local num2 = cmath.constructor("4+5i") print(num1 * num2)
- 输出:-7+22i
- 或者使用函数库内容:
local num1 = cmath.constructor("i") print(cmath.sqrt(num1))
- 输出:0.70710678118655+0.70710678118655i
- 例如:
- 若需要在模板中使用,请参阅{{复变运算}}
原理
复数可分为实部和虚部,此特性可以通过Lua的table功能({real=..., imag=...,}
)来实现,同时通过复写Metatables来完成其各运算符(如+
、-
、*
、/
)来实现复变的基本运算:
p.ComplexNumberMeta = {
__add = function (op1, op2)
return p.ComplexNumber(op1.real + op2.real, imag = op1.imag + op2.imag)
end,
--...
}
function p.ComplexNumber(real, imag)
local complexNumber = {real = op1.real + op2.real, imag = op1.imag + op2.imag}
setmetatable(complexNumber,p.ComplexNumberMeta)
return complexNumber
end
如此一来,只要是设置过Metatables的含实部和虚部的table都可以直接进行复变量的运算。
剩下的部分就是完善数学函数库math.xxx
的各函数。
比较
函数库 | 默认的math
|
.cmath
|
.qmath
|
.math
|
.bmath
|
.tagmath 位于Module:Complex Number/Calculate | |
---|---|---|---|---|---|---|---|
说明 | Lua默认提供的math程序库 | 复数()专用程序库 | 四元数()专用程序库 | 默认math 的扩展,定义了上方两个程序库中的功能
|
简单的布尔代数 | 会运算成<math></math> 的程序库
| |
函数库初始化方式 | 无须初始化 | cmath = require("Module:Complex Number").cmath.init();
|
qmath = require("Module:Complex Number").qmath.init();
|
math = require("Module:Complex Number").math.init();
|
bmath = require("Module:Complex Number").bmath.init();
|
tagmath = require("Module:Complex Number/Calculate").tagmath.init();
| |
数字建构/初始化方式 | tonumber("10"); 10
|
cmath.toComplexNumber("1+i"); cmath.getComplexNumber(1,1);
|
qmath.toQuaternionNumber("i+j+k"); qmath.getQuaternionNumber(0,1,1,1);
|
tonumber("10"); 10
|
bmath.toBoolean("yes");
|
tagmath.toTagMath("a");
| |
四则运算 | 加法a + b
|
lua原生支持 | 逻辑或 | 输出 | |||
减法a - b
|
lua原生支持 | 输出 | |||||
乘法a * b
|
lua原生支持 | 逻辑与 | 输出 | ||||
除法a / b
|
只能除实数 | lua原生支持 | 不存在 | 输出 | |||
模除a % b
|
以高斯符号定义 | lua原生支持 | 不存在 | ||||
一元运算 | 相反数-a
|
lua原生支持 | 逻辑非 | 输出 | |||
tostring | lua原生支持 | ||||||
e常量e
|
输出 | ||||||
圆周率pi
|
lua原生支持 | 输出 | |||||
虚数单位i
|
输出 | ||||||
j单位j
|
输出 | ||||||
k单位k
|
输出 | ||||||
绝对值abs(a)
|
lua原生支持 | 回传1或0 | 输出 | ||||
符号函数sgn(a)
|
回传1或0 | 输出 | |||||
共轭复数conjugate(a)
|
原式输出。 | 输出 | |||||
辐角arg(a)
|
输出 | ||||||
平方根sqrt(a)
|
输出 | ||||||
倒数inverse(a)
|
输出 | ||||||
分数div(a,b)
|
输出 | ||||||
数字部件 | 实部re(a)
|
输出 | |||||
虚部im(a)
|
恒为0 | 输出 | |||||
非实部nonRealPart(a)
|
恒为0 | 恒为0 | 即将到来 | ||||
标量部 | |||||||
向量部 | |||||||
部件向量tovector(a)
|
单一元素向量 | ||||||
内积dot(a,b)
|
与乘法相同 | 输出 | |||||
外积outer(a,b)
|
不存在 | 恒为0 | 不存在 | 不存在 | 即将到来 | ||
幂a ^ b
|
只能pow(a,b) | 只能pow(a,b) | lua原生支持 | 只能pow(a,b) | |||
指对数函数 | 指数pow(a,b)
|
lua原生支持 | 输出 | ||||
自然对数log(a)
|
lua原生支持 | 不存在 | 输出 | ||||
自然指数exp(a)
|
lua原生支持 | 不存在 | 输出 | ||||
ciscis(a)
|
不存在 | 输出 | |||||
高斯符号 | 地板floor(a)
|
lua原生支持 | 不存在 | 输出 | |||
天花板ceil(a)
|
lua原生支持 | 不存在 | 输出 | ||||
数值修约round(a)
|
不存在 | 即将到来 | |||||
截尾函数trunc(a,b)
|
不存在 | 输出 | |||||
三角函数 | 正弦sin(a)
|
lua原生支持 | 不存在 | 输出 | |||
余弦cos(a)
|
lua原生支持 | 不存在 | 输出 | ||||
正切tan(a)
|
lua原生支持 | 不存在 | 输出 | ||||
余切cot(a)
|
不存在 | 输出 | |||||
反三角函数 | 反正弦asin(a)
|
lua原生支持 | 不存在 | 输出 | |||
反余弦acos(a)
|
lua原生支持 | 不存在 | 输出 | ||||
反正切atan(a)
|
lua原生支持 | 不存在 | 输出 | ||||
反余切acot(a)
|
不存在 | 输出 | |||||
双曲函数 | 双曲正弦sinh(a)
|
lua原生支持 | 不存在 | 输出 | |||
双曲余弦cosh(a)
|
lua原生支持 | 不存在 | 输出 | ||||
双曲正切tanh(a)
|
lua原生支持 | 不存在 | 输出 | ||||
双曲余切coth(a)
|
不存在 | 输出 | |||||
反双曲函数 | 双曲反正弦asinh(a)
|
不存在 | 输出 | ||||
双曲反余弦acosh(a)
|
不存在 | 输出 | |||||
双曲反正切atanh(a)
|
不存在 | 输出 | |||||
双曲反余切acoth(a)
|
不存在 | 输出 |
扩展函数
本模块仅为这些数学结构定义一些基本运算(见上表)。一些较复杂的运算可通过调用Module:Complex_Number/Functions来完成。本模块提供的3个部分(cmath、qmath、math)皆支持Module:Complex_Number/Functions。
- 使用方法
-
mathlib = require("Module:Complex Number/Functions")._init(mathlib, numberConstructer)
- 其中,
mathlib
为已初始化的数学函数库(如cmath、qmath、math),numberConstructer
为对应该数学函数库数字结构的构造函数函数。 - 所回传的新mathlib将会包含Module:Complex_Number/Functions中已定义的所有扩展函数。
- 注:详细使用条件参见Module:Complex_Number/Functions/doc#使用条件,说明了函数库须具备那些条件方能使用此扩展。
定义新的数学库
Module:Complex Number是一系列数学运算库,并可以相互兼容。当然也能定义其他兼容的程序库,但需要符合特定条件,例如需要实现一些需求函数。详细内容可以参考示例数学库Module:Complex Number/Example。
若要定义一个新的Module:Complex Number系列函数库需要实现一个新的对象,并实现其Metatables中的运算符。
定义数学数据结构
数学数据结构需要定义成一个table,并以table来定义或表达所需要的数字。即使数字只有单一对象,也许使用table因为这样才能通过实现Metatables来完成Module:Complex Number系列函数库所需的相关功能。
- numberType:本数学数据结构的类型名称(字符串),用于Module:Complex Number系列函数库的识别(参阅Example的第92行)
- update():更新结构数值的成员函数(参阅Example的第89行)
- clean():去除过小值或误差值的成员函数,并返回结果。若无此需求,直接返回自身即可。(参阅Example的第90行)
实现metatable
需定义Metatables的 __add(加法)、 __sub(减法)、 __mul(乘法)、 __div(除法)、 __mod(取余数)、 __unm(相反数)、 __eq(相等判断)、 __tostring(以字符串表达本对象)
定义数学数据结构的构造函数
由于数学数据结构需要定义为table因此需要有构造函数来赋予该结构初值。构造函数需要完成以下步骤:
- 读取输入的对象或字符串将其存入table对象中(参阅Example的第91行)
- 设置table的metatable为刚才定义的metatable(参阅Example的第88行)
- 定义其他所需的成员变量或函数
定义数学库的初始化函数
数学库必须是一个独立对象,所有的函数皆需定义在数学函数库对象下(包括数学数据结构的构造函数)。初始化数学库的函数名称必为init,当中需要定义以下内容:
- 各项常量的定义(参阅Example的第102行)
- numberType成员函数定义为Module:Complex Number中的_numberType(参阅Example的第106行)
- constructor成员函数设置为数学结构的构造函数(参阅Example的第107行)
- elements成员变量设置为单位元的清单(参阅Example的第108行)
完成数学库的定义
视情况定义列于Module:Complex_Number/doc#比较中的各项函数(如需支持Module:Complex_Number/Functions的情况)。
其他函数库
require("Module:Complex Number").cmath
- 复变函数库
require("Module:Complex Number").qmath
- 四元数函数库
require("Module:Complex Number").math
- 实数函数库扩展
require("Module:Complex Number").bmath
- 布尔代数函数库
require("Module:Complex Number/Calculate").tagmath
- 输出为
<math></math>
的运算库 require("Module:Complex Number/Matrix").mmath
- 矩阵函数库
require("Module:Complex Number/Dual Number").dumath
- 二元数函数库
require("Module:Complex Number/Dual Number").ducmath
- 二元复数函数库
require("Module:Complex Number/Octonion").omath
- 八元数函数库
require("Module:Complex Number/CayleyDickson").cdmath.init(math_lib)
- 将指定的函数库
math_lib
套用凯莱-迪克森结构形成新的函数库(无法自我嵌套) require("Module:Complex Number/CayleyDickson").sdmath
- 八元数套用凯莱-迪克森结构后的形成新的十六元数函数库
require("Module:Complex Number/CayleyDickson").cdmathOctonion
- 预先套用凯莱-迪克森结构的八元数后的函数库(可作为十六元数使用)
require("Module:Complex Number/CayleyDickson").cdmathSedenion
- 预先套用凯莱-迪克森结构的十六元数后的函数库(可作为三十二元数使用)
相关页面
- Module:Complex_Number/Solver:求解器和部分共享的函数。
--'
local p = { PrimeTable = {} }
local numlib = require("Module:Number")
local numdata = require("Module:Number/data")
local calclib = require("Module:Complex Number/Calculate")
local sollib = require("Module:Complex_Number/Solver")
p._numberType = sollib._numberType
p._isNaN = sollib._isNaN
--debug
--local cmath,tonum=p.cmath.init(),p.cmath.init().toComplexNumber; mw.logObject(cmath.abs(cmath.nonRealPart(tonum("2+3i"))))
local eReal, eImag = 'reω', 'ω'
p.cmath = {
abs=function(z)
local real, imag = p.cmath.readPart(z)
if math.abs(imag) < 1e-12 then return math.abs(real) end
return math.sqrt(real * real + imag * imag)
end,
floor=function(z)
local real, imag = p.cmath.readPart(z)
return p.cmath.getComplexNumber(math.floor(real), math.floor(imag))
end,
ceil=function(z)
local real, imag = p.cmath.readPart(z)
return p.cmath.getComplexNumber(math.ceil(real), math.ceil(imag))
end,
round=function(op1,op2,op3)
local number = p.cmath.getComplexNumber(tonumber(op1) or op1.real or 0, (tonumber(op1) and 0) or op1.imag or 0)
local digs = p.cmath.getComplexNumber(tonumber(op2) or (op2 or {}).real or 0, (tonumber(op2) and 0) or (op2 or {}).imag or 0)
local base = p.cmath.getComplexNumber(tonumber(op3) or (op3 or {}).real or 10, (tonumber(op3) and 0) or (op3 or {}).imag or 0)
local round_rad = p.cmath.pow(base,digs)
local check_number = number * round_rad
check_number.real = check_number.real + 0.5; check_number.imag = check_number.imag + 0.5;
return p.cmath.floor( check_number ) / round_rad
end,
div=function(op1,op2)
local a, c = tonumber(op1) or op1.real, tonumber(op2) or op2.real
local b, d = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
local op1_d, op2_d = a*a + b*b, c*c + d*d
if op2_d <= 0 then return op1_d / op2_d end
return p.cmath.getComplexNumber((a * c + b * d) / op2_d, (b * c - a * d) / op2_d)
end,
re=function(z)return tonumber(z) or z.real end,
im=function(z) return (tonumber(z) and 0) or z.imag end,
nonRealPart=function(z) return p.cmath.getComplexNumber(0, (tonumber(z) and 0) or z.imag) end,
conjugate=function(z)
local real, imag = p.cmath.readPart(z)
return p.cmath.getComplexNumber(real, -imag)
end,
inverse=function(z)
local real, imag = p.cmath.readPart(z)
return p.cmath.getComplexNumber(real, -imag) / ( real*real + imag*imag )
end,
tovector=function(z)
return {p.cmath.readPart(z)}
end,
trunc=function(z,digs)
local real, imag = p.cmath.readPart(z)
local n = tonumber(digs) or digs.real or 0
return p.cmath.getComplexNumber(sollib._trunc(real,n), sollib._trunc(imag,n))
end,
digits=function(z)
local real, imag = p.cmath.readPart(z)
real, imag = math.floor(math.abs(real)), math.floor(math.abs(imag))
return math.max(tostring(real):len(),tostring(imag):len())
end,
--判斷是否為第一象限高斯質數
is_prime_quadrant1=function(z)
local real, imag = p.cmath.readPart(z)
if imag == 0 and real == 0 then return false end
if not numdata._is_integer(imag) or not numdata._is_integer(real) then return false end
if imag == 0 then
if real <= 1 then return false end
if numdata._is_integer((real - 3.0) / 4.0) then
if p.PrimeTable.table_max == nil then p.PrimeTable = require('Module:Factorization') end
p.PrimeTable.primeIndexOf({(real or 0)+2})
return p.PrimeTable.lists[real] ~= nil
end
end
--非第一象限高斯質數
if imag < 0 or real < 0 then return false end
if imag ~= 0 and real == 0 then return false end
local value = imag*imag + real*real
--both are nonzero and a² + b² is a prime number (which will not be of the form 4n + 3).
if numdata._is_integer((value - 3.0) / 4.0) then return false end
if p.PrimeTable.table_max == nil then p.PrimeTable = require('Module:Factorization') end
p.PrimeTable.primeIndexOf({value+2})
return p.PrimeTable.lists[value] ~= nil
end,
sqrt=function(z)
local real, imag = p.cmath.readPart(z)
local argument = 0
local length = math.sqrt( real * real + imag * imag )
if imag ~= 0 then
argument = 2.0 * math.atan(imag / (length + real))
else
if real > 0 then argument = 0.0
else argument = math.pi end
end
local sq_len = math.sqrt(length)
return p.cmath.getComplexNumber(sq_len * math.cos(argument/2.0), sq_len * math.sin(argument/2.0)):clean()
end,
root=function(_z,_n,_num)
local z = p.cmath.getComplexNumber(p.cmath.readPart(_z))
local n = p.cmath.getComplexNumber(p.cmath.readPart(_n or 2))
local num = p.cmath.getComplexNumber(p.cmath.readPart(_num or 1))
if num == p.cmath.one or num == p.cmath.zero or num == nil then
return p.cmath.pow(z, p.cmath.inverse(n))
end
local sgn_data = p.cmath.getComplexNumber(0, 1)
local result = p.cmath.pow(p.cmath.abs(z), p.cmath.inverse(n)) * p.cmath.exp(sgn_data * (p.cmath.arg(z) + (num-1)*(2*math.pi) ) * p.cmath.inverse(n))
result:clean()
return result
end,
sin=function(z)
local real, imag = p.cmath.readPart(z)
return p.cmath.getComplexNumber(math.sin(real) * math.cosh(imag), math.cos(real) * math.sinh(imag))
end,
cos=function(z)
local real, imag = p.cmath.readPart(z)
return p.cmath.getComplexNumber(math.cos(real) * math.cosh(imag), -math.sin(real) * math.sinh(imag))
end,
tan=function(z)
local theta = p.cmath.readComplexNumber(z)
return p.cmath.sin(theta) / p.cmath.cos(theta)
end,
cot=function(z)
local theta = p.cmath.readComplexNumber(z)
return p.cmath.cos(theta) / p.cmath.sin(theta)
end,
asin=function(z)
local real, imag = p.cmath.readPart(z)
local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
return -sgnimag * p.cmath.asinh( v * sgnimag )
end,
acos=function(z)
local real, imag = p.cmath.readPart(z)
local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
return -sgnimag * p.cmath.acosh( v )
end,
atan=function(z)
local real, imag = p.cmath.readPart(z)
local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
return -sgnimag * p.cmath.atanh( v * sgnimag )
end,
acot=function(z)
local real, imag = p.cmath.readPart(z)
local u, v = p.cmath.getComplexNumber(0, imag), p.cmath.getComplexNumber(real, imag)
local sgnimag = p.cmath.sgn(u); if math.abs(sgnimag.imag) < 1e-12 then sgnimag.imag = 1 end
return sgnimag * p.cmath.acoth( v * sgnimag )
end,
sinh=function(z)
local real, imag = p.cmath.readPart(z)
local im_sgn if imag > 0 then im_sgn = 1 elseif imag < 0 then im_sgn = -1 else im_sgn = 0 end
return p.cmath.getComplexNumber( math.cos(math.abs(imag)) * math.sinh(real) , im_sgn * math.sin(math.abs(imag)) * math.cosh(real) )
end,
cosh=function(z)
local real, imag = p.cmath.readPart(z)
local im_sgn if imag > 0 then im_sgn = 1 elseif imag < 0 then im_sgn = -1 else im_sgn = 0 end
return p.cmath.getComplexNumber( math.cos(math.abs(imag)) * math.cosh(real) , im_sgn * math.sin(math.abs(imag)) * math.sinh(real) )
end,
tanh=function(z)
local theta = p.cmath.readComplexNumber(z)
return p.cmath.sinh(theta) / p.cmath.cosh(theta)
end,
coth=function(z)
local theta = p.cmath.readComplexNumber(z)
return p.cmath.cosh(theta) / p.cmath.sinh(theta)
end,
asinh=function(z)
local real, imag = p.cmath.readPart(z)
local u = p.cmath.getComplexNumber(real, imag)
return p.cmath.log( u + p.cmath.sqrt( u * u + p.cmath.getComplexNumber(1,0) ) )
end,
acosh=function(z)
local real, imag = p.cmath.readPart(z)
local u = p.cmath.getComplexNumber(real, imag)
return p.cmath.log( u + p.cmath.sqrt( u + p.cmath.getComplexNumber(1,0) ) * p.cmath.sqrt( u + p.cmath.getComplexNumber(-1,0) ) )
end,
atanh=function(z)
local real, imag = p.cmath.readPart(z)
local u = p.cmath.getComplexNumber(real, imag)
return ( p.cmath.log( 1 + u ) - p.cmath.log( 1 - u ) ) / 2
end,
acoth=function(z)
local real, imag = p.cmath.readPart(z)
local u = p.cmath.getComplexNumber(real, imag)
return ( p.cmath.log( 1 + p.cmath.inverse(u) ) - p.cmath.log( 1 - p.cmath.inverse(u) ) ) / 2
end,
dot=function (op1, op2)
local real1, imag1 = p.cmath.readPart(op1)
local real2, imag2 = p.cmath.readPart(op2)
return real1 * real2 + imag1 * imag2
end,
outer = function (op1, op2)
return p.cmath.getComplexNumber(0, 0)
end,
sgn=function(z)
local real, imag = p.cmath.readPart(z)
if real == 0 and imag == 0 then return p.cmath.getComplexNumber(0, 0) end
local length = math.sqrt( real * real + imag * imag )
return p.cmath.getComplexNumber(real/length, imag/length)
end,
arg=function(z)
local real, imag = p.cmath.readPart(z)
if imag ~= 0 then
local length = math.sqrt( real * real + imag * imag )
return 2.0 * math.atan(imag / (length + real))
else
if real >= 0 then return 0.0
else return math.pi end
end
return tonumber("nan")
end,
cis=function(z)
local real, imag = p.cmath.readPart(z)
local hyp = 1
if imag ~= 0 then hyp = math.cosh(imag) - math.sinh(imag) end
return p.cmath.getComplexNumber(math.cos(real) * hyp, math.sin(real) * hyp)
end,
exp=function(z)
local real, imag = p.cmath.readPart(z)
local cis_r, cis_i, exp_r = 1, 0, math.exp(real)
if imag ~= 0 then cis_r, cis_i = math.cos(imag), math.sin(imag) end
return p.cmath.getComplexNumber(exp_r * cis_r, exp_r * cis_i)
end,
elog=function(z)
local real, imag = p.cmath.readPart(z)
local argument = 0
local length = math.sqrt( real * real + imag * imag )
if imag ~= 0 then
argument = 2.0 * math.atan(imag / (length + real))
else
if real > 0 then argument = 0.0
else argument = math.pi end
end
return p.cmath.getComplexNumber(math.log(length), argument)
end,
log=function(z,basez)
if basez~=nil then return p.cmath.elog(basez) * p.cmath.inverse(p.cmath.elog(z)) end
return p.cmath.elog(z)
end,
eisenstein=function(op1)
local real1, imag1 = tonumber(op1) or op1.real, (tonumber(op1) and 0) or op1.imag
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
return p._eisenstein_integer(real1+sqrt33*imag1, 2*sqrt33*imag1)
end,
pow=function(op1,op2)
local check_op1, check_op2 = tonumber(tostring(op1)) or -1, tonumber(tostring(op2)) or -1
if check_op1 == 1 then return p.cmath.getComplexNumber(1,0) end -- 1^z === 1
if check_op2 == 1 then return op1 end -- z^1 === z
if check_op2 == 0 then -- z^0
if check_op1 ~= 0 then return p.cmath.getComplexNumber(1,0) -- z^0 === 1, z ≠ 0
else return p.cmath.getComplexNumber(tonumber('nan'),0) end -- 0^0 Indeterminate
elseif check_op1 == 0 then
if check_op2 < 0 then return p.cmath.getComplexNumber(tonumber('inf'),0) end -- 0^(-n) Infinity
return p.cmath.getComplexNumber(0,0) -- 0^z === 0, z ≠ 0
end
--a ^ z
local a = p.cmath.getComplexNumber( tonumber(op1) or op1.real, (tonumber(op1) and 0) or op1.imag )
local z = p.cmath.getComplexNumber( tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag )
return p.cmath.exp(z * p.cmath.log(a)):clean()
end,
random = function (op1, op2)
if type(op1)==type(nil) and type(op2)==type(nil) then return p.cmath.getComplexNumber(math.random(),0) end
local real1, real2 = tonumber(op1) or op1.real, tonumber(op2) or (op2 or{}).real
local imag1, imag2 = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or (op2 or{}).imag
if type(op2)==type(nil) then return p.cmath.getComplexNumber(sollib._random(real1), sollib._random(imag1)) end
return p.cmath.getComplexNumber(sollib._random(math.min(real1,real2), math.max(real1,real2)), sollib._random(math.min(imag1,imag2), math.max(imag1,imag2)))
end,
isReal=function(z) return math.abs((tonumber(z) and 0) or z.imag) < 1e-14 end,
ComplexNumberMeta = {
__add = function (op1, op2)
local real1, real2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local imag1, imag2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
return p.cmath.getComplexNumber(real1 + real2, imag1 + imag2)
end,
__sub = function (op1, op2)
local real1, real2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local imag1, imag2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
return p.cmath.getComplexNumber(real1 - real2, imag1 - imag2)
end,
__mul = function (op1, op2)
local a, c = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local b, d = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
return p.cmath.getComplexNumber(a * c - b * d, b * c + a * d)
end,
__div = function (op1, op2)
local a, c = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local b, d = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
local op1_d, op2_d = a*a + b*b, c*c + d*d
if op2_d <= 0 then return op1_d / op2_d end
return p.cmath.getComplexNumber((a * c + b * d) / op2_d, (b * c - a * d) / op2_d)
end,
__mod = function (op1, op2)
local x = p.cmath.getComplexNumber(tonumber(op1) or (op1 or {}).real, (tonumber(op1) and 0) or (op1 or {}).imag)
local y = p.cmath.getComplexNumber(tonumber(op2) or (op2 or {}).real, (tonumber(op2) and 0) or (op2 or {}).imag)
return x - y * p.cmath.floor(x / y)
end,
__tostring = function (this)
local body = ''
if this.real ~= 0 then body = tostring(this.real) end
if this.imag ~= 0 then
if body ~= '' and this.imag > 0 then body = body .. '+' end
if this.imag == -1 then body = body .. '-' end
if math.abs(this.imag) ~= 1 then body = body .. tostring(this.imag) end
body = body .. 'i'
end
if sollib._isNaN(this.real) or sollib._isNaN(this.imag) then body = 'nan' end
if body == '' then body = '0' end
return body
end,
__unm = function (this)
return p.cmath.getComplexNumber(-this.real, -this.imag)
end,
__eq = function (op1, op2)
local diff_real = math.abs( (tonumber(op1) or (op1 or {}).real) - (tonumber(op2) or (op2 or {}).real) )
local diff_imag1 = math.abs( ( (tonumber(op1) and 0) or (op1 or {}).imag) - ( (tonumber(op2) and 0) or (op2 or {}).imag) )
return diff_real < 1e-12 and diff_imag1 < 1e-12
end,
},
readComplexNumber = function(z)
if type(z) == type({}) then --if already be complex number, don't run string find.
if z.numberType == "complex" then
return z
elseif z.numberType == "quaternion" then
return p.cmath.getComplexNumber(z.real, z.imag)
end
elseif type(z) == type(0) then
return p.cmath.getComplexNumber(z, 0)
elseif type(z) == type(true) then
return p.cmath.getComplexNumber(z and 1 or 0, 0)
end
return p.cmath.getComplexNumber(tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or (z or {}).imag or 0)
end,
readPart = function(z)
if type(z) == type({}) and (z.numberType == "complex" or z.numberType == "quaternion") then --if already be complex number, don't run string find.
return z.real, z.imag
elseif type(z) == type(0) then
return z, 0
elseif type(z) == type(true) then
return z and 1 or 0, 0
end
return tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0, ((tonumber(z) or tonumber(tostring(z))) and 0) or (z or {}).imag or 0
end,
ele=function(id)
local _zero = p.cmath.getComplexNumber(0, 0)
local eles = (p.cmath.elements or {})
local id_msg = tonumber(tostring(id)) or 0
return eles[id_msg+1]or _zero
end,
getComplexNumber = function(real,imag)
local ComplexNumber = {}
setmetatable(ComplexNumber,p.cmath.ComplexNumberMeta)
function ComplexNumber:update()
self.argument = 0
self.length = math.sqrt( self.real * self.real + self.imag * self.imag )
if self.imag ~= 0 then
self.argument = 2.0 * math.atan(self.imag / (self.length + self.real))
else
if self.real > 0 then self.argument = 0.0
else self.argument = math.pi end
end
end
function ComplexNumber:clean()
if math.abs(self.real) <= 1e-12 then self.real = 0 end
if math.abs(self.imag) <= 1e-12 then self.imag = 0 end
if math.abs(self.real - math.floor(self.real)) <= 1e-12 then self.real = math.floor(self.real) end
if math.abs(self.imag - math.floor(self.imag)) <= 1e-12 then self.imag = math.floor(self.imag) end
return self
end
ComplexNumber.real, ComplexNumber.imag = real, imag
ComplexNumber.numberType = "complex"
return ComplexNumber
end,
toComplexNumber = function(num_str)
if type(num_str)==type({"table"}) and num_str.isEisensteinNumber == true then
real, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local eis = p._eisenstein_integer(real+sqrt33*imag, 2*sqrt33*imag)
eis.real,eis.imag = real, imag
return eis
end
if type(num_str) == type({}) then --if already be complex number, don't run string find.
if num_str.numberType == "complex" then
return num_str
elseif num_str.numberType == "quaternion" then
return p.cmath.getComplexNumber(num_str.real, num_str.imag)
end
elseif type(num_str) == type(0) then
return p.cmath.getComplexNumber(num_str, 0)
elseif type(num_str) == type(true) then
return p.cmath.getComplexNumber(num_str and 1 or 0, 0)
elseif type(num_str) == type("string") then
local check_number = tonumber(num_str)
if check_number ~= nil then return p.cmath.getComplexNumber(check_number, 0) end
end
local real, imag
if num_str == nil then return nil end
if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then
real, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag
else real, imag = p.cmath.toComplexNumberPart(num_str)end
if real == nil or imag == nil then return nil end
return p.cmath.getComplexNumber(real, imag)
end,
toComplexNumberPart = function(num_str)
if type(num_str) == type(function()end) then return end
if type(num_str) == type(true) then if num_str then return 1,0 else return 0,0 end end
local body = ''
local real, imag = 0, 0
local split_str = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(
tostring(num_str) or '',
'%s+',''),'%++([%d%.])',',+%1'),'%++([ij])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ij])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ij])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ij])',',/1%1'),',')
local first = true
local continue = false
for k,v in pairs(split_str) do
continue = false
local val = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.text.trim(v),'[ij]+','i'),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ij])','+1%1')
if mw.ustring.find(val,"%/") or mw.ustring.find(val,"%*") then return end
if val == nil or val == '' then if first == true then first = false continue = true else return end end
if not continue then
local num_text = mw.ustring.match(val,"[%+%-][%d%.]+i?")
if num_text ~= val then return end
local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
if num_part == nil then return end
if mw.ustring.find(num_text,"i") then
imag = imag + num_part
else
real = real + num_part
end
end
end
return real, imag
end,
halfNumberParts = function(num)
local real, imag = p.cmath.readPart(num)
return {real, imag}
end,
init = function()
p.cmath.e = p.cmath.getComplexNumber(math.exp(1), 0)
p.cmath.pi = p.cmath.getComplexNumber(math.pi, 0)
p.cmath["π"] = p.cmath.getComplexNumber(math.pi, 0)
p.cmath["°"] = p.cmath.getComplexNumber(math.pi/180, 0)
p.cmath.nan = p.cmath.getComplexNumber(tonumber("nan"), tonumber("nan"))
p.cmath.infi = p.cmath.getComplexNumber(0, tonumber("inf"))
p.cmath.zero = p.cmath.getComplexNumber(0, 0)
p.cmath.one = p.cmath.getComplexNumber(1, 0)
p.cmath[-1] = p.cmath.getComplexNumber(-1, 0)
p.cmath[eImag] = p._eisenstein_integer(0, 1)
p.cmath.i = p.cmath.getComplexNumber(0, 1)
p.cmath[0],p.cmath[1] = p.cmath.zero,p.cmath.one
p.cmath.numberType = sollib._numberType
p.cmath.constructor = p.cmath.toComplexNumber
p.cmath.elements = {
p.cmath.getComplexNumber(1, 0),
p.cmath.getComplexNumber(0, 1)
}
return p.cmath
end
}
p.math={
init = function()
local my_math = math
my_math.e, my_math.nan = math.exp(1), tonumber("nan")
my_math["π"] = math.pi
my_math["°"] = math.pi/180
my_math.zero, my_math.one, my_math[-1] = 0, 1, -1
my_math[0],my_math[1] = my_math.zero,my_math.one
my_math.inverse = function(x)return 1.0/(tonumber(x)or 1.0)end
my_math.sgn=function(x)if x==0 then return 0 elseif x<0 then return -1 elseif x>0 then return 1 else return tonumber("nan")end end
my_math.arg=function(x)if x >= 0 then return 0.0 else return math.pi end end
my_math.re=function(z) return tonumber(z) or z.real or 0 end
my_math.im=function(z) return (tonumber(z) and 0) or z.imag or 0 end
my_math.conjugate=function(z) return tonumber(z) or z.real or 0 end
my_math.root=function(z,n) return math.pow((tonumber(z)or 1.0), (1.0/(tonumber(n)or 1.0))) end
my_math.nonRealPart=function(z) return (tonumber(z) and 0) or z.imag or 0 end
my_math.tovector=function(z) return {tonumber(z) or z.real or 0} end
my_math.trunc=function(z,digs)
local x = tonumber(z) or z.real or 0
local n = tonumber(digs) or digs.real or 0
local _10_n = math.pow(10,n)
local _10_n_x = _10_n * x
return (x >= 0)and(math.floor(_10_n_x) / _10_n)or(math.ceil(_10_n_x) / _10_n)
end
my_math.div=function(op1,op2) return tonumber(op1) / tonumber(op2) end
my_math.dot=function(x,y)return x*y end
--sin, cos, tan are already support
my_math.cot=function(z)local theta = tonumber(z)return math.cos(theta) / math.sin(theta)end
--asin, acos, atan are already support
my_math.acot=function(x)return p.cmath.acot(x).real end
--sinh, cosh, tanh are already support
my_math.coth=function(x)return math.cosh(x) / math.sinh(x) end
my_math.asinh=function(x)return math.log( x + math.sqrt( x * x + 1 ) )end
my_math.acosh=function(x)return math.log( x + math.sqrt( x * x - 1 ) )end
my_math.atanh=function(x) local result = p.cmath.atanh(x):clean() if math.abs(result.imag) > 1e-12 then return tonumber('nan') else return result.real end end
my_math.acoth=function(x) local result = p.cmath.acoth(x):clean() if math.abs(result.imag) > 1e-12 then return tonumber('nan') else return result.real end end
my_math.ele=function(id)
if (tonumber(tostring(id))or -1) == 0 then return 1 end
return 0
end
my_math.isReal = function(x) if type(x)==type(true) then return true else return tonumber(x)~=nil end end
my_math.numberType = sollib._numberType
my_math.constructor = function(x) if type(x)==type(true) then return x and 1 or 0 else return tonumber(x) end end
my_math.elements = {1}
return my_math
end
}
p.bmath={
abs=function(_z)
local z = p.bmath.toBoolean(_z)
return (not not z.value) and 1 or 0
end,
sgn=function(_z)
local z = p.bmath.toBoolean(_z)
return (not not z.value) and 1 or 0
end,
as=function(op1, op2)
local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
b.value = a.value
return b
end,
nonRealPart=function(bv) return p.bmath.toBoolean(0) end,
BooleanNumberMeta = {
__add = function (op1, op2)
local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
a.value = a.value or b.value
return a
end,
__sub = function (op1, op2)
local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
a.value = a.value and (not b.value)
return a
end,
__mul = function (op1, op2)
local a, b = p.bmath.toBoolean(op1) or p.bmath.toBoolean(false), p.bmath.toBoolean(op2) or p.bmath.toBoolean(false)
a.value = a.value and b.value
return a
end,
__tostring = function (this) return this.value_table[this.value] end,
__unm = function (this)local that = p.bmath.toBoolean(this)that.value = not that.value return that end,
__eq = function (op1, op2)return p.bmath.toBoolean(op1).value == p.bmath.toBoolean(op2).value end,
},
value_table={
[1]={[true]=1,[false]=0},[0]={[true]=1,[false]=0},
['1']={[true]=1,[false]=0},['0']={[true]=1,[false]=0},
['yes']={[true]='yes',[false]='no'},['no']={[true]='yes',[false]='no'},
['y']={[true]='Y',[false]='N'},['n']={[true]='Y',[false]='N'},
[true]={[true]=true,[false]=false},[false]={[true]=true,[false]=false},
['true']={['true']=true,['false']=false},['false']={['true']=true,['false']=false},
['t']={[true]='T',[false]='F'},['f']={[true]='T',[false]='F'},
['on']={[true]='on',[false]='off'},['off']={[true]='on',[false]='off'},
['是']={[true]='是',[false]='否'},['否']={[true]='是',[false]='否'},
['真']={[true]='真',[false]='假'},['假']={[true]='真',[false]='假'},
['有']={[true]='有',[false]='無'},['無']={[true]='有',[false]='無'},['无']={[true]='有',[false]='无'},
['开']={[true]='开',[false]='关'},['关']={[true]='开',[false]='关'},
['開']={[true]='開',[false]='關'},['關']={[true]='開',[false]='關'},},
toBoolean = function(num_str)
local BooleanNumber = {}
if (type(num_str) == type({}) and num_str.numberType == "boolean") then return num_str end
if (type(num_str) == type({})) and num_str.value_table ~= nil and num_str.value ~= nil then
BooleanNumber = {value_table=num_str.value_table,value=num_str.value}
elseif (type(num_str) == type({}) and type(num_str.numberType)==type("string") and num_str.numberType ~= "boolean")then
local data = tostring(num_str) ~= "0"
BooleanNumber = {}
BooleanNumber.value_table={[true]='T',[false]='F'}
BooleanNumber.value=data
elseif (type(num_str) == type(0))then
local data = math.abs(num_str) > 1e-14
BooleanNumber = {}
BooleanNumber.value_table={[true]='T',[false]='F'}
BooleanNumber.value=data
elseif (type(num_str) == type(true))then
local data = num_str
BooleanNumber = {}
BooleanNumber.value_table={[true]='T',[false]='F'}
BooleanNumber.value=data
else
if yesno == nil then yesno = require('Module:Yesno') end
local input_str = mw.ustring.gsub(mw.text.trim(tostring(num_str)),"%s",'')
input_str = mw.ustring.gsub(input_str,"([真假有無无])",function(str) return(
{['真']='是',['假']='否',['有']='是',['無']='否',['无']='否'})[str] or str end)
local data = yesno(num_str) or yesno(input_str)
if data == nil then return nil end
BooleanNumber = {}
BooleanNumber.value_table=p.bmath.value_table[num_str] or p.bmath.value_table[input_str] or {[true]='T',[false]='F'}
BooleanNumber.value=data
end
setmetatable(BooleanNumber,p.bmath.BooleanNumberMeta)
BooleanNumber.numberType = "boolean"
return BooleanNumber
end,
init = function()
p.bmath.zero = p.bmath.toBoolean(0)
p.bmath.one = p.bmath.toBoolean(1)
p.bmath[0],p.bmath[1] = p.bmath.zero,p.bmath.one
p.bmath.is_bool_lib = true
p.bmath.numberType = sollib._numberType
p.bmath.constructor = p.bmath.toBoolean
p.bmath.elements = {true}
return p.bmath
end
}
p.qmath = {
abs=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
if imag == 0 and jpart == 0 and kpart == 0 then return math.abs(real) end
return math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart )
end,
floor=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
return p.qmath.getQuaternionNumber(math.floor(real), math.floor(imag), math.floor(jpart), math.floor(kpart))
end,
ceil=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
return p.qmath.getQuaternionNumber(math.ceil(real), math.ceil(imag), math.ceil(jpart), math.ceil(kpart))
end,
div=function(left,z)
local lreal, limag, ljpart, lkpart = p.qmath.readPart(left)
local real, imag, jpart, kpart = p.qmath.readPart(z)
return p.qmath.getQuaternionNumber(lreal, limag, ljpart, lkpart) * (p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart ) / ( real*real + imag*imag + jpart*jpart + kpart*kpart ))
end,
round=function(op1,op2,op3)
local number = p.qmath.getQuaternionNumber(tonumber(op1) or op1.real or 0, (tonumber(op1) and 0) or (op1.imag or 0) or 0, (tonumber(op1) and 0) or (op1.jpart or 0) or 0, (tonumber(op1) and 0) or (op1.kpart or 0) or 0)
local digs = p.qmath.getQuaternionNumber(tonumber(op2) or (op2 or {}).real or 0, (tonumber(op2) and 0) or ((op2 or {}).imag or 0) or 0, (tonumber(op2) and 0) or ((op2 or {}).jpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) or 0 )
local base = p.qmath.getQuaternionNumber(tonumber(op3) or (op3 or {}).real or 10, (tonumber(op3) and 0) or ((op3 or {}).imag or 0) or 0, (tonumber(op3) and 0) or ((op3 or {}).jpart or 0) or 0, (tonumber(op3) and 0) or ((op3 or {}).kpart or 0) or 0 )
local round_rad = p.qmath.pow(base,digs)
local check_number = number * round_rad
check_number.real = check_number.real + 0.5; check_number.imag = check_number.imag + 0.5;
check_number.jpart = check_number.jpart + 0.5; check_number.kpart = check_number.kpart + 0.5;
return p.qmath.floor( check_number ) * p.qmath.inverse(round_rad)
end,
re=function(z)return tonumber(z) or z.real end,
im=function(z) return (tonumber(z) and 0) or z.imag end,
conjugate=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
return p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart )
end,
inverse=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
return p.qmath.getQuaternionNumber( real, -imag, -jpart, -kpart ) / ( real*real + imag*imag + jpart*jpart + kpart*kpart )
end,
tovector=function(z)
return {p.qmath.readPart(z)}
end,
trunc=function(z,digs)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local n = tonumber(digs) or digs.real or 0
return p.qmath.getQuaternionNumber( sollib._trunc(real,n), sollib._trunc(imag,n), sollib._trunc(jpart,n), sollib._trunc(kpart,n) )
end,
sqrt=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
if jpart == 0 and kpart == 0 then
local complex = p.cmath.sqrt(p.cmath.getComplexNumber(real, imag))
return p.qmath.getQuaternionNumber(complex.real, complex.imag, 0, 0)
end
return p.qmath.pow(z, 0.5)
end,
root=function(_z,_n,_num)
local z = p.qmath.getQuaternionNumber(p.qmath.readPart(_z))
local n = p.qmath.getQuaternionNumber(p.qmath.readPart(_n or 2))
local num = p.qmath.getQuaternionNumber(p.qmath.readPart(_num or 1))
if num == p.qmath.one or num == p.qmath.zero or num == nil then
return p.qmath.pow(z, p.qmath.inverse(n))
end
local sgn_data = p.qmath.sgn(p.qmath.nonRealPart(z))
if math.abs(sgn_data.imag)<1e-14 and math.abs(sgn_data.jpart)<1e-14 and math.abs(sgn_data.kpart)<1e-14 then sgn_data=p.qmath.getQuaternionNumber(0,1,0,0) end
local result = p.qmath.pow(p.qmath.abs(z), p.qmath.inverse(n)) * p.qmath.exp(sgn_data * (p.qmath.arg(z) + (num-1)*(2*math.pi) ) * p.qmath.inverse(n))
result:clean()
return result
end,
sin=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
return ( math.cosh(p.qmath.abs(u)) * math.sin(real) ) + ( p.qmath.sgn(u) * math.sinh(p.qmath.abs(u)) * math.cos(real) )
end,
cos=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
return ( math.cosh(p.qmath.abs(u)) * math.cos(real) ) - ( p.qmath.sgn(u) * math.sinh(p.qmath.abs(u)) * math.sin(real) )
end,
tan=function(z)
local theta = p.qmath.readComplexNumber(z)
return p.qmath.sin(theta) * p.qmath.inverse( p.qmath.cos(theta) )
end,
cot=function(z)
local theta = p.qmath.readComplexNumber(z)
return p.qmath.cos(theta) * p.qmath.inverse( p.qmath.sin(theta) )
end,
asin=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
local sgnu = p.qmath.sgn(u);
if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
return -sgnu * p.qmath.asinh( v * sgnu )
end,
acos=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
local sgnu = p.qmath.sgn(u);
if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
return -sgnu * p.qmath.acosh( v )
end,
atan=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
local sgnu = p.qmath.sgn(u);
if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
return -sgnu * p.qmath.atanh( v * sgnu )
end,
acot=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
local sgnu = p.qmath.sgn(u);
if math.abs(sgnu.imag) < 1e-12 and math.abs(sgnu.jpart) < 1e-12 and math.abs(sgnu.kpart) < 1e-12 then sgnu.imag = 1 end
return sgnu * p.qmath.acoth( v * sgnu )
end,
sinh=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
return ( math.cos(p.qmath.abs(u)) * math.sinh(real) ) + ( p.qmath.sgn(u) * math.sin(p.qmath.abs(u)) * math.cosh(real) )
end,
cosh=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
return ( math.cos(p.qmath.abs(u)) * math.cosh(real) ) + ( p.qmath.sgn(u) * math.sin(p.qmath.abs(u)) * math.sinh(real) )
end,
tanh=function(z)
local theta = p.qmath.readComplexNumber(z)
return p.qmath.sinh(theta) * p.qmath.inverse( p.qmath.cosh(theta) )
end,
coth=function(z)
local theta = p.qmath.readComplexNumber(z)
return p.qmath.cosh(theta) * p.qmath.inverse( p.qmath.sinh(theta) )
end,
asinh=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
return p.qmath.log( u + p.qmath.sqrt( u * u + p.qmath.getQuaternionNumber(1,0,0,0) ) )
end,
acosh=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
return p.qmath.log( u + p.qmath.sqrt( u + p.qmath.getQuaternionNumber(1,0,0,0) ) * p.qmath.sqrt( u + p.qmath.getQuaternionNumber(-1,0,0,0) ) )
end,
atanh=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
return ( p.qmath.log( 1 + u ) - p.qmath.log( 1 - u ) ) / 2
end,
acoth=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
return ( p.qmath.log( 1 + p.qmath.inverse(u) ) - p.qmath.log( 1 - p.qmath.inverse(u) ) ) / 2
end,
dot = function (op1, op2)
local a, t = tonumber(op1) or op1.real, tonumber(op2) or op2.real
local b, x = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
local c, y = (tonumber(op1) and 0) or (op1.jpart or 0), (tonumber(op2) and 0) or (op2.jpart or 0)
local d, z = (tonumber(op1) and 0) or (op1.kpart or 0), (tonumber(op2) and 0) or (op2.kpart or 0)
return a * t + b * x + c * y + d * z
end,
outer = function (op1, op2)
local a, t = tonumber(op1) or op1.real, tonumber(op2) or op2.real
local b, x = (tonumber(op1) and 0) or op1.imag, (tonumber(op2) and 0) or op2.imag
local c, y = (tonumber(op1) and 0) or (op1.jpart or 0), (tonumber(op2) and 0) or (op2.jpart or 0)
local d, z = (tonumber(op1) and 0) or (op1.kpart or 0), (tonumber(op2) and 0) or (op2.kpart or 0)
return p.qmath.getQuaternionNumber(0,
c*z-d*y,
d*x-b*z,
b*y-x*c
)
end,
scalarPartQuaternion=function(z)
return p.qmath.getQuaternionNumber(tonumber(z) or z.real, 0, 0, 0)
end,
nonRealPart=function(z) return p.qmath.getQuaternionNumber(0, (tonumber(z) and 0) or (z.imag or 0), (tonumber(z) and 0) or (z.jpart or 0), (tonumber(z) and 0) or (z.kpart or 0)) end,
vectorPartQuaternion=function(z)
return p.qmath.getQuaternionNumber(0, (tonumber(z) and 0) or (z.imag or 0), (tonumber(z) and 0) or (z.jpart or 0), (tonumber(z) and 0) or (z.kpart or 0))
end,
sgn=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local length = math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart )
if length <= 0 then return p.qmath.getQuaternionNumber(0,0,0,0) end
return z / length
end,
arg=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local length = math.sqrt( real * real + imag * imag + jpart * jpart + kpart * kpart )
return math.acos( real / length )
end,
cis=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
return p.qmath.cos(u) + p.qmath.getQuaternionNumber(0,1,0,0) * p.qmath.sin(u)
end,
exp=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u = p.qmath.getQuaternionNumber(0, imag, jpart, kpart)
return ( (p.qmath.sgn(u) * math.sin(p.qmath.abs(u))) + math.cos(p.qmath.abs(u))) * math.exp(real)
end,
elog=function(z)
local real, imag, jpart, kpart = p.qmath.readPart(z)
local u, v = p.qmath.getQuaternionNumber(0, imag, jpart, kpart), p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
return (p.qmath.sgn(u) * p.qmath.arg(v)) + math.log(p.qmath.abs(v))
end,
log=function(z,basez)
if basez~=nil then return p.qmath.elog(basez) * p.qmath.inverse(p.qmath.elog(z)) end
return p.qmath.elog(z)
end,
pow=function(op1,op2)
local check_op1, check_op2 = tonumber(tostring(op1)) or -1, tonumber(tostring(op2)) or -1
if check_op1 == 1 then return p.qmath.getQuaternionNumber(1,0,0,0) end -- 1^z === 1
if check_op2 == 1 then return op1 end -- z^1 === z
if check_op2 == 0 then -- z^0
if check_op1 ~= 0 then return p.qmath.getQuaternionNumber(1,0,0,0) -- z^0 === 1, z ≠ 0
else return p.qmath.getQuaternionNumber(tonumber('nan'),0,0,0) end --0^0 Indeterminate
elseif check_op1 == 0 then
if check_op2 < 0 then return p.qmath.getQuaternionNumber(tonumber('inf'),0,0,0) end -- 0^(-n) Infinity
return p.qmath.getQuaternionNumber(0,0,0,0) -- 0^z === 0, z ≠ 0
end
--a ^ z
local a = p.qmath.getQuaternionNumber( p.qmath.readPart(op1) )
local z = p.qmath.getQuaternionNumber( p.qmath.readPart(op2) )
a:clean();z:clean();
if a.jpart == 0 and z.jpart == 0 and a.kpart == 0 and z.kpart == 0 then
local complex = p.cmath.pow(p.cmath.getComplexNumber(a.real, a.imag), p.cmath.getComplexNumber(z.real, z.imag))
return p.qmath.getQuaternionNumber(complex.real, complex.imag, 0, 0)
end
return p.qmath.exp(z * p.qmath.log(a)):clean()
end,
random = function (op1, op2)
if type(op1)==type(nil) and type(op2)==type(nil) then return p.qmath.getQuaternionNumber(math.random(), 0, 0, 0) end
local a, t = tonumber(op1) or (op1 or {}).real or 0, tonumber(op2) or (op2 or{}).real or 0
local b, x = (tonumber(op1) and 0) or (op1 or {}).imag or 0, (tonumber(op2) and 0) or (op2 or{}).imag or 0
local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or{}).jpart or 0)
local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0) or 0, (tonumber(op2) and 0) or ((op2 or{}).kpart or 0)
if type(op2)==type(nil) then return p.qmath.getQuaternionNumber(sollib._random(a), sollib._random(b), sollib._random(c), sollib._random(d)) end
return p.qmath.getQuaternionNumber(sollib._random(math.min(a, t), math.max(a, t)), sollib._random(math.min(b, x), math.max(b, x)), sollib._random(math.min(c, y), math.max(c, y)), sollib._random(math.min(d, z), math.max(d, z)))
end,
isReal=function(z) return p.qmath.abs(p.qmath.nonRealPart(z)) < 1e-14 end,
QuaternionNumberMeta = {
__add = function (op1, op2)
local a, t = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local b, x = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
return p.qmath.getQuaternionNumber(a + t, b + x, c + y, d + z)
end,
__sub = function (op1, op2)
local a, t = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local b, x = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
local c, y = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
local d, z = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
return p.qmath.getQuaternionNumber(a - t, b - x, c - y, d - z)
end,
__mul = function (op1, op2)
local a1, a2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local b1, b2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
local c1, c2 = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
local d1, d2 = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
return p.qmath.getQuaternionNumber(
a1 * a2 - b1 * b2 - c1 * c2 - d1 * d2,
a1 * b2 + b1 * a2 + c1 * d2 - d1 * c2,
a1 * c2 - b1 * d2 + c1 * a2 + d1 * b2,
a1 * d2 + b1 * c2 - c1 * b2 + d1 * a2
)
end,
__div = function (op1, op2)
local r1, r2 = tonumber(op1) or (op1 or {}).real, tonumber(op2) or (op2 or {}).real
local i1, i2 = (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op2) and 0) or (op2 or {}).imag
local j1, j2 = (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)
local k1, k2 = (tonumber(op1) and 0) or ((op1 or {}).kpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)
if i2 ~= 0 or j2 ~= 0 or k2 ~= 0 then error( "Quaternion can not divide by non scalar value" ) end
local op1_d, op2_d = r1*r1 + i1*i1 + j1*j1 + k1*k1, r2*r2 + i2*i2 + j2*j2 + k2*k2
if op2_d <= 0 then return op1_d / op2_d end
return p.qmath.getQuaternionNumber(r1/r2, i1/r2, j1/r2, k1/r2)
end,
__mod = function (op1, op2)
local x = p.qmath.getQuaternionNumber(tonumber(op1) or (op1 or {}).real, (tonumber(op1) and 0) or (op1 or {}).imag, (tonumber(op1) and 0) or ((op1 or {}).jpart or 0), (tonumber(op1) and 0) or ((op1 or {}).kpart or 0) )
local y = p.qmath.getQuaternionNumber(tonumber(op2) or (op2 or {}).real, (tonumber(op2) and 0) or (op2 or {}).imag, (tonumber(op2) and 0) or ((op2 or {}).jpart or 0), (tonumber(op2) and 0) or ((op2 or {}).kpart or 0) )
return x - y * p.qmath.floor(x / y)
end,
__tostring = function (this)
local body = ''
if this.real ~= 0 then body = tostring(this.real) end
if this.imag ~= 0 then
if body ~= '' and this.imag > 0 then body = body .. '+' end
if this.imag == -1 then body = body .. '-' end
if math.abs(this.imag) ~= 1 then body = body .. tostring(this.imag) end
body = body .. 'i'
end
if this.jpart ~= 0 then
if body ~= '' and this.jpart > 0 then body = body .. '+' end
if this.jpart == -1 then body = body .. '-' end
if math.abs(this.jpart) ~= 1 then body = body .. tostring(this.jpart) end
body = body .. 'j'
end
if this.kpart ~= 0 then
if body ~= '' and this.kpart > 0 then body = body .. '+' end
if this.kpart == -1 then body = body .. '-' end
if math.abs(this.kpart) ~= 1 then body = body .. tostring(this.kpart) end
body = body .. 'k'
end
if sollib._isNaN(this.real) or sollib._isNaN(this.imag) or sollib._isNaN(this.jpart) or sollib._isNaN(this.kpart) then body = 'nan' end
if body == '' then body = '0' end
return body
end,
__unm = function (this)
return p.qmath.getQuaternionNumber(-this.real, -this.imag, -this.jpart, -this.kpart)
end,
__eq = function (op1, op2)
local diff_real = math.abs( (tonumber(op1) or (op1 or {}).real) - (tonumber(op2) or (op2 or {}).real) )
local diff_imag1 = math.abs( ( (tonumber(op1) and 0) or (op1 or {}).imag) - ( (tonumber(op2) and 0) or (op2 or {}).imag) )
local diff_jpart = math.abs( ( (tonumber(op1) and 0) or ((op1 or {}).jpart or 0)) - ( (tonumber(op2) and 0) or ((op2 or {}).jpart or 0)) )
local diff_kpart = math.abs( ( (tonumber(op1) and 0) or ((op1 or {}).kpart or 0)) - ( (tonumber(op2) and 0) or ((op2 or {}).kpart or 0)) )
return diff_real < 1e-12 and diff_imag1 < 1e-12 and diff_jpart < 1e-12 and diff_kpart < 1e-12
end,
},
ele=function(id)
local _zero = p.qmath.getQuaternionNumber(0, 0, 0, 0)
local eles = (p.qmath.elements or {})
local id_msg = tonumber(tostring(id)) or 0
return eles[id_msg+1]or _zero
end,
readComplexNumber = function(z)
if type(z) == type({}) then --if already be complex number, don't run string find.
if z.numberType == "complex" then
return p.qmath.getQuaternionNumber(z.real, z.imag, 0, 0)
elseif z.numberType == "quaternion" then
return z
end
elseif type(z) == type(0) then
return p.qmath.getQuaternionNumber(z, 0, 0, 0)
elseif type(z) == type(true) then
return p.qmath.getQuaternionNumber(z and 1 or 0, 0, 0, 0)
end
return p.qmath.getQuaternionNumber(tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0,
((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).imag or 0),
((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).jpart or 0),
((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).kpart or 0))
end,
readPart = function(z)
if type(z) == type({}) and (z.numberType == "complex" or z.numberType == "quaternion") then --if already be complex number, don't run string find.
if z.numberType == "quaternion"then
return z.real, z.imag, z.jpart, z.kpart
else
return z.real, z.imag, 0, 0
end
elseif type(z) == type(0) then
return z, 0, 0, 0
elseif type(z) == type(true) then
return z and 1 or 0, 0, 0, 0
end
return tonumber(z) or (z or {}).real or tonumber(tostring(z)) or 0,
((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).imag or 0),
((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).jpart or 0),
((tonumber(z) or tonumber(tostring(z))) and 0) or ((z or {}).kpart or 0)
end,
getQuaternionNumber = function(real, imag, jpart, kpart)
local QuaternionNumber = {}
setmetatable(QuaternionNumber,p.qmath.QuaternionNumberMeta)
function QuaternionNumber:update()
self.argument = 0
self.length = math.sqrt( self.real * self.real + self.imag * self.imag
+ self.jpart * self.jpart + self.kpart * self.kpart )
end
function QuaternionNumber:clean()
if math.abs(self.real) <= 1e-12 then self.real = 0 end
if math.abs(self.imag) <= 1e-12 then self.imag = 0 end
if math.abs(self.jpart) <= 1e-12 then self.jpart = 0 end
if math.abs(self.kpart) <= 1e-12 then self.kpart = 0 end
if math.abs(self.real - math.floor(self.real)) <= 1e-12 then self.real = math.floor(self.real) end
if math.abs(self.imag - math.floor(self.imag)) <= 1e-12 then self.imag = math.floor(self.imag) end
if math.abs(self.jpart - math.floor(self.jpart)) <= 1e-12 then self.jpart = math.floor(self.jpart) end
if math.abs(self.kpart - math.floor(self.kpart)) <= 1e-12 then self.kpart = math.floor(self.kpart) end
return self
end
QuaternionNumber.real, QuaternionNumber.imag, QuaternionNumber.jpart, QuaternionNumber.kpart = real, imag, jpart, kpart
QuaternionNumber.numberType = "quaternion"
return QuaternionNumber
end,
toQuaternionNumber = function(num_str)
local real, imag, jpart, kpart
if num_str == nil then return nil end
if type(num_str) == type({}) then --if already be complex number, don't run string find.
if num_str.numberType == "quaternion" then
return num_str
elseif num_str.numberType == "complex" then
return p.qmath.getQuaternionNumber(num_str.real, num_str.imag, 0, 0)
end
elseif type(num_str) == type(1) then
return p.qmath.getQuaternionNumber(num_str, 0, 0, 0)
elseif type(num_str) == type(true) then
return p.qmath.getQuaternionNumber(num_str and 1 or 0, 0, 0, 0)
end
if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then
real, imag, jpart, kpart = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or (num_str.imag or 0), (tonumber(num_str) and 0) or (num_str.jpart or 0), (tonumber(num_str) and 0) or (num_str.kpart or 0)
else
real, imag, jpart, kpart = p.qmath.toQuaternionNumberPart(tostring(num_str))
end
if real == nil or imag == nil or jpart == nil or kpart == nil then return nil end
return p.qmath.getQuaternionNumber(real, imag, jpart, kpart)
end,
toQuaternionNumberPart = function(num_str)
if type(num_str) == type(function()end) then return end
if type(num_str) == type(true) then if num_str then return 1,0,0,0 else return 0,0,0,0 end end
local body = ''
local real, imag, jpart, kpart = 0, 0, 0, 0
local split_str = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(
tostring(num_str) or '',
'%s+',''),'%++([%d%.])',',+%1'),'%++([ijk])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijk])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijk])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijk])',',/1%1'),',')
local first = true
local continue = false
for k,v in pairs(split_str) do
continue = false
local val = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.text.trim(v),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ijk])','+1%1')
if mw.ustring.find(val,"%/") or mw.ustring.find(val,"%*") then return end
if val == nil or val == '' then if first == true then first = false continue = true else return end end
if not continue then
local num_text = mw.ustring.match(val,"[%+%-][%d%.]+[ijk]?")
if num_text ~= val then return end
local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
if num_part == nil then return end
if mw.ustring.find(num_text,"i") then
imag = imag + num_part
elseif mw.ustring.find(num_text,"j") then
jpart = jpart + num_part
elseif mw.ustring.find(num_text,"k") then
kpart = kpart + num_part
else
real = real + num_part
end
end
end
return real, imag, jpart, kpart
end,
halfNumberParts = function(num)
local real, imag, jpart, kpart = p.qmath.readPart(num)
return {p.cmath.getComplexNumber(real, imag), p.cmath.getComplexNumber(jpart, kpart)}
end,
init = function()
p.qmath.pi = p.qmath.getQuaternionNumber(math.pi, 0, 0, 0)
p.qmath["π"] = p.qmath.getQuaternionNumber(math.pi, 0, 0, 0)
p.qmath["°"] = p.qmath.getQuaternionNumber(math.pi/180, 0, 0, 0)
p.qmath.e = p.qmath.getQuaternionNumber(math.exp(1), 0, 0, 0)
p.qmath.nan = p.qmath.getQuaternionNumber(tonumber("nan"), tonumber("nan"), tonumber("nan"), tonumber("nan"))
p.qmath.infi = p.qmath.getQuaternionNumber(0, tonumber("inf"), 0, 0)
p.qmath.infj = p.qmath.getQuaternionNumber(0, 0, tonumber("inf"), 0)
p.qmath.infk = p.qmath.getQuaternionNumber(0, 0, 0, tonumber("inf"))
p.qmath.zero = p.qmath.getQuaternionNumber(0, 0, 0, 0)
p.qmath.one = p.qmath.getQuaternionNumber(1, 0, 0, 0)
p.qmath[-1] = p.qmath.getQuaternionNumber(-1, 0, 0, 0)
p.qmath.i = p.qmath.getQuaternionNumber(0, 1, 0, 0)
p.qmath.j = p.qmath.getQuaternionNumber(0, 0, 1, 0)
p.qmath.k = p.qmath.getQuaternionNumber(0, 0, 0, 1)
p.qmath[0],p.qmath[1] = p.qmath.zero,p.qmath.one
p.qmath.numberType = sollib._numberType
p.qmath.constructor = p.qmath.toQuaternionNumber
p.qmath.elements = {
p.qmath.getQuaternionNumber(1, 0, 0, 0),
p.qmath.getQuaternionNumber(0, 1, 0, 0),
p.qmath.getQuaternionNumber(0, 0, 1, 0),
p.qmath.getQuaternionNumber(0, 0, 0, 1),
}
return p.qmath
end
}
p._efloor=function(z)
local real, imag = tonumber(z) or z[eReal], (tonumber(z) and 0) or z[eImag]
return p._eisenstein_integer(math.floor(real), math.floor(imag))
end
p._eisenstein_meta={
__add = function (op1, op2)
local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
if not real2 or not imag2 then
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3
end
return p._eisenstein_integer(real1 + real2, imag1 + imag2)
end,
__sub = function (op1, op2)
local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
if not real2 or not imag2 then
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3
end
return p._eisenstein_integer(real1 - real2, imag1 - imag2)
end,
__mul = function (op1, op2)
local a, c = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
local b, d = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
if not c or not d then
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
c, d = real3+sqrt33*imag3, 2*sqrt33*imag3
end
return p._eisenstein_integer(a * c - b * d, b * c + a * d - b * d)
end,
__div = function (op1, op2)
local a, c = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
local b, d = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
if not c or not d then
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
c, d = real3+sqrt33*imag3, 2*sqrt33*imag3
end
if c==d or c*c == (c*d*d)/(c-d) then
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local pn, q = p.cmath.getComplexNumber(a-b/2, sqrt32 * b), p.cmath.getComplexNumber(c-d/2, sqrt32 * d)
local p_q = pn/q
local real1, imag1 = tonumber(p_q) or p_q.real, (tonumber(p_q) and 0) or p_q.imag
return p._eisenstein_integer(real1+sqrt33*imag1, 2*sqrt33*imag1)
end
local op1_d, op2_d = c*d/(c-d), c*c + (c*d*d)/(c-d)
return p._eisenstein_integer((a * c + b * op1_d) / op2_d, (b * c - a * op1_d + b * op1_d) / op2_d)
end,
__mod = function (op1, op2)
local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
if not real2 or not imag2 then
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3
end
local x = p._eisenstein_integer(real1, imag1)
local y = p._eisenstein_integer(real2, imag2)
return x - y * p._efloor(x / y)
end,
__tostring = function (this)
local body = ''
if this[eReal] ~= 0 then body = tostring(this[eReal]) end
if this[eImag] ~= 0 then
if body ~= '' and this[eImag] > 0 then body = body .. '+' end
if this[eImag] == -1 then body = body .. '-' end
if math.abs(this[eImag]) ~= 1 then body = body .. tostring(this[eImag]) end
body = body .. eImag
end
if body == '' then body = '0' end
return body
end,
__unm = function (this)
return p._eisenstein_integer(-this[eReal], -this[eImag])
end,
__eq = function (op1, op2)
local real1, real2 = tonumber(op1) or op1[eReal], tonumber(op2) or op2[eReal]
local imag1, imag2 = (tonumber(op1) and 0) or op1[eImag], (tonumber(op2) and 0) or op2[eImag]
if not real2 or not imag2 then
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local real3, imag3 = tonumber(op2) or op2.real, (tonumber(op2) and 0) or op2.imag
real2, imag2 = real3+sqrt33*imag3, 2*sqrt33*imag3
end
local diff_real = math.abs( real1 - real2 )
local diff_imag1 = math.abs( imag1 - imag2 )
return diff_real < 1e-12 and diff_imag1 < 1e-12
end,
}
function p._eisenstein_integer(int_a, int_b)
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
local eisenstein = p.cmath.getComplexNumber(int_a-int_b/2, sqrt32 * int_b)
eisenstein[eReal], eisenstein[eImag] = int_a,int_b
setmetatable(eisenstein,p._eisenstein_meta)
eisenstein.isEisensteinNumber = true
return eisenstein
end
function p._toEisensteinNumber(num_str)
local real, imag
if num_str == nil then return nil end
if ( type(num_str)==type(0) or ( (type(num_str)==type({"table"})) and type(num_str.real)==type(0) ) ) then
real, imag = tonumber(num_str) or num_str.real, (tonumber(num_str) and 0) or num_str.imag
else
real, imag = p._toEisensteinNumberPart(num_str)
end
if real == nil or imag == nil then return nil end
return p._eisenstein_integer(real, imag)
end
function p._toEisensteinNumberPart(num_str)
if type(num_str) == type(function()end) then return end
local body = ''
local real, imag, omg = 0, 0, 0
local split_str = mw.text.split(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(
tostring(num_str) or '',
'%s+',''),'%++([%d%.])',',+%1'),'%++([ijω])',',+1%1'),'%-+([%d%.])',',-%1'),'%-+([ijω])',',-1%1'),'%*+([%d%.])',',*%1'),'%*+([ijω])',',*1%1'),'%/+([%d%.])',',/%1'),'%/+([ijω])',',/1%1'),',')
local first = true
local continue = false
for k,v in pairs(split_str) do
continue = false
local val = mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.ustring.gsub(mw.text.trim(v),'[ijω]+','i'),'^(%.)','0%1'),'^([%d%.])','+%1'),'([%+%-])([%d%.])','%1\48%2'),'^([ijω])','+1%1')
if mw.ustring.find(val,"%/") or mw.ustring.find(val,"%*") then return end
if val == nil or val == '' then if first == true then first = false continue = true else return end end
if not continue then
local num_text = mw.ustring.match(val,"[%+%-][%d%.]+i?")
if num_text ~= val then return end
local num_part = tonumber(mw.ustring.match(num_text,"[%+%-][%d%.]+"))
if num_part == nil then return end
if mw.ustring.find(num_text,"i") then
imag = imag + num_part
elseif mw.ustring.find(num_text,"ω") then
omg = omg + num_part
else
real = real + num_part
end
end
end
local sqrt32, sqrt33 = math.sqrt(3)/2, 1/math.sqrt(3)
return real+sqrt33*imag, 2*sqrt33*imag+omg
end
return p