`
atomoptics
  • 浏览: 95173 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

快速精确的对数学表达式求值

阅读更多
<p>快速精确的对数学表达式求值<br />表达式计算: 分析与设计<br />zz from .ibm.com/developerWorks</p> <p><!-- Black line separator--></p> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr valign="top"> <td>快速精确的对数学表达式求值</td> <td width="8"><img width="8" height="1" border="0" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> <td width="180" valign="bottom" align="right"><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index_eng.shtml"><b>英文原文</b></a></td> <td width="6"><img width="6" height="1" border="0" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> <tr valign="top"> <td bgcolor="#000000" colspan="5"><img width="100" height="1" border="0" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> <tr valign="top"> <td bgcolor="#ffffff" colspan="5"><img width="100" height="8" border="0" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> </tbody> </table> <p><!-- END HEADER AREA--><br /><!-- START BODY AREA--></p> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr valign="top"> <td width="10"><img width="10" height="1" border="0" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> <td width="100%"> <p><!-- Sidebar Gutter--><br /> <table width="168" cellspacing="0" cellpadding="0" border="0" align="right"> <tbody> <tr> <td width="8"><img width="5" height="21" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> <td width="160"><!-- Start TOC--></p> <p> <table width="160" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td width="160" height="1" bgcolor="#000000"><img width="160" height="1" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> <tr> <td height="5" align="center"><b>内容:</b></td> </tr> <tr> <td width="160" height="1" bgcolor="#666666"><img width="160" height="1" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> <tr> <td align="right"> <p><!--Standard links for every article --></p> <p> <table width="98%" cellspacing="0" cellpadding="3" border="0"> <tbody> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#h4577">表达式求值的经典算法</a></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#h10533">W3Eval:一种新的方法</a></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#h35212">结论</a></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#resources">参考资料</a></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#author1">关于作者</a></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#rating">对本文的评价</a></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <p><!-- End TOC--><br /><!-- Start Related Content Area--></p> <p> <table width="160" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td width="160" height="1" bgcolor="#000000"><img width="160" height="1" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> <tr> <td height="5" align="center"><b>相关内容:</b></td> </tr> <tr> <td width="160" height="1" bgcolor="#666666"><img width="160" height="1" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> <tr> <td align="right"> <p><!--Related Zone content --><br /> <table width="98%" cellspacing="0" cellpadding="3" border="0"> <tbody> <tr> <td><a href="http://www-105.ibm.com/developerWorks/education.nsf/java-onlinecourse-bytitle/95CA3B951560F6FD852567570076D326?OpenDocument">教程:Building a Java applet</a></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/index.shtml">更多 dW Java 参考资料</a></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <p><!-- End Related dW Content Area--></p> <p> <table width="160" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td width="150" height="2" bgcolor="#000000" colspan="2"><img width="160" height="2" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> <tr> <td width="150" height="2" bgcolor="#ffffff" colspan="2"><img width="160" height="2" src="http://www-900.ibm.com/developerWorks/cn/i/c.gif" alt="" /></td> </tr> </tbody> </table> <p><!-- END STANDARD SIDEBAR AREA--></td> </tr> </tbody> </table> <p>使用这个方便的 applet ,您就能一步一步的计算数学表达式了 <p><a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#author1">Nikola Stepan</a> (<a href="mailto:nikola.stepan@vz.tel.hr">nikola.stepan@vz.tel.hr</a>)<br />软件工程师,ABIT Ltd.<br />2001 年 9 月</p> <blockquote><p>对<br />于未经训练的用户来说,计算机科学领域中数学表达式求值的传统方法即不顺手又难以使用;软件工程师 Nikola.Stepan<br />旨在改变这些传统方法。他的 applet W3Eval<br />对表达式求值与您用纸笔计算的一系列步骤完全一致,但更快并且没有错误。请往下读,了解这一挑战 — 人类易读的数学到 Java 代码的转换。</p></blockquote> <p>还<br />记得在您的第一台科学计算器上用逆波兰表示法奋斗的经历吗?W3Eval applet 无法让您可信赖的 HP-41 更易用,正如它的名称所暗示<br />— 一个只能运行于 Web 的表达式求值程序。但它的确提供了一种方法 — 人类更易于遵循的对表达式一步一步的求值。</p> <p>W3Eval<br />的方法与传统计算器不同,却和人类的计算方式一致。当您用传统的计算器计算时,每输入一个新数,前一个数就看不到了。如果在输入一个长表达式中出了错,就<br />得全部重来。有了<br />W3Eval,您就能看到参与计算的所有东西,还能轻松的编辑表达式。它独特的能力(一步一步的对表达式求值)非常容易实现,因为用户能看到求值的每一<br />步,包括临时结果。</p> <p>本文将让您从头至尾认识 W3Eval 功能性的要点;您将看到一些用于表达式求值的代码。不过,我们还是先看看表达式求值的经典算法,这样您就会明白 W3Eval 方法的差异究竟有多少。</p> <p><a name="1"> </a> <a name="h4577">表达式求值的经典算法</a><br /> 编写代码对算术表达式求值的经典方法由 Donald Knuth 描述于 1962 年(请参阅<a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#resources">参考资料</a>)。Knuth 将此概括为三个步骤:</p> <ul> <li>对中缀表达式进行语法分析</li> <li>中缀表达式到后缀表达式的转换</li> <li>对后缀表达式求值</li> </ul> <p> 注意到我们谈到的这个经典算法有些简化:算术表达式只包含操作数、二元操作符和一种括号。此外,对于每个操作数和操作符,只用单个字符表示,使语法分析直观。</p> <p><a name="h5330">表达式表示法</a><br /> 算术表达式中最常见的表示法形式有<i>中缀、前缀</i>和<i>后缀</i>表示法。中缀表示法是书写表达式的常见方式,而前缀和后缀表示法主要用于计算机科学领域。</p> <p><b>中缀表示法</b><br /> 中缀表示法是算术表达式的常规表示法。称它为<i>中缀</i>表示法是因为每个操作符都位于其操作数的中间,这种表示法只适用于操作符恰好对应两个操作数的时候(在操作符是二元操作符如加、减、乘、除以及取模的情况下)。对以中缀表示法书写的表达式进行语法分析时,需要用括号和优先规则排除多义性。</p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />Syntax: operand1 operator operand2<br />Example: (A+B)*C-D/(E+F)<br /></code></pre></td> </tr> </tbody> </table> <p><b>前缀表示法</b><br /> 前缀表示法中,操作符写在操作数的前面。这种表示法经常用于计算机科学,特别是编译器设计方面。为纪念其发明家 — Jan Lukasiewicz(请参阅<a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#resources">参考资料</a>),这种表示法也称<i>波兰表示法</i>。</p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />Syntax : operator operand1 operand2<br />Example : -*+ABC/D+EF<br /></code></pre></td> </tr> </tbody> </table> <p><b>后缀表示法</b><br /> 在后缀表示法中,操作符位于操作数后面。后缀表示法也称<i>逆波兰表示法</i>(reverse Polish notation,RPN),因其使表达式求值变得轻松,所以被普遍使用。</p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />Syntax : operand1 operand2 operator<br />Example : AB+C*DEF+/-<br /></code></pre></td> </tr> </tbody> </table> <p>前缀和后缀表示法有三项公共特征:</p> <ul> <li>操作数的顺序与等价的中缀表达式中操作数的顺序一致</li> <li>不需要括号</li> <li>操作符的优先级不相关</li> </ul> <p><a name="h7667">中缀表达式到后缀表达式的转换</a><br /> 要把表达式从中缀表达式的形式转换成用后缀表示法表示的等价表达式,必须了解操作符的优先级和结合性。<i>优先级</i>或者说操作符的强度决定求值顺序;优先级高的操作符比优先级低的操作符先求值。 如果所有操作符优先级一样,那么求值顺序就取决于它们的<i>结合性</i>。操作符的结合性定义了相同优先级操作符组合的顺序(从右至左或从左至右)。 </p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />Left associativity : A+B+C = (A+B)+C<br />Right associativity : A^B^C = A^(B^C)<br /></code></pre></td> </tr> </tbody> </table> <p>转换过程包括用下面的算法读入中缀表达式的操作数、操作符和括号:</p> <ol> <li>初始化一个空堆栈,将结果字符串变量置空。</p> </li> <li>从左到右读入中缀表达式,每次一个字符。 </li> <li>如果字符是操作数,将它添加到结果字符串。 </li> <li>如果字符是个操作符,弹出(pop)操作符,直至遇见开括号(opening parenthesis)、优先级较低的操作符或者同一优先级的右结合符号。把这个操作符压入(push)堆栈。 </li> <li>如果字符是个开括号,把它压入堆栈。 </li> <li>如果字符是个闭括号(closing parenthesis),在遇见开括号前,弹出所有操作符,然后把它们添加到结果字符串。 </li> <li>如果到达输入字符串的末尾,弹出所有操作符并添加到结果字符串。</li> </ol> <p><a name="h9608">后缀表达式求值</a><br /> 对后缀表达式求值比直接对中缀表达式求值简单。在后缀表达式中,不需要括号,而且操作符的优先级也不再起作用了。您可以用如下算法对后缀表达式求值:</p> <ol> <li>初始化一个空堆栈</p> </li> <li>从左到右读入后缀表达式 </li> <li>如果字符是一个操作数,把它压入堆栈。 </li> <li>如果字符是个操作符,弹出两个操作数,执行恰当操作,然后把结果压入堆栈。如果您不能够弹出两个操作数,后缀表达式的语法就不正确。 </li> <li>到后缀表达式末尾,从堆栈中弹出结果。若后缀表达式格式正确,那么堆栈应该为空。</li> </ol> <p><a name="h10533">W3Eval:一种新的方法</a></p> <p>W3Eval<br />的方法与上面概括的经典算法不同。不是把中缀表达式转换为后缀表示法;恰恰相反,它对中缀表达式直接求值。这种方法比传统方法稍微复杂了些,但它支持一步<br />一步的求值,在执行时您能看到每一步。求值过程类似于手工计算:如果表达式中包含括号,先求嵌套最深的括号对中的子表达式的值。所有括号内的子表达式都求<br />值完毕后,表达式的其它部分再求值。</p> <p>求值过程分为三个步骤:</p> <ol> <li>表达式语法分析</li> <li>表达式检查</li> <li>一步一步的求值</li> </ol> <p><a name="h11517">表达式语法分析</a><br /> W3Eval 的数学表达式由数字、变量、操作符、函数和括号组成。除了缺省的十进制计数制外 W3Eval 还支持二进制、八进制和十六进制。这些以其它计数制计数的数必须以 <code>#</code> 开头,并紧跟 <code>b</code>、<code>o</code> 或者 <code>h</code> 来分别表示二进制、八进制或十六进制。</p> <p>W3Eval 的变量是不限长度的大写字母和数字序列,其首字符必须是字母。W3Eval 有一些预定义的变量,不过它也支持用户定义的变量。</p> <p>W3Eval 支持带有固定或不定数量自变量的函数。 函数可分为以下几组:</p> <ul> <li>三角函数(sin、cos、tan、cot、sec、csc)</li> <li>反三角函数(asin、acos、atan、atan2、acot、asec、acsc)</li> <li>双曲线函数(sinh、cosh、tanh、coth、sech、csch)</li> <li>反双曲线函数(asinh、acosh、atanh、acoth、asech、acsch)</li> <li>指数函数(log、log2、log10、exp、exp2、exp10、sqrt、cur)</li> <li>组合学函数(Combinatoric)(comb、combr、perm、permr、var、varr)</li> <li>统计函数(sum、avg、min、max、stddev、count)</li> <li>其它(abs、ceil、fact、floor、pow、random、rint、round、sign、frac、hypot、deg、rad、trunc、int)</li> </ul> <p>W3Eval 对表达式进行<i>语法分析</i>,也就是指它识别出表达式的算术成分,并将它们转化成语言符号(token),然后把它们放入向量。表达式一旦处于这种状态,就为下面两步做好了准备:表达式检查和求值。</p> <p> W3Eval 的<i>符号(token)</i>是算术表达式的组成部分;<i>记号(mark)</i> 是独立的字符, 由 applet 使用,作为识别各种符号的内部标志。每种符号有唯一的 mark 与之对应。W3Eval 的表达式由表 1 所示的符号组成。</p> <p><b>表 1. W3Eval 的符号</b></p> <table width="100%" cellspacing="0" cellpadding="5" border="1"> <tbody> <tr> <td><b>Token</b></td> <td><b>Mark</b></td> <td><b>类</b></td> </tr> <tr> <td>十进制数</td> <td></td> <td><code>Double</code></td> </tr> <tr> <td>二进制数</td> <td></td> <td><code>String</code></td> </tr> <tr> <td>十六进制数</td> <td></td> <td><code>String</code></td> </tr> <tr> <td>八进制数</td> <td></td> <td><code>String</code></td> </tr> <tr> <td>变量</td> <td></td> <td>Variable </td> </tr> <tr> <td>函数</td> <td></td> <td><code>Function</code></td> </tr> <tr> <td>操作符</td> <td></td> <td><code>Operator</code></td> </tr> <tr> <td>开括号</td> <td></td> <td><code>String</code></td> </tr> <tr> <td>闭括号</td> <td></td> <td><code>String</code></td> </tr> <tr> <td>逗号</td> <td></td> <td><code>String</code></td> </tr> </tbody> </table> </p> <p>用以表示函数、操作符和变量类的定义如清单 1 所示:</p> <p><a name="code1"><b>清单 1. Function、Operator 和 Variable 类的定义</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />public class Function<br /> {<br /> public String function;<br /> public int number_of_arguments;<br /><br /> public Function( String function, int number_of_arguments )<br /> {<br /> this.function=function;<br /> this.number_of_arguments=number_of_arguments;<br /> }<br /><br /> public String toString()<br /> {<br /> return function;<br /> }<br /> }<br /><br />public class Operator<br /> {<br /> public String operator;<br /> public byte priority;<br /><br /> public Operator( String operator, byte priority )<br /> {<br /> this.operator=operator;<br /> this.priority=priority;<br /> }<br /><br /> public String toString()<br /> {<br /> return operator;<br /> }<br /> }<br /><br />public class Variable<br /> {<br /> public String variable;<br /> public double value;<br /><br /> public Variable( String variable, double value )<br /> {<br /> this.variable=variable;<br /> this.value=value;<br /> }<br /><br /> public String toString()<br /> {<br /> return variable;<br /> }<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p><code>Token</code> 类如清单 2 所示。</p> <p><a name="listing2"><b>清单 2. Token 类</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />public class Token<br /> {<br /> public Object token;<br /> public char mark;<br /> public int position;<br /> public int length;<br /><br /> public Token ( Object token, char mark, int position, int length )<br /> {<br /> this.token=token;<br /> this.mark=mark;<br /> this.position=position;<br /> this.length=length;<br /> }<br /><br /> public String toString()<br /> {<br /> return token.toString()+" ; "+mark+" ; "+position+" ; "+length+"<br />";<br /> }<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p><a name="h16567">表达式检查</a><br /> 检查正规表达式正确性的所有代码都在一个独立的类中。详细的表达式检查能够确定错误确切的类型和位置。 错误检查有七类: </p> <p><b>括号检查。</b>W3Eval 的表达式可以包含三种括号:标准圆括号、方括号和花括号。如果表达式包含相同数量的开括号和闭括号,并且每个开括号与一个相应的同种闭括号相匹配,则表达式的括号语法正确。三种括号在语义上等价,如下面的代码段所示。</p> <p><a name="listing3"><b>清单 3. 三种括号</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />import java.util.Stack;<br /><br />public class Parentheses_check<br /> {<br /><br /> public static boolean is_open_parenthesis( char c )<br /> {<br /> if ( c=='(' &line;&line; c=='[' &line;&line; c=='{' )<br /> return true;<br /> else<br /> return false;<br /> }<br /><br /> public static boolean is_closed_parenthesis( char c )<br /> {<br /> if ( c==')' &line;&line; c==']' &line;&line; c=='}' )<br /> return true;<br /> else<br /> return false;<br /> }<br /><br /> private static boolean parentheses_match( char open, char closed )<br /> {<br /> if ( open=='(' &amp;&amp; closed==')' )<br /> return true;<br /> else if ( open=='[' &amp;&amp; closed==']' )<br /> return true;<br /> else if ( open=='{' &amp;&amp; closed=='}' )<br /> return true;<br /> else<br /> return false;<br /> }<br /><br /> public static boolean parentheses_valid( String exp )<br /> {<br /> Stack s = new Stack();<br /> int i;<br /> char current_char;<br /> Character c;<br /> char c1;<br /> boolean ret=true;<br /><br /> for ( i=0; i {<br /><br /> current_char=exp.charAt( i );<br /><br /> if ( is_open_parenthesis( current_char ) )<br /> {<br /> c=new Character( current_char );<br /> s.push( c );<br /> }<br /> else if ( is_closed_parenthesis( current_char ) )<br /> {<br /> if ( s.isEmpty() )<br /> {<br /> ret=false;<br /> break;<br /> }<br /> else<br /> {<br /> c=(Character)s.pop();<br /> c1=c.charValue();<br /> if ( !parentheses_match( c1, current_char ) )<br /> {<br /> ret=false;<br /> break;<br /> }<br /> }<br /> }<br /> }<br /><br /> if ( !s.isEmpty() )<br /> ret=false;<br /><br /> return ret;<br /> }<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p><b>token 检查。</b>检查表达式语法。确保表达式所有部分都被认为是合法的。</p> <p><b>表达式开头的检查</b>(请参阅<a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#listing4">清单 4</a>)<b>。</b>确保表达式从合法的符号开始。不可以用操作符、逗号或闭括号作为表达式的开始符。</p> <pre><a name="listing4"><b>清单 4. 正确的表达式开头的检查</b></a><br /><br /><br /><br /><table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"><tbody><tr><td><pre><code><br />private static boolean begin_check( Vector tokens, Range r, StringBuffer err )<br /> {<br /> char mark;<br /> Token t;<br /><br /> t=(Token)tokens.elementAt( 0 );<br /> mark=t.mark;<br /><br /> if ( mark=='P' )<br /> err.append( Messages.begin_operator );<br /> else if ( mark==')' )<br /> err.append( Messages.begin_parenthesis );<br /> else if ( mark=='Z' )<br /> err.append ( Messages.begin_comma );<br /> else<br /> return true;<br /><br /> r.start=0;<br /> r.end=t.length;<br /> return false;<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p></p> </pre><p><b>表达式末尾的检查。</b>确保表达式以合法符号结束。不可以用操作符、函数、逗号或开括号作为表达式结束符。</p> <p><b>符号序列的检查。</b>检查表达式中的符号序列。在下面的表格中,若 X 轴上的符号和 Y 轴上的符号对应的交界处用 X 作了记号,则相应 X 轴上的符号可以接在 Y 轴上符号的后面。</p> <p><b>表 2. 合法的符号序列</b></p> <p> <table width="50%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td></td> </tr> <tr> <th width="20"> _</th> <th width="20" bgcolor="#cccccc"> D </th> <th width="20" bgcolor="#cccccc"> B </th> <th width="20" bgcolor="#cccccc"> H </th> <th width="20" bgcolor="#cccccc"> O </th> <th width="20" bgcolor="#cccccc"> V </th> <th width="20" bgcolor="#cccccc"> F </th> <th width="20" bgcolor="#cccccc"> P </th> <th width="20" bgcolor="#cccccc"> ( </th> <th width="20" bgcolor="#cccccc"> ) </th> <th width="20" bgcolor="#cccccc"> Z </th> </tr> <tr> <th bgcolor="#cccccc"> D </th> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> 犠 </td> </tr> <tr> <th bgcolor="#cccccc"> B </th> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> 犠 </td> </tr> <tr> <th bgcolor="#cccccc"> H </th> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> 犠 </td> </tr> <tr> <th bgcolor="#cccccc"> O </th> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> 犠 </td> </tr> <tr> <th bgcolor="#cccccc"> V </th> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> 犠 </td> </tr> <tr> <th bgcolor="#cccccc"> F </th> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> 犠 </td> <td> _</td> <td> _</td> </tr> <tr> <th bgcolor="#cccccc"> P </th> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> _</td> <td> _</td> </tr> <tr> <th bgcolor="#cccccc"> ( </th> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> _</td> <td> _</td> </tr> <tr> <th bgcolor="#cccccc"> ) </th> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> _</td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> 犠 </td> </tr> <tr> <th bgcolor="#cccccc"> Z </th> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> 犠 </td> <td> _</td> <td> 犠 </td> <td> _</td> <td> _</td> </tr> </tbody> </table> </p> <p><b>函数检查。</b>确保表达式中所有函数的自变量数量正确。 </p> <p><b>逗号检查。</b>逗号只能用于分隔函数的自变量。若用于表达式其它地方,就不合法。</p> <p><a name="">一步一步的求值</a><br /> 只有能顺利通过以上概括的所有检查的表达式,W3Eval 才求值。从而确保内建于 W3Eval 中的前提条件不会出现问题。后面的算法用于单步执行表达式求值:</p> <ol> <li>找出嵌入最深的那对括号。</li> <li>在这对括号中,找出优先级最高的操作符。</li> <li>若这对括号中没有操作符: <ul> <li>如果表达式再不包含任何其它的括号,求值(过程)完成。</li> <li>如果表达式包含括号,但不包含操作符,则存在一个函数。对函数求值,然后转到步骤 5。</li> </ul> </li> <li>获取操作数并执行运算。</li> <li>从向量中除去用过的符号并在同一位置放入结果。</li> <li>除去冗余括号。</li> <li>将向量中剩余的符号结合到字符串并在屏幕上显示结果。</li> </ol> <p>现在,我们将更为详细的查看算法的每一步,同时查看大部分有意思的代码片段。</p> <p><b>步骤 1:</b>为避免括号的处理,W3Eval 确定哪个子表达式处于嵌套最深的那对括号中。这项任务需要两步。第一步,W3Eval 必须找出第一个闭括号: </p> <p><a name="listing5"><b>清单 5. 找出第一个闭括号</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />public static int pos_first_closed_parenthesis( Vector tokens )<br /> {<br /> Token t;<br /><br /> for ( int i=0; i {<br /> t=(Token)tokens.elementAt( i );<br /> if ( t.mark==')' )<br /> return i;<br /> }<br /> return 0;<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p> 第二步,找出与第一步找到的闭括号相匹配的开括号,如<a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#listing6">清单 6 所示</a>。</p> <pre><a name="listing6"><b>清单 6. 找出匹配的开括号</b></a><br /><br /><br /><br /><table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"><tbody><tr><td><pre><code><br />public static int pos_open_parenthesis( Vector tokens, int closed_parenthesis )<br /> {<br /> int i;<br /> Token t;<br /><br /> i=closed_parenthesis-2;<br /><br /> while ( i&gt;=0 )<br /> {<br /> t=(Token)tokens.elementAt( i );<br /> if ( t.mark=='(' )<br /> {<br /> return i;<br /> }<br /> i--;<br /> }<br /> return 0;<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p></p> </pre><p><b>步骤 2:</b>要实现求值的单步执行,W3Eval 在嵌套最深的那对括号中找出优先级最高的操作符。(操作符的优先级已硬编码到 applet 中;请参阅<a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/index.shtml#resources">参考资料</a>以获取完整的代码清单。)</p> <p><a name="listing7"><b>清单 7. 找出优先级最高的操作符</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />public static int pos_operator( Vector tokens, Range r )<br /> {<br /> byte max_priority=Byte.MAX_VALUE;<br /> int max_pos=0;<br /><br /> byte priority;<br /> String operator;<br /> Token t;<br /><br /> for ( int i=r.start+2; i {<br /> t=(Token)tokens.elementAt( i );<br /> if ( t.mark!='P' )<br /> continue;<br /> priority=((Operator)t.token).priority;<br /> operator=((Operator)t.token).operator;<br /><br /> if ( priority operator.equals("**") ) &amp;&amp; priority == max_priority )<br /> {<br /> max_priority=priority;<br /> max_pos=i;<br /> }<br /> }<br /> return max_pos;<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p><b>步骤 3:</b>如果表达式中不包含其它括号,求值的过程就完成。如果表达式包含括号,但不包含操作符,则存在需要求值的函数。</p> <p><a name="listing8"><b>清单 8. 检查是否还有其它操作符</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />...<br />int poz_max_op=pos_operator( tokens, range );<br />// if there are no operators<br />if ( poz_max_op==0 )<br /> {<br /> if ( no_more_parentheses )<br /> {<br /> return false;<br /> }<br /> else<br /> {<br /> double result;<br /> result=function_result( tokens, range.start-1 );<br /> function_tokens_removal( tokens, range.start-1 );<br /><br /> t = new Token ( new Double(result), 'D', 0, 0 );<br /> tokens.setElementAt( t, range.start-1 );<br /><br /> parentheses_removal( tokens, range.start-1 );<br /> return true;<br /> }<br /> }<br />...<br /></code></pre></td> </tr> </tbody> </table> <p><b>步骤 4:</b>所有的操作符都是二元的,也就是说第一个操作数位于操作符之前,第二个操作符位于操作符之后。</p> <p><a name="listing9"><b>清单 9. 获取操作数并执行运算</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />...<br />double operand1, operand2;<br /><br />// first operand is before...<br />t=(Token)tokens.elementAt( poz_max_op-1 );<br />operand1=operand_value( t );<br /><br />// ...and second operand is after operator<br />t=(Token)tokens.elementAt( poz_max_op+1 );<br />operand2=operand_value( t );<br /><br />// operator<br />t=(Token)tokens.elementAt( poz_max_op );<br />String op=((Operator)t.token).operator;<br /><br />double result=operation_result( operand1, operand2, op );<br /><br />tokens.removeElementAt( poz_max_op+1 );<br />tokens.removeElementAt( poz_max_op );<br /><br />t = new Token ( new Double(result), 'D', 0, 0 );<br />tokens.setElementAt( t, poz_max_op-1 );<br /><br />parentheses_removal( tokens, poz_max_op-1 );<br />...<br /></code></pre></td> </tr> </tbody> </table> <p>操作数可以是变量,还可以是十进制、十六进制、八进制或二进制数。</p> <p><a name="listing10"><b>清单 10. 获取操作数</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />public static double operand_value( Token t )<br /> {<br /> if ( t.mark=='V' )<br /> return ((Variable)t.token).value;<br /> else if ( t.mark=='D' )<br /> return ((Double)t.token).doubleValue();<br /> else if ( t.mark=='H' )<br /> return base_convert( ((String)t.token).substring(2), 16 );<br /> else if ( t.mark=='O' )<br /> return base_convert( ((String)t.token).substring(2), 8 );<br /> else if ( t.mark=='B' )<br /> return base_convert( ((String)t.token).substring(2), 2 );<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p>接下来的方法将不同计数制的数转化为十进制的形式。</p> <p><a name="listing11"><b>清单 11. 将数转化为十进制数</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />public static long base_convert( String s, int base )<br /> {<br /> long r=0;<br /> int i, j;<br /><br /> for ( i=s.length()-1, j=0; i&gt;=0; i--, j++ )<br /> r=r+digit_weight( s.charAt( i ) )*(long)Math.pow( base, j );<br /> return r;<br /> }<br /><br />public static int digit_weight( char c )<br /> {<br /> if ( Character.isDigit( c ) )<br /> return c-48;<br /> else if ( 'A' return c-55;<br /> else if ( 'a' return c-87;<br /> return -1;<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p>一旦确定操作数和操作符后,就可以执行运算了,如<a href="http://www-900.ibm.com/developerWorks/cn/java/j-w3eva/listing12.html">清单 12</a> 所示。</p> <p><b>步骤 5:</b>在这步中,W3Eval 从向量中除去用过的符号并在同一位置放入结果。对于函数求值这类情况,除去的是函数、括号、自变量和逗号;而对于操作符求值这类情况而言,除去的则是操作数和操作符。</p> <p><b>步骤 6:</b>在求值的这一步,W3Eval 从表达式中除去冗余括号。 </p> <p><a name="listing13"><b>清单 13. 除去冗余括号</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />private static void parentheses_removal( Vector tokens, int pos )<br /> {<br /> if ( <br /> pos&gt;1 &amp;&amp;<br />amp;&amp;&amp;<br />amp;<br /> ((Token)tokens.elementAt( poz-2 )).mark!='F' &amp;&amp;<br />amp;&amp;&amp;<br />amp;<br /> ((Token)tokens.elementAt( poz-1 )).mark=='(' &amp;&amp;<br />amp;&amp;&amp;<br />amp;<br /> ((Token)tokens.elementAt( poz+1 )).mark==')'<br /> &line;&line;<br /> pos==1 &amp;&amp;<br />amp;&amp;&amp;<br />amp;<br /> ((Token)tokens.elementAt( 0 )).mark=='(' &amp;&amp;<br />amp;&amp;&amp;<br />amp;<br /> ((Token)tokens.elementAt( 2 )).mark==')'<br /> )<br /> {<br /> tokens.removeElementAt( poz+1 );<br /> tokens.removeElementAt( poz-1 );<br /> }<br /> return;<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p><b>步骤 7:</b>在求值的最后一步,向量中剩余的符号被结合到字符串,并在屏幕上显示。</p> <p><a name="listing14"><b>清单 14. 结合符号并显示结果</b></a></p> <table width="100%" cellspacing="0" cellpadding="5" border="1" bgcolor="#cccccc"> <tbody> <tr> <td> <pre><code><br />public static String token_join( Vector tokens )<br /> {<br /> String result=new String();<br /> Token t;<br /><br /> for ( int i=0; i {<br /> t=(Token)tokens.elementAt( i );<br /><br /> if ( t.mark=='D' )<br /> {<br /> double n=((Double)t.token).doubleValue();<br /> result=result + formated_number( n );<br /> }<br /> else<br /> result=result + t.token;<br /><br /> if ( result.endsWith( ".0" ) )<br /> result=result.substring( 0, result.length()-2 );<br /> result=result + " ";<br /> }<br /> return result;<br /> }<br /></code></pre></td> </tr> </tbody> </table> <p><a name="9"> </a> <a name="h35212">结论</a><br /> 本文分析了一个 applet ,它能一步一步的对算术表达式求值。同时还按顺序回顾了最有意思的代码片段,并论述了两种不同的表达式求值方法。</p> <p> 下一版 W3Eval 有望在各方面得到增强,包括有能力添加用户定义的功能;支持分数、复数和矩阵;改良的图形用户界面(GUI);大小和速度优化以及安全性方面的增强。我鼓励您提供您自己对于增强方面的设想。</p> <p>我希望您会发现 W3Eval 是个对表达式求值有益的在线工具,它在某种程度上比经典的方法更简单自然。我还期待这里谈到的代码和算法使您明白 Java 语言有助于处理数学问题。</p> <p><a name="resources">参考资料</a></p> <ul> <li><a href="http://geodet.geof.hr/%7Emstepan/nik/W3Eval.html">W3Eval applet</a> 是免费的,它的<a href="http://geodet.geof.hr/%7Emstepan/nik/help.html">帮助</a>有助于您解决问题。</p> </li> <li>这张表格展示了 <a href="http://geodet.geof.hr/%7Emstepan/nik/operators.html">W3Eval 操作符的优先级</a>。 </li> <li>请阅读波兰数学家 <a href="http://www-groups.dcs.st-and.ac.uk/%7Ehistory/Mathematicians/Lukasiewicz.html">Jan Lukasiewicz</a> 的传记。 </li> <li>Donald Knuth,计算机科学领域卓越的学者,曾详尽的就算法的设计和分析撰写和演讲。他的<a href="http://www-cs-faculty.stanford.edu/%7Eknuth/">主页</a>提供最近出版的有关其作品的论文和信息的链接。 </li> <li>有兴趣随意编写 applet 吗?可以查看我们的教程 <a href="http://www-105.ibm.com/developerWorks/education.nsf/java-onlinecourse-bytitle/95CA3B951560F6FD852567570076D326?OpenDocument">Building a Java applet</a>(developerWorks,1999 年)以获得一步一步的指导。 </li> <li>您会觉得 <a href="http://www.ibiblio.org/javafaq/javafaq.html">Java FAQ</a> 很有用。 </li> <li>还有很多有关 applet 的信息在 Peter Van Der Linden(Prentice Hall PTR/Sun Microsystems 出版社出版,1998 年 12 月)的<i><a>Just Java 2</a></i> 中。 </li> <li> 由 Ken Arnold、James Gosling 和 David Holmes 撰写的 <a href="http://www.amazon.com/exec/obidos/ASIN/0201704331/qid=997216269/sr=2-2/102-7082828-4831324"><i>The Java Programming Language</i></a>(Addison Wesley 出版社出版,2000 年 12 月)包含有益的关于集合的信息。 </li> <li>学习 Martin Bastiaan 的<a href="http://www-106.ibm.com/developerWorks/java/library/walk-in-the-park.html">“A Walk in the Park”</a>(developerWorks,1998 年 1 月),了解更多有关 applet 的知识。 </li> <li><a href="http://www-900.ibm.com/developerWorks/cn/cgi-bin/click.cgi?url=http://www-4.ibm.com/software/ad/vajava/&amp;origin=j">VisualAge for Java</a> 使 applet 的开发变得轻而易举。 </li> <li>在 <a href="http://www-900.ibm.com/developerWorks/cn/java/index.shtml">developerWorks Java 技术专区</a>查找更多 Java 参考资料。 </li> </ul> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td><a name="author1">关于作者<br /><img width="64" height="80" border="0" align="left" src="http://www-900.ibm.com/developerWorks/cn/i/authors/p-stepan.jpg" alt="photo of Nikola Stepan" />Nikola<br />Stepan 是 ABIT Ltd.<br />的软件工程师,他在那里从事银行业软件的设计和开发。他有广博的信息系统方面的学术背景和丰富的编程经验(从低级编程到信息系统)。他特别喜欢面向对象编<br />程语言、关系数据库、因特网编程和系统编程。他于 1999 年在克罗地亚 Varazdin 的 Faculty of Organisation<br />and Informatic 获得信息系统学士学位。他会说克罗地亚语、英语和一点德语。请通过 </a><a href="mailto:nikola.stepan@vz.tel.hr">nikola.stepan@vz.tel.hr</a> 与 Nikola 联系。</p> </td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr valign="top"> <td>表达式计算: 分析与设计 </td> <td width="8"><img width="8" height="1" border="0" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> <td width="180" align="right"><img width="180" height="1" border="0" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> <td width="6"><img width="6" height="1" border="0" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr valign="top"> <td bgcolor="#000000" colspan="5"><img width="100" height="1" border="0" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr valign="top"> <td bgcolor="#ffffff" colspan="5"><img width="100" height="8" border="0" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> </tbody> </table> <table width="100%" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr valign="top"> <td width="5"><img width="5" height="1" border="0" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> <td width="100%"> <table width="168" cellspacing="0" cellpadding="0" border="0" align="right"> <tbody> <tr> <td width="8"><img width="5" height="21" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> <td width="160"> <table width="160" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td width="160" height="1" bgcolor="#000000"><img width="160" height="1" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td height="5" align="center"><b>内容:</b></td> </tr> <tr> <td width="160" height="1" bgcolor="#666666"><img width="160" height="1" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td> <table width="160" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAASQOC">问题由来</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAHSQOC">问题的一般性</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDANSQOC">一些已有的设计和实现不能满足要求</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDATSQOC">我的设计想法和目标</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDA3SQOC">数值</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAETQOC">括号</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDARTQOC">运算符</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAAUQOC">变量</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAGUQOC">表达式解析接口</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAWUQOC">中缀表达式到后缀的转换</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAFVQOC">计算后缀表达式</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDASVQOC">缺省实现</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAQWQOC">扩展实现</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#IDAWWQOC">总结</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <p><!--Standard links for every dw-article--><br /> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#author1">关于作者</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#rating">对本文的评价</a></td> </tr> <tr> <td><img width="160" height="10" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <table width="160" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td width="160" height="1" bgcolor="#000000"><img width="160" height="1" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td height="5" align="center"><b>订阅:</b></td> </tr> <tr> <td width="160" height="1" bgcolor="#666666"><img width="160" height="1" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td> <table width="160" cellspacing="0" cellpadding="1" border="0"> <tbody> <tr> <td><a href="http://www-900.ibm.com/developerworks/cn/newsletter/index.html">developerWorks 时事通讯</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td><a href="http://www-900.ibm.com/developerworks/cn/subscription/index.shtml">developerWorks 订阅<br />(订阅CD 和下载)</a></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td height="1"><img width="160" height="5" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <table width="160" cellspacing="0" cellpadding="0" border="0"> <tbody> <tr> <td width="150" height="2" bgcolor="#000000" colspan="2"><img width="160" height="2" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> <tr> <td width="150" height="2" bgcolor="#ffffff" colspan="2"><img width="160" height="2" alt="" src="http://www-900.ibm.com/developerworks/cn/i/c.gif" /></td> </tr> </tbody> </table> </td> </tr> </tbody> </table> <p><a href="http://www-900.ibm.com/developerWorks/cn/java/l-expression/index.shtml#author1">刘源</a><br />软件工程师, 上海复旦光华电信部<br />2004 年 11 月 </p> <blockquote></blockquote> <p><a name="IDAASQOC">问题由来</a><br />在<br />我做过的一个针对网络设备和主机的数据采集系统中,某些采集到的数据需要经过一定的计算后才保存入库,而不是仅仅保存其原始值。为了提供给用户最大的灵活<br />性,我设想提供一个用户界面,允许用户输入计算表达式(或者称为计算公式)。这样,除了需要遵从少量的规则,用户可以得到最大的灵活性。</p> <p>这<br />样的表达式具有什么特点呢?它一般不是纯的可立即计算的表达式(简单的如:1+2*3-4)。它含有我称为变量的元素。变量一般具有特殊的内定的语法,例<br />如可能用"@totalmemory"表示设备或主机(下面简称为设备)的物理内存总数,那么表达式"(@totalmemory-<br />@freememory)/@totalmemory*100"就表示设备当前内存使用
分享到:
评论

相关推荐

    逍遥表达式求值控件

    这款控件的核心功能在于其强大的表达式处理能力,能够接受以字符串形式输入的数学表达式,并执行求值运算。 该控件主要适用于那些需要在程序中动态计算复杂数学表达式的情况。例如,如果你正在开发一款财务软件,...

    实用数学工具企业版(可以计算超复杂的数学表达式)

    2.可以作为大型的计算器,本工具可以计算超复杂的数学表达式! 如:lg(1+2*5+2-|1-10|)+cos(tg(0.1))+3!=8.0778 3.完全符合数学简写习惯,大大加快了输入速度! 如5*x可简写为5x,2*sin(x)可简写为2sin(x) 4.多达20...

    基于中点弦测法的轨道不平顺精确值数学模型研究

    - **传递函数**:用于描述系统输入(轨道不平顺)与输出(弦测值)之间关系的数学表达式。 - **数学模型**:本研究的核心,用以描述轨道不平顺与弦测值之间的数学关系,为后续算法开发提供理论基础。 #### 弦测法的...

    牛顿拉夫逊算法进行潮流计算,数据处理程序,方便处理实验数据,并取得数学表达式

    总结起来,牛顿拉夫逊算法是电力系统潮流计算的关键技术,它通过迭代求解非线性方程组,实现了对电力网络中复杂物理现象的精确模拟。MATLAB作为实现工具,简化了算法的编程过程,使得数据处理和结果分析更为便捷。...

    弹性表达式

    弹性表达式是实现物体弹性运动的一种有效手段,它结合了振幅、频率、衰减等多种参数,通过精确的数学计算来模拟真实世界的物理现象,从而达到高度逼真的动画效果。掌握这些基本原理对于提升动画作品的质量至关重要。

    【三维设计】2013届高考数学一轮复习 题型技法点拨 快得分系列(四)巧用平方关系解决三角化简、求值问题 新人教版

    本节内容主要聚焦于“巧用平方关系解决三角化简、求值问题”,这是2013届高考数学一轮复习中题型技法点拨的一部分,特别针对新人教版教材。在处理三角函数的化简和求值时,熟练运用平方关系可以显著减少计算量,提高...

    atan_test.zip_atan_fast_atan

    数值逼近是计算atan函数的一种常见方法,因为精确的数学表达式(如通过积分得到的无穷级数)在计算机上可能不切实际或效率低下。"atan_fast_atan"可能采用了特定算法或近似方法,比如Maclaurin级数、CORDIC算法或者...

    北师版七年级数学(下)期中水平测试(A)借鉴.pdf

    4. 数学表达式:了解正确的数学表达式书写规则,例如正确答案是B. abbaba4)()(22,表示a乘以b的平方再乘以b的四次方等于2的平方。 5. 近似数的理解:近似数3.20×10^5有3个有效数字(3, 2, 0),精确到千位。有效...

    MatLab工程数学应用

    符号运算在理论计算中不可或缺,MatLab的符号计算工具箱允许进行精确的数学表达式处理,包括简化表达式、求解代数方程、积分和微分。这为理论研究和验证提供了强大支持,避免了数值计算中可能出现的误差。 在图形...

    matlab符号数学工具箱

    MATLAB的符号数学工具箱是MATLAB环境中的一个重要扩展,它提供了一系列高级的数学运算功能,使得用户可以处理未定义的、精确的数学表达式,而不仅仅是数值计算。这个工具箱广泛应用于科研、工程和教育领域,对于进行...

    数学公式解析控件

    在IT领域,数学公式解析控件是一种至关重要的工具,它主要负责处理和解析数学公式,以实现对数学表达式的正确理解和计算。这类控件广泛应用于教育软件、科学计算软件、电子文档编辑器以及在线学习平台等,为用户提供...

    maple软件实用例题

    在计算机科学中,Maple作为一款高级数学工具,可以处理复杂的数学问题,比如在编程时解决数学算法的难题,进行精确的数学表达式操作,或者进行数值模拟。对于电子、电气工程专业的学生,Maple可以帮助他们分析电路、...

    matlab零基础入门符号计算:15 脚本m文件 (含教学视频).zip

    这个“matlab零基础入门符号计算:15 脚本m文件 (含教学视频)”的资源提供了对MATLAB符号计算的基本介绍,通过15个脚本M文件和配套的教学视频,帮助初学者快速上手。 首先,我们要了解什么是M文件。M文件是MATLAB...

    符号计算系统MAPLE教程

    首先,Maple与传统的数值计算软件不同,它更擅长进行符号计算,即直接处理数学表达式和符号,得出精确的数学公式解答。这与我们通常使用的计算器或数值计算软件如MATLAB等进行的数值计算有很大区别,后者主要是针对...

    matlab求解高等数学问题

    1. **符号计算**:MATLAB不仅支持数值计算,还提供了符号计算工具箱,允许用户进行精确的数学表达式处理,如积分、微分方程求解等。这对于处理高等数学中的理论问题非常有用。 2. **微积分**:MATLAB可以求解一元和...

    C语言下迈克耳孙干涉仪测量空气折射率的实验探究.pdf

    在处理实验数据时,最小二乘法能够提供一个精确的数学模型,对实验数据进行拟合,得到数据变化趋势的数学表达式。这个数学表达式不仅能够反映出空气折射率随压强变化的关系,还能够为实验数据提供一个连续可导的拟合...

    基于MATLAB的高等数学问题求解高清扫描版

    MATLAB的符号计算功能则允许对数学表达式进行精确运算,这对于解析解的求解至关重要。 在微积分部分,教程将详细讲解如何利用MATLAB求解导数和不定积分,以及如何应用牛顿-莱布尼茨公式进行定积分的计算。MATLAB的...

    2022年全国中考数学分类解析汇编专题8定值问题.pdf

    根据给出的部分内容,本文档是一份专门针对2022年全国中考数学定值问题的分类解析汇编资料。文档中可能涉及多个数学知识点,包括...中考数学考生需要对这些知识点有充分的了解和掌握,以便在考试中准确快速地解决问题。

    牛顿迭代求根算法的分析与实现 论文 完整版

    而即使对于求一元方程实根这类问题,也只有在少数简单的情况下,才可以用传统的方法得到根的数学表达式。对于需要计算定积分的问题,便的计算出来结果但并不影响计算出来结果的精确度,运用于多种工业设计和数学设计...

    正值表达式工具,可以通过它方便写出表达式

    正值表达式工具是一种用于创建和处理数学或逻辑表达式的实用程序,它可以帮助用户方便地构建、编辑和评估复杂的表达式。在计算机科学和编程领域,正值表达式通常指的是正则表达式,这是一种强大的文本处理模式匹配...

Global site tag (gtag.js) - Google Analytics