在许多情况下,可能会遇到包含数学表达式的字符串,例如 "1+2*5"、"(3+i)(3-i)" 或 "(z^2*w+4z^3w-w^2-4z*w^2)/(w+4z*w)",并且需要进行计算以得到结果。也许需要根据不同的变量值来计算结果,而结果可能是另一个多项式。在这些情况下,这里介绍的多项式解析器可能会有所帮助。
这里的类是完全免费且可下载的计算机代数系统(CAS)计算器的一小部分,但有所改进。其中一个目标是这些类不依赖于其他“外部”类,就像在CAS计算器中发生的那样。
类 'Msg10' 只包含一些用于处理可能的错误的消息。类 'G10' 包含像正则表达式模式这样的全局成员。类 'Rational' 提供了更精确的操作。类 'Complex' 执行复数数学运算。类 'Polynomial' 操作多项式。类 'Roots' 寻找多项式的根和因子。类 'parsePolynomial' 负责将输入字符串分割成标记,并相应地调用 Roots、Polynomial 或 Msg10 类。Roots 依赖于 Polynomial 类,而 Polynomial 又依赖于 Complex,Complex 依赖于 Rational。'标记化'工作由正则表达式模式完成。
标记组包括:
正则表达式模式如下所示:
(?s)(?((\d{1,3}((\,\d{3})+(?!\d))(\.[0-9]+)?)|[\.\d]+)([eE](\s*)[-+]?[0-9]+)?)(?-s)|
(?[-+*/\^])|
(?nand|mod|and|nor|xor|not|or|%|!)(?![a-zA-Z_]+)|
(?i)(?logtwo|logten|acosh|acoth|acsch|asech|asinh|atanh|floor|round|norm|conj|
coth|csch|sech|acos|acot|acsc|asec|asin|atan|cosh|sign|sinh|sqrt|tanh|abs|cos|cot|
csc|exp|log|sec|sin|sqr|tan|ln|re|im(?-i))(?![a-zA-Z_]+)|
(?i)(?roots|(?factorize|factors|factor)(?-i))(?![a-zA-Z_]+)|
(?e|(?i)pi(?-i))(?![a-zA-Z_]+)|
\(|\)|
(?\w)+|(?\e)+|
(?[^\s←\,\.])+|(?\,|\.)+
函数 'roots' 返回包含输入多项式根的复数数组。函数 'factor' 返回输入多项式的因子数组。输入也可以是形式 (分子多项式)/(分母多项式)。
有两种实例化方式:
Dim eP As New ParsePolynomial
eP.CultureInfo = New Globalization.CultureInfo("fr-FR")
...
Dim eP As New ParsePolynomial(New Globalization.CultureInfo("es-AR"))
...
默认情况下,CultureInfo 设置为 "en-US"。
通过调用两个 'Evaluate()' 方法之一进行评估。第一种方法:
Dim poly As Polynomial = eP.Evaluate("(x-1)*(x+1)")
...
第一种方法带有变量,设置在 Dictionary(Of String, Polynomial) 中:
Dim eP As New ParsePolynomial
eP.vars.Add("x", New Polynomial(Complex.one))
Dim polyA As New Polynomial("a", 2)
' // 'a' 变量,2 指数 (a^2)
polyA += New Polynomial(-1.0)
' // a ^ 2 - 1
eP.vars.Add("y", polyA)
' // 参数是字符串:
Dim cplx As Complex = eP.Evaluate("x*(y-i*5)")
...
一旦字符串被解析,可以调用重载的第二种方法:
' // 更改 "x" 值(更改任何变量值):
eP.vars.Item("x") = New Polynomial(3)
' // 参数是 Dictionary(Of String, Polynomial):
Dim polyC As Polynomial = eP.Evaluate(eP.vars)
...
变量名以字母或下划线 (_) 开头,可以包含字母、数字或下划线,并且可以是任何长度。当然,如果不需要解析器,可以直接调用 Polynomial 类。
输出可以只是一个 Polynomial,一个 Complex() 数组,或者一个 Polynomial() 数组:
Dim t1 As Int64 = Now.Ticks
Dim p As Polynomial = eP.Evaluate(TBExpression.Text)
Dim t2 As New TimeSpan(Now.Ticks - t1)
If eP.vPoly.Length Then
' Response is an array of Polynomials ?
Dim s1 As String = ""
For i As Int32 = 0 To eP.vPoly.Length - 1
If eP.vPoly(i) IsNot Nothing Then
s1 += eP.vPoly(i).ToStringPolynomial(eP.Decimals, eP.Imaginary, eP.CultureInfo) + "
"
Else
s1 +=
"
-------------------"
End If
Next
NavigateToString(s1)
' Show in Webbrowser1
ElseIf eP.vRoots.Length Then
' Response is an array of Complex ?
Dim s1 As String = ""
For i As Int32 = 0 To eP.vRoots.Length - 1
s1 += eP.vRoots(i).ToStringComplex(eP.Decimals, eP.Imaginary, eP.CultureInfo) + "
"
Next
NavigateToString(s1)
' Show in Webbrowser1
Else
' Response is a Polynomial
NavigateToString(p.ToStringPolynomial(eP.Decimals, eP.Imaginary, eP.CultureInfo))
End If
当调用 eP.Evaluate("factor(numerator)/(denominator)") 时,返回将在 eP.vPoly() 中,并且一个 null 元素将因子与分子和分母分开。
可以调用 Polynomial.ToString() 或 ToStringPolynomial(Optional numDecimals As Int32 = 15, Optional sImg As String = "i", Optional cultureInfo As Globalization.CultureInfo = Nothing) As String:
...
polyC.ToStringPolynomial(4, eP.Imaginary, eP.CultureInfo)
...
详细版本将通过在单词 'detail' 前面添加操作步骤来显示。
这里介绍的算法将 T 和 F 包含在单个方法中。此外,方法 v 操作任何可能的函数,如 cos()、csc()、mod 等。