跳转到内容

模块:Complex Number

本页使用了标题或全文手工转换
被永久保护的模块
维基百科,自由的百科全书
文档图示 模块文档[查看] [编辑] [历史] [清除缓存]

本模块为Lua定义了一套复数(如虚数四元数)运算的系统,可提供其他模块调用使用,而若要直接在模板或条目中使用可通过Module:Complex Number/Calculate‎或{{复变运算}}来完成。

关于本模块创建动机详见Module:TemplateParameters#设计缘由(亦可参考Template_talk:Root)。

模块内容

本模块有4套数学数据结构的定义以及对应的数学运算库:

.cmath
复数的数学数据结构及运算的系统
.qmath
四元数的数学数据结构及运算的系统
.math
实数运算系统的扩展
.bmath
布尔代数的数学数据结构及运算的系统

使用方法

  1. 初始化数学库
    • local 自定义函数库名称 = require("Module:Complex Number").函数库名称.init()
      例如:local cmath = require("Module:Complex Number").cmath.init()
  2. 初始化指定数学结构的数字
    • local 变量名称 = 自定义函数库名称.constructor("描述数字的字符串")
      例如:local num1 = cmath.constructor("2+3i")
  3. 执行运算
    例如:
    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原生支持 不存在 输出
cis
cis(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中的运算符。

定义数学数据结构

参阅Example的第85行

数学数据结构需要定义成一个table,并以table来定义或表达所需要的数字。即使数字只有单一对象,也许使用table因为这样才能通过实现Metatables来完成Module:Complex Number系列函数库所需的相关功能。

实现metatable

参阅Example的第47行

需定义Metatables的 __add(加法)、 __sub(减法)、 __mul(乘法)、 __div(除法)、 __mod(取余数)、 __unm(相反数)、 __eq(相等判断)、 __tostring(以字符串表达本对象)

定义数学数据结构的构造函数

参阅Example的第85行第95行

由于数学数据结构需要定义为table因此需要有构造函数来赋予该结构初值。构造函数需要完成以下步骤:

定义数学库的初始化函数

参阅Example的第101行

数学库必须是一个独立对象,所有的函数皆需定义在数学函数库对象下(包括数学数据结构的构造函数)。初始化数学库的函数名称必为init,当中需要定义以下内容:

完成数学库的定义

视情况定义列于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
二元复数英语Applications of dual quaternions to 2D geometry函数库
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
预先套用凯莱-迪克森结构十六元数后的函数库(可作为三十二元数使用)

相关页面

--'
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