发一个自创的表达式计算器(VB开源) (申精)
vb吧
全部回复
仅看楼主
level 6
XiaoJSoft 楼主
1楼防抽
2011年01月22日 13点01分 1
level 6
XiaoJSoft 楼主
先发连接:
(1) 执行文件:
http://excalc.googlecode.com/files/ecc-1.06.7660_zh-CN.zip
(2) 代码在这里:
http://excalc.googlecode.com/files/ecc-1.06.7660.source.zip
一会发截图和算法描述。
本人初四,有些地方还需各位给建议啊[抛媚眼]。

2011年01月22日 13点01分 2
level 6
XiaoJSoft 楼主
首先是主界面截图:
这个程序可以进行复杂的计算,内嵌丰富的函数可供使用。通过编辑 Constants.ini 还可以实现自定义函数。
这个程序还支持小数点精确、log底数设置、字体设置、函数图像等功能。
还可以绘制简单的函数图像哦,复杂也可以哦,只要符合语法就可以了。

2011年01月22日 13点01分 3
level 7
貌似不错,有空看看
2011年01月22日 13点01分 4
level 13
哈哈~~~蛮不错的
2011年01月22日 13点01分 5
level 6
XiaoJSoft 楼主
说一下我的算法吧。
以前看过各位高人们写的如何计算表达式,而且在网上搜过一阵子,发现几乎没有符合我心意的表达式计算算法。于是便想要自己创造一个(现在想起来,如果要让我创造这么个东西,我得自杀)。
首先是如何实现算数优先级,由于对堆栈理解不透彻,索性就不用它,我突然想到了,我们人是怎么思考表达式的呢 -> 分割吗。
举个例子吧:1+2*3,我们人会先把它分解成 1 和 2*3 分别运算最后求值。
那么表达式计算也可以符合这个过程,表达式有+、-、*、/、^、%等,这里我是这么想的:
(1) 首先要把最低级的先分割,譬如说1+2*3这个算式,我们要把它分割成1和2*3而不是1+2和3。
+最优先分割,-其次,然后分*,最后分/,接下来处理百分号和其他自变量、常量(如pi)等。
(2) 分割完后,把它重新递归到表达式计算过程中,让它进一步分割直到完全求值为止(一定会有一个递归终点,那就是当算式中只有1个运算符的时候)。
(3) 特殊情况
A. 分割时也要考虑到调号。如1-2-3-4,我们不能把它直接分解为1和2-3-4递归了之,而是要把2-3-4调号,为2+3+4,即我们所认为的1-(2+3+4)这种情况,这样才能运算正确),这个情况适用于减法和除法。
B. 至少不能把相连的两个运算符其中之一给分割了吧。如2*-4,如果我们先分割减号,那么岂不是要成为这种情况:2*和4,这是什么?递归后程序把2*认为是2*0等于0,运算了之,最终岂不是等于0了!所以我们在程序中需要考虑到这种情况,如果低级运算符前面有高级运算符,那么无视低级运算符。
接下来是括号处理,这里闹了我很久,最终发现了解决方法(只是发现在统计字符串时,如果恰好到括号所对应的扩回,从扩回这一点到括号这一点(包括这两点)其中的括号字符和扩回字符数量一致。
于是我们设有这样的变量:L1、L2,用于统计个数,假设我们需要的算式是:2*((3+4*(3*5))-2),我们要分解第二层括号。
第二层括号的起始位置是 4,循环从这里开始,一直到 17(算式字符串长度) 为止,每当遇到“(”时,自动把 L1+1,遇到“)”时把 L2+1,我们发现当到 14 时,L1=L2,则这里所对应的符号就应该是第二层括号的扩回了,然后用 mid 函数取括号内的内容,取括号前面的内容的一部分用于函数处理,把括号内部分递归到计算过程中运算,如果有函数,就将返回值处理一下,用最终计算结果替换掉括号及其里面的内容,如果括号后面直接又是一个括号(如sin(1+2)(3*4)),就在括号后面自动补上一个*,如果括号内是负数,就把负数变为正数,并将其后面再加上K符号(其实这里是为了处理这样的一种类似情况并将其区分:(-4)*3和-4*3,明显可以看出这两种返回值是不同的,至于K可以在后期分割符号时,因为不是数字不能直接参与运算,被程序再次递归运算,这次直接返回值进入计算变量,就不会有字符串处理的过程,也就没有了这种情况,至少我是这么想的,不知道你是不是有更好的方法)。
自变量/常量支持,这个相当简单,如果分割到最后仍然有不能识别的部分,则让程序去上常量库中找找,看有没有,如果有就返回运算,如果没有,终止这一级别的运算过程,调用这一运算过程的过程也将终止,运算失败。
然后是给懒人们留个门,怎么说呢,就是在常量前面直接加上数字啦,如4pi,我们一般写成4*pi,程序是不会识别4pi的,怎么办呢,还记得常量是如何被判断的吧(上面呢),我们在读取常量库时先看看常量前面有没有数字就可以了。
我很懒,源代码中没有注释,接下来我会把所有代码都加上注释给大家。

2011年01月22日 13点01分 6
level 6
XiaoJSoft 楼主
对了,整个算法中用到了一个超大数计算器的代码(为了给阶乘留点余地,也为了给自己减轻点负担,用了别人的代码修改得到),在此声明[吐舌],涉及到的过程有:
GUI\mdlCalculator.bas:
BigAdd
BigSubtract
BigProduct
BigDivide
xBigAdd
xBigSubtract
xBigProduct
xBigDivide

2011年01月22日 13点01分 7
level 6
XiaoJSoft 楼主
今天就发到这里吧,累了。
2011年01月22日 15点01分 21
不核心的代码还有多长??[88]格式你怎么弄出来的?
2012年10月21日 15点10分
level 1
话说,你对单目运算符理解有点错误,正负(+,-)的优先级其实比双目的乘除(*,/)要高的。
支持一下!
2011年01月22日 15点01分 22
level 6
XiaoJSoft 楼主
回复:22楼
谢谢你纠正了我的一些错误。
程序中这个是要最先分割开的。
2011年01月22日 15点01分 23
level 6
XiaoJSoft 楼主
而且应该乘号和除号的分割顺序我还表述错了,应该是先除后×
2011年01月22日 15点01分 24
level 1
其实你可以参考 C 语言的运算符优先级和结合方向来编写,那样对语言的认识也可以加深,你的那个括号连乘可以省略乘号比较有意思,虽说这是书写中的正常形式[狂汗]
2011年01月22日 15点01分 25
level 6
XiaoJSoft 楼主
                    Exit Function
                End If
                strPWR1 = strPWRReturn
            End If
            If IsNumeric(strPWR2) = False Then
                strPWRReturn = CalculateString(strPWR2, ensPWRSub, lpLevel + 1)
                If ensPWRSub <> lpSucceed Then
                    lpReturn = ensPWRSub
                    Exit Function
                End If
                strPWR2 = strPWRReturn
            End If
            strCallback = Trim(Str(GetRoot(Val(strPWR1), Val(strPWR2))))
            GoTo EndExtract
        End If
        ' 计算括号中的内容
        strCallback = CalculateString(strReplace, enReturnSub, lpLevel + 1)
        If enReturnSub <> lpSucceed Then
            lpReturn = enReturnSub
            Exit Function
        End If
        ' 如果有函数的话,就按照函数定义去对计算完的内容处理。
        Select Case Trim(UCase(strSpecial3))
            Case Trim(UCase("ihcos"))
                lpX = Val(strCallback)
                lpX = Log(lpX + Sqr(lpX * lpX - 1))
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))

2011年01月22日 16点01分 26
level 6
XiaoJSoft 楼主
                GoTo EndExtract
            Case Trim(UCase("ihcsc"))
                lpX = Val(strCallback)
                lpX = Log((Sgn(lpX) * Sqr(lpX * lpX + 1) + 1) / lpX)
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("ihcot"))
                lpX = Val(strCallback)
                lpX = Log((lpX + 1) / (lpX - 1)) / 2
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("ihsin"))
                lpX = Val(strCallback)
                lpX = Log(lpX + Sqr(lpX * lpX + 1))
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("ihsec"))

2011年01月22日 16点01分 27
level 6
XiaoJSoft 楼主
                lpX = Val(strCallback)
                lpX = Log((Sqr(-lpX * lpX + 1) + 1) / lpX)
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("ihtan"))
                lpX = Val(strCallback)
                lpX = Log((1 + lpX) / (1 - lpX)) / 2
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
        End Select
        Select Case Trim(UCase(strSpecial2))
            Case Trim(UCase("hsin"))
                If bpRadianWay = True Then
                    lpX = Val(strCallback)
                Else
                    lpX = ConvertToRadian(Val(strCallback))
                End If
                lpX = (Exp(lpX) - Exp(-lpX)) / 2
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("hcos"))

2011年01月22日 16点01分 28
level 6
XiaoJSoft 楼主
                If bpRadianWay = True Then
                    lpX = Val(strCallback)
                Else
                    lpX = ConvertToRadian(Val(strCallback))
                End If
                lpX = (Exp(lpX) + Exp(-lpX)) / 2
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("hcsc"))
                If bpRadianWay = True Then
                    lpX = Val(strCallback)
                Else
                    lpX = ConvertToRadian(Val(strCallback))
                End If
                lpX = 2 / (Exp(lpX) - Exp(-lpX))
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("hcot"))
                If bpRadianWay = True Then
                    lpX = Val(strCallback)
                Else
                    lpX = ConvertToRadian(Val(strCallback))
                End If
                lpX = (Exp(lpX) + Exp(-lpX)) / (Exp(lpX) - Exp(-lpX))
                strCallback = Trim(Str(lpX))
                GoTo EndExtract

2011年01月22日 16点01分 29
level 6
XiaoJSoft 楼主
                lpX = Atn(lpX / Sqr(-lpX * lpX + 1))
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("itan"))
                lpX = Val(strCallback)
                lpX = Atn(lpX)
                If bpRadianWay = False Then
                    lpX = ConvertToDegree(lpX)
                End If
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
        End Select
        Select Case Trim(UCase(strSpecial))
            Case Trim(UCase("sqr"))
                If Val(strCallback) < 0 Then
                    lpReturn = lpRunError
                    Exit Function
                End If
                strCallback = Trim(Str(Sqr(Val(strCallback))))
                GoTo EndExtract
            Case Trim(UCase("abs"))
                strCallback = Trim(Str(Abs(Val(strCallback))))
                GoTo EndExtract
            Case Trim(UCase("cos"))

2011年01月22日 16点01分 32
level 6
XiaoJSoft 楼主
                If bpRadianWay = True Then
                    strCallback = Trim(Str(Cos(Val(strCallback))))
                Else
                    strCallback = Trim(Str(Cos(ConvertToRadian(Val(strCallback)))))
                End If
                GoTo EndExtract
            Case Trim(UCase("exp"))
                strCallback = Trim(Str(Exp(Val(strCallback))))
                GoTo EndExtract
            Case Trim(UCase("log"))
                strCallback = Trim(Str(Log(Val(strCallback)) / Log(lpLogBase)))
                GoTo EndExtract
            Case Trim(UCase("rnd"))
                strCallback = Trim(Str(Rnd(Val(strCallback))))
                GoTo EndExtract
            Case Trim(UCase("sgn"))
                strCallback = Trim(Str(Sgn(Val(strCallback))))
                GoTo EndExtract
            Case Trim(UCase("sin"))
                If bpRadianWay = True Then
                    strCallback = Trim(Str(Sin(Val(strCallback))))
                Else
                    strCallback = Trim(Str(Sin(ConvertToRadian(Val(strCallback)))))
                End If
                GoTo EndExtract
            Case Trim(UCase("opp"))

2011年01月22日 16点01分 33
level 6
XiaoJSoft 楼主
                strCallback = Trim(Str(-Val(strCallback)))
                GoTo EndExtract
            Case Trim(UCase("tan"))
                If bpRadianWay = True Then
                    strCallback = Trim(Str(Tan(Val(strCallback))))
                Else
                    strCallback = Trim(Str(Tan(ConvertToRadian(Val(strCallback)))))
                End If
                GoTo EndExtract
            Case Trim(UCase("sec"))
                If bpRadianWay = True Then
                    lpX = Val(strCallback)
                Else
                    lpX = ConvertToRadian(Val(strCallback))
                End If
                lpX = 1 / Cos(lpX)
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
            Case Trim(UCase("csc"))
                If bpRadianWay = True Then
                    lpX = Val(strCallback)
                Else
                    lpX = ConvertToRadian(Val(strCallback))
                End If
                lpX = 1 / Sin(lpX)
                strCallback = Trim(Str(lpX))

2011年01月22日 16点01分 34
level 6
XiaoJSoft 楼主
                GoTo EndExtract
            Case Trim(UCase("cot"))
                If bpRadianWay = True Then
                    lpX = Val(strCallback)
                Else
                    lpX = ConvertToRadian(Val(strCallback))
                End If
                lpX = 1 / Tan(lpX)
                strCallback = Trim(Str(lpX))
                GoTo EndExtract
        End Select
        Select Case Trim(UCase(strSpecial4))
            Case Trim(UCase("ln"))
                strCallback = Trim(Str(Log(Val(strCallback))))
                GoTo EndExtract
        End Select
EndExtract:
        ' 如果括号左边最后一个字符为-号,而且 Callback 小于零,则改-为+,strCallback取相反数。
        If Right(strIncludeLeft, 1) = "-" And Val(strCallback) < 0 Then
            strCallback = Trim(Str(-Val(strCallback)))
            strIncludeLeft = Left(strIncludeLeft, Len(strIncludeLeft) - 1) & "+"
        End If
        ' 如果右边有符号,那么取倒数+"K"
        If (Trim(UCase(Left(strIncludeRight, 1))) = Trim(UCase("+")) Or _
            Trim(UCase(Left(strIncludeRight, 1))) = Trim(UCase("-")) Or _
            Trim(UCase(Left(strIncludeRight, 1))) = Trim(UCase("*")) Or _
            Trim(UCase(Left(strIncludeRight, 1))) = Trim(UCase("/")) Or _
2011年01月22日 16点01分 35
1 2 3 4 5 6 尾页