65.9K
CodeProject 正在变化。 阅读更多。
Home

VB.NET 中的复数数学解析器和求值器

starIconstarIconstarIconstarIconstarIcon

5.00/5 (15投票s)

2022年3月25日

MIT

3分钟阅读

viewsIcon

40165

downloadIcon

2266

简化/求值实数/复数数学表达式

引言

在很多情况下,可能存在一个包含数学表达式的 string,例如 "1+2*5" 或 "(3+i)(3-i)",并且需要进行数学运算并计算结果。 此外,对于像 "0.5*x+4" 这样的公式,我们可能需要计算 x 的几个不同值的结果。 在这些情况下,此处提供的复数解析器可能会有所帮助。

这里的类是我所有免费且可下载的 CAS 计算器 http://xrjunque.nom.es 的一小部分(但经过改进)。 其中一个目标是这些类不依赖于其他“外部”类,就像 CAS 计算器中发生的那样。

五个类

  • Global10 类包含全局值,如小数位数、虚数单位(ij)或 CultureInfo
  • Msg10 类仅包含一些消息以处理可能的错误。
  • Rational 类在运算中提供了更高的精度。
  • Complex 类执行复数数学运算。
  • parseComplex 类负责将输入字符串分成标记,并相应地调用 ComplexMsg10 类。 Complex 类利用 Rational 类作为其 Real 和 Imaginary 成员。 “标记化”工作由 Regex 模式完成。

令牌

标记组是

mode <mode>
numbers <num>
operators <op>
logical operators <lop>
functions <fn>
constants <cnt>
variables <var>
any other character <any>
besides end of tokens <end> formed by an escape character Chr(27).

该模式看起来像

(?i)(?<mode>(&dec(?<dec>\d{1,2})|&(rad|deg|grad|[hobdij])))(?-i)
(?<numop>(?<num>((\d{1,3}((\,\d{3})+(?!\d))(\.[0-9]+)?)|
            [\d]{1}[\.\dA-Fa-f]*)([eE](\s*)[-+]?[0-9]+)?)|
(?<op>[-+*/\^]))|\(|\)|
(?i)(?<fn>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)(?![a-zA-Z_]+)|
(?<lop>\<\<|\>\>|nand|mod|and|nor|xor|not|or|%|!)(?![a-zA-Z_]+)|
(?<cnt>e|(?i)pi)(?![a-zA-Z_]+)|
(?<vars>[_a-zA-Z]\w*)+|(?<end>\e)+|
(?<any>[^\s←\,\.])+|(?<any>\,|\.)+
</dec>

数字的模式,取决于 Globalization.CultureInfo 设置,可能会交换点(NumberFormat.NumberDecimalSeparator)和逗号(NumberFormat.NumberGroupSeparator)。

模式使得可以输入十六进制、十进制、八进制或二进制基数的数字; 以及设置小数位数和虚数单位。

Using the Code

有两种可能的实例化方式

    Dim eP As New ParseComplex
    eP.CultureInfo = New Globalization.CultureInfo("fr-FR")
    ...
    Dim eP As New ParseComplex(New Globalization.CultureInfo("es-AR"))
    ...

默认情况下,CultureInfo 设置为 "en-US"。

求值是通过调用两个 Evaluate() 方法之一来完成的。

第一种方法

    '// argument is a string:
    Dim cplx As Complex = eP.Evaluate("(3+5*i)*(3-i*5)")
    

第一个方法带有变量,设置在 Dictionay(Of String, Complex)

    eP.vars.Add("x", Complex.one)
    eP.vars.Add("y", New Complex(-1, 2))
    '// argument is a string:
    Dim cplx As Complex = eP.Evaluate("(3+x*i)*(y-i*5)")

解析完 string 后,可以调用重载的第二个方法

    '// change "x" value (change any variable value):
     eP.vars.Item("x") = New Complex(3)
    '// argument is the Dictionary(Of String, Complex):
    Dim cplx As Complex = eP.Evaluate(eP.vars)
   

变量名称以字母或下划线 (_) 开头,可以包含字母、数字或下划线,并且可以是任意长度。

当然,如果您不需要解析器,您可以直接调用 Complex 类。

默认的数字基数为十进制。 要更改为另一个基数,请写入 &h(十六进制)、&o(八进制)或 &b(二进制)。 附加 &d 将恢复为十进制基数。

以类似的方式,&deg&grad 将接受以度或梯度为单位的角度。 要恢复为默认的弧度,请输入 &rad

要将默认虚数单位 i 更改为 j,请写入 &j,要返回默认字符,请写入 &i

例如,输入 &culture it-IT 会将当前的 CultureInfo 更改为 it-IT。 因此,输入和输出将以 mented 文化进行。

可能的修饰符的示例如下

  Dim cplx As Complex = eP.Evaluate("&culture fr-FR &dec2 &h 0f + &j &d 0,2+0,3*j"
  Console.WriteLine(cplx.tostring) ' will show 15,2+j*0,3

输出

您可以调用 Complex.ToString()ToStringComplex( numDecimals As Int32, sImg As String, cultureInfo As Globalization.CultureInfo) As String

   cplx.ToStringComplex(4, eP.Imaginary, eP.CultureInfo)

详细版本

如果找到单词 detail,代码将输出操作步骤。 例如

    Dim cP As New ParseComplex
    Dim cplx As Complex = cP.Evaluate("detail (2+i*3)*(1+i)")
    Console.WriteLine(cP.GetDetail)
    ' Will output:
    ' [ (2+i*3)*(1+i) ]
    ' [2*1 - 3*1 + i*(2*1+3*1) ]
    ' [-1+i*5]

基本原理

解析方法是递归下降解析: 通过递归下降解析表达式

求值方法 E 为任何加法或减法调用 T,但 T 首先为任何乘法或减法调用 F,并且 F 首先为任何可能的幂运算调用 P。 P 首先调用 v 以获取下一个标记。 如果存在 "(" 标记,则 v 递归调用 T

    E --> T {( "+" | "-" ) T}
    T --> F {( "*" | "/" ) F}
    F --> P ["^" F]
    P --> v | "(" E ")" | "-" T

分步演示

此处提出的算法将 T F 包裹在一个方法中。 此外,方法 v 运行逻辑运算符,“%' 和 mod 任何可能的函数,如 cos()csc() 等。

在撰写本文时,我发现了一些小问题。 如果您发现任何其他错误,请告诉我。

历史

  • 2022 年 3 月 25 日:初始版本
© . All rights reserved.