SumTingWong Posted December 22, 2004 Share Posted December 22, 2004 (edited) I saw a discussion a few days ago about a Calc function to evaluate string expressions and thought it would be perfect to do an RPN calculator implementation in AutoIT so here it is:This UDF supports the following operators:+ - * / ^and formulas:MOD SIN COS TAN ASIN ACOS ATAN SQRT LOG EXPIt doesn't check for well-formed expressions. That means it's up to you to check for things such as matching brackets... in your infix expression before passing it to _CalcRPNFor more information on Reverse Polish Notation, look hereEDIT1: added some commentsEDIT2: added some more commentsEDIT3: added support for formulasEDIT4: streamlined the operand/formula parsing section to support non decimal values so ezzetabi can add his functions EDIT5: Fixed a bug with number conversion. Now we convert to number, if required, at eval time. This way we preserve non-decimal characters such as hex strings. However, this means that it's now up to you to convert operand(s) to a format that's compatible with your formula or operator.expandcollapse popupDim $n1, $n2 ; usage example ; calculate using AutoIT $n1 = (Log(1000+5*6)*Exp(ACos(5))/Sqrt(8))*(Sin(1)*Cos(1)*Tan(1))/(5*(20-7+Mod(20,35))) ; calculate using _CalcRPN $n2 = _CalcRPN("(Log(1000+5*6)*Exp(ACos(5))/Sqrt(8))*(Sin(1)*Cos(1)*Tan(1))/(5*(20-7+Mod(20,35)))") ; both results should match MsgBox(4096, "Test" , "AutoIT = " & $n1 & @LF & _ "_CalcRPN = " & $n2);### Debug MSGBOX ; remove value from stack Func _PopStack(ByRef $vaStack) Local $vValue If Not IsArray($vaStack) Then SetError(1) ; invalid stack Else $vValue = $vaStack[UBound($vaStack)-1] If UBound($vaStack) > 1 Then ReDim $vaStack[UBound($vaStack)-1] $vaStack[0] = UBound($vaStack)-1 Else $vaStack[0] = 0 EndIf EndIf Return $vValue EndFunc ; add value to stack Func _PushStack(ByRef $vaStack, $vValue) If Not IsArray($vaStack) Then SetError(1) ; invalid stack Return 0 EndIf ReDim $vaStack[UBound($vaStack)+1] $vaStack[UBound($vaStack)-1] = $vValue ; first element contains stack count $vaStack[0] = UBound($vaStack)-1 Return 1 EndFunc ; Reverse Polish Notation calculator Func _CalcRPN($sInfix) Local $sOps = "+-*/^" Local $sFormulas = "MOD SIN COS TAN ASIN ACOS ATAN SQRT LOG EXP" Local $vaStack1[1] Local $vaStack2[1] Local $sChar Local $sNextChar Local $n, $i Local $nOperand1 Local $nOperand2 Local $sOp $sInfix = StringStripWS($sInfix, 8) For $n = 1 To StringLen($sInfix) $sChar = StringMid($sInfix, $n, 1) If (Asc($sChar) >= 48 And Asc($sChar) <= 57) Or _ (Asc($sChar) >= 65 And Asc($sChar) <= 90) Or _ (Asc($sChar) >= 97 And Asc($sChar) <= 122) Or _ $sChar = "." Then ; if alphanumeric character, assume operand or formula ; get remaining characters While $n <= StringLen($sInfix) $sNextChar = StringMid($sInfix, $n+1, 1) If (Asc($sNextChar) >= 48 And Asc($sNextChar) <= 57) Or _ (Asc($sNextChar) >= 65 And Asc($sNextChar) <= 90) Or _ (Asc($sNextChar) >= 97 And Asc($sNextChar) <= 122) Or _ $sNextChar = "." Then $sChar = $sChar & $sNextChar $n = $n+1 Else ExitLoop EndIf WEnd If StringInStr($sFormulas, $sChar) Then ; push formula name into stack2 _PushStack($vaStack2, $sChar) Else ; push operand into stack1 _PushStack($vaStack1, $sChar) EndIf ElseIf $sChar = "(" Then ; push left bracket into stack2 _PushStack($vaStack2, $sChar) ElseIf $sChar = ")" Then ; pop operators from stack2 and push them into stack1 ; until left bracket is reached in stack2 While $vaStack2[0] > 0 And $vaStack2[$vaStack2[0]] <> "(" _PushStack($vaStack1, _PopStack($vaStack2)) WEnd ; pop left bracket from stack2 If $vaStack2[$vaStack2[0]] = "(" Then _PopStack($vaStack2) Else ; get position of operator. Higher position = higher precedence $i = StringInStr($sOps, $sChar) If $i > 0 Then ; pop higher precedence operators and formulas from stack2 ; and push them into stack1 While $vaStack2[0] > 0 And _ StringInStr($sFormulas, $vaStack2[$vaStack2[0]]) > 0 Or _ StringInStr($sOps, $vaStack2[$vaStack2[0]]) >= $i _PushStack($vaStack1, _PopStack($vaStack2)) WEnd ; push current operator into stack2 _PushStack($vaStack2, $sChar) EndIf EndIf Next ; pop remaining operators from stack2 and push them into stack1 While $vaStack2[0] > 0 _PushStack($vaStack1, _PopStack($vaStack2)) WEnd ; clear stack2 Redim $vaStack2[1] ; copy stack1 to stack2 so the stack order is reversed For $n = $vaStack1[0] To 1 Step -1 _PushStack($vaStack2, $vaStack1[$n]) Next ; clear stack1 ReDim $vaStack1[1] While $vaStack2[0] > 0 If StringInStr($sOps, $vaStack2[$vaStack2[0]]) Or _ StringInStr($sFormulas, $vaStack2[$vaStack2[0]]) Then ; if top item is an operator or formula then pop it $sOp = _PopStack($vaStack2) Select Case $sOp = "+" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1+$nOperand2) Case $sOp = "-" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1-$nOperand2) Case $sOp = "*" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1*$nOperand2) Case $sOp = "/" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1/$nOperand2) Case $sOp = "^" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1^$nOperand2) Case $sOp = "MOD" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Mod($nOperand1, $nOperand2)) Case $sOp = "SIN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Sin($nOperand1)) Case $sOp = "COS" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Cos($nOperand1)) Case $sOp = "TAN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Tan($nOperand1)) Case $sOp = "ASIN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, ASin($nOperand1)) Case $sOp = "ACOS" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, ACos($nOperand1)) Case $sOp = "ATAN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, ATan($nOperand1)) Case $sOp = "SQRT" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Sqrt($nOperand1)) Case $sOp = "LOG" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Log($nOperand1)) Case $sOp = "EXP" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Exp($nOperand1)) EndSelect Else ; pop operand from stack2 and push into stack1 _PushStack($vaStack1, _PopStack($vaStack2)) EndIf WEnd ; the last remaining item in stack1 is the final result Return _PopStack($vaStack1) EndFuncAttached is the source file if you don't want to copy/pasteRpn.au3 Edited January 5, 2005 by pacman Link to comment Share on other sites More sharing options...
Josbe Posted December 22, 2004 Share Posted December 22, 2004 It looks very interesting. Excellent! • AUTOIT > AutoIt docs / Beta folder - AutoIt latest beta Link to comment Share on other sites More sharing options...
trids Posted December 23, 2004 Share Posted December 23, 2004 Hmmm .. Reverse Polish! Exciting looks, this does Link to comment Share on other sites More sharing options...
ezzetabi Posted December 23, 2004 Share Posted December 23, 2004 (edited) Thanks PacMan, as usual you are the best. Great program! Can I use this code in Run! ? Edited December 23, 2004 by ezzetabi Link to comment Share on other sites More sharing options...
SumTingWong Posted December 23, 2004 Author Share Posted December 23, 2004 Thanks PacMan, as usual you are the best. Great program!Can I use this code in Run! ?<{POST_SNAPBACK}>Of course, yours to do with as you please. Link to comment Share on other sites More sharing options...
layer Posted December 23, 2004 Share Posted December 23, 2004 hmmm, a little problem.. in my mathematics program, u recomend me using this little neat script, except it's like teh same thing as doing $lala= GUIRead ($something) $hehe= Number ($lala) MsgBox (0, "lala", $hehe) if i use it, it still returns weird numbers, i use it like this: Case $get=$button_26 Dim $n $n = GUIRead ($edit_23) $n = _CalcRPN($edit_23) GUICtrlSetData ($edit_23, $n, 1) lets just say all those undeclared variables in there are declared, it still returns the very wrong answer... suggestions? FootbaG Link to comment Share on other sites More sharing options...
SlimShady Posted December 23, 2004 Share Posted December 23, 2004 Duhh! Use this: Case $get=$button_26 $sum = GUIRead ($edit_23) $result = _CalcRPN($sum) GUICtrlSetData ($edit_23, $result, 1) I changed the variables because that's the only way to avoid these bugs. Link to comment Share on other sites More sharing options...
layer Posted December 23, 2004 Share Posted December 23, 2004 tanks slim im just a little tired today... FootbaG Link to comment Share on other sites More sharing options...
ezzetabi Posted December 30, 2004 Share Posted December 30, 2004 pacman. How do you think is the best way of adding operators that act over a single number? E.g. sin, cos, !, ect... Link to comment Share on other sites More sharing options...
SumTingWong Posted December 31, 2004 Author Share Posted December 31, 2004 (edited) pacman.How do you think is the best way of adding operators that act over a single number?E.g. sin, cos, !, ect...<{POST_SNAPBACK}>@ezzetabi - see my updated code above.I was bored at work yesterday so I started on coding a Reversi/Othello game in AutoIT. Got the UI done and been researching on a decent algorithm that I can implement in AutoIT but I can't decide. So far, I have looked at c sources for a combination of weighted board, alpha-beta, min-max but it's a pain trying to unravel and translate to AutoIT. Can anyone suggest a decent source for an average Reversi/Othello algo that can be implemented in AutoIT? Edited December 31, 2004 by pacman Link to comment Share on other sites More sharing options...
ezzetabi Posted January 4, 2005 Share Posted January 4, 2005 (edited) I added the toHex, toOct and toBin operators that converts decimal numbers to hex, oct and bin bases. I'd like to add also their opposites, like frOct and frBin that would convert non decimal values in decimal... But I can't find a way to detect if the letters are digits of hex numbers or operators... PacMan, do you have any suggestion? expandcollapse popupMsgBox(0, '', _CalcRPN('fat(7)')) Func _PopStack(ByRef $vaStack) Local $vValue If Not IsArray($vaStack) Then SetError(1); invalid stack Else $vValue = $vaStack[UBound($vaStack) - 1] If UBound($vaStack) > 1 Then ReDim $vaStack[UBound($vaStack) - 1] $vaStack[0] = UBound($vaStack) - 1 Else $vaStack[0] = 0 EndIf EndIf Return $vValue EndFunc ;==>_PopStack ; Add value to stack Func _PushStack(ByRef $vaStack, $vValue) If Not IsArray($vaStack) Then SetError(1); invalid stack Return 0 EndIf ReDim $vaStack[UBound($vaStack) + 1] $vaStack[UBound($vaStack) - 1] = $vValue ; first element contains stack count $vaStack[0] = UBound($vaStack) - 1 Return 1 EndFunc ;==>_PushStack ; Reverse Polish Notation calculator Func _CalcRPN($sInfix) Local $sOps = "+-*/^" Local $sFormulas = "MOD SIN COS TAN ASIN ACOS ATAN LOG EXP ToHex ToBin ToOct Fat" Local $vaStack1[1] Local $vaStack2[1] Local $sChar Local $sNextChar Local $n, $i Local $nOperand1 Local $nOperand2 Local $sOp Local $bNum = 0 $sInfix = StringStripWS($sInfix, 8) For $n = 1 To StringLen($sInfix) $sChar = StringMid($sInfix, $n, 1) If (Asc($sChar) >= 48 And Asc($sChar) <= 57) Or $sChar = "." Then ; if character is a digit or a dot, assume operand ; get operand While $n <= StringLen($sInfix) $sNextChar = StringMid($sInfix, $n + 1, 1) If (Asc($sNextChar) >= 48 And Asc($sNextChar) <= 57) Or $sNextChar = "." Then $sChar = $sChar & $sNextChar $n = $n + 1 Else ExitLoop EndIf Wend ; push operand into stack1 _PushStack($vaStack1, Number($sChar)) ElseIf (Asc($sChar) >= 65 And Asc($sChar) <= 90) Or (Asc($sChar) >= 97 And Asc($sChar) <= 122) Then ; if character is a letter, assume formula ; get formula name While $n <= StringLen($sInfix) $sNextChar = StringMid($sInfix, $n + 1, 1) If (Asc($sNextChar) >= 65 And Asc($sNextChar) <= 90) Or (Asc($sNextChar) >= 97 And Asc($sNextChar) <= 122) Then $sChar = $sChar & $sNextChar $n = $n + 1 Else ExitLoop EndIf Wend ; push formula name into stack2 _PushStack($vaStack2, $sChar) ElseIf $sChar = "(" Then ; push left bracket into stack2 _PushStack($vaStack2, $sChar) ElseIf $sChar = ")" Then ; pop operators from stack2 and push them into stack1 ; until left bracket is reached in stack2 While $vaStack2[0] > 0 And $vaStack2[$vaStack2[0]] <> "(" _PushStack($vaStack1, _PopStack($vaStack2)) Wend ; pop left bracket from stack2 If $vaStack2[$vaStack2[0]] = "(" Then _PopStack($vaStack2) Else ; get position of operator. Higher position = higher precedence $i = StringInStr($sOps, $sChar) If $i > 0 Then ; pop higher precedence operators and formulas from stack2 ; and push them into stack1 While $vaStack2[0] > 0 And _ StringInStr($sFormulas, $vaStack2[$vaStack2[0]]) > 0 Or _ StringInStr($sOps, $vaStack2[$vaStack2[0]]) >= $i _PushStack($vaStack1, _PopStack($vaStack2)) Wend ; push current operator into stack2 _PushStack($vaStack2, $sChar) EndIf EndIf Next ; pop remaining operators from stack2 and push them into stack1 While $vaStack2[0] > 0 _PushStack($vaStack1, _PopStack($vaStack2)) Wend ; clear stack2 ReDim $vaStack2[1] ; copy stack1 to stack2 so the stack order is reversed For $n = $vaStack1[0] To 1 Step - 1 _PushStack($vaStack2, $vaStack1[$n]) Next ; clear stack1 ReDim $vaStack1[1] While $vaStack2[0] > 0 If StringInStr($sOps, $vaStack2[$vaStack2[0]]) Or _ StringInStr($sFormulas, $vaStack2[$vaStack2[0]]) Then ; if top item is an operator or formula then pop it $sOp = _PopStack($vaStack2) Select Case $sOp = "+" ; pop the second operand $nOperand2 = _PopStack($vaStack1) ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 + $nOperand2) Case $sOp = "-" ; pop the second operand $nOperand2 = _PopStack($vaStack1) ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 - $nOperand2) Case $sOp = "*" ; pop the second operand $nOperand2 = _PopStack($vaStack1) ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 * $nOperand2) Case $sOp = "/" ; pop the second operand $nOperand2 = _PopStack($vaStack1) ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 / $nOperand2) Case $sOp = "^" ; pop the second operand $nOperand2 = _PopStack($vaStack1) ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 ^ $nOperand2) Case $sOp = "MOD" ; pop the second operand $nOperand2 = _PopStack($vaStack1) ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, Mod($nOperand1, $nOperand2)) Case $sOp = "SIN" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, Sin($nOperand1)) Case $sOp = "COS" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, Cos($nOperand1)) Case $sOp = "TAN" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, Tan($nOperand1)) Case $sOp = "ASIN" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, ASin($nOperand1)) Case $sOp = "ACOS" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, ACos($nOperand1)) Case $sOp = "ATAN" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, ATan($nOperand1)) Case $sOp = "LOG" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, Log($nOperand1)) Case $sOp = "EXP" ; pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, Exp($nOperand1)) Case $sOp = "ToHex" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Dec2Any($nOperand1, 16)) Case $sOp = "ToBin" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Dec2Any($nOperand1, 2)) Case $sOp = "ToOct" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Dec2Any($nOperand1, 8)) Case $sOp = "Fat" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Fat($nOperand1)) EndSelect Else ; pop operand from stack2 and push into stack1 _PushStack($vaStack1, _PopStack($vaStack2)) EndIf Wend ; the last remaining item in stack1 is the final result Return _PopStack($vaStack1) EndFunc ;==>_CalcRPN #region;_Any2Dec, _Dec2Any Func _Any2Dec($sNum, $iBase) If $iBase < 2 Or $iBase > 36 Then Return 0 $sNum = StringReplace($sNum, ' ', '') Local $iSep, $fOutPut = 0, $iDigit, $c, $iL, $bNeg = 0, $sValidDigits If StringLeft($sNum, 1) = '-' Then $bNeg = 1 $sNum = StringTrimLeft($sNum, 1) EndIf If $iBase <= 10 Then For $c = 0 to ($iBase - 1) $sValidDigits = $sValidDigits & '|' & $c Next $sValidDigits = StringTrimLeft($sValidDigits, 1) Else $sValidDigits = '0|1|2|3|4|5|6|7|8|9' For $c = 10 To $iBase - 1 $sValidDigits = $sValidDigits & '|' & Chr(55 + $c) Next EndIf If Not _Only($sNum, $sValidDigits & '|.') Then Return 0 EndIf $iSep = StringInStr($sNum, '.') If $iSep <> 0 Then $sNum = StringReplace($sNum, '.', '') $iSep = (StringLen($sNum) - $iSep + 1) * - 1 EndIf $iL = StringLen($sNum) For $c = 1 To StringLen($sNum) $iDigit = StringMid($sNum, $iL - $c + 1, 1) If Asc($iDigit) >= 65 Then $iDigit = Asc($iDigit) - 55 Else $iDigit = Int($iDigit) EndIf $fOutPut = $fOutPut + $iDigit * $iBase^ ($iSep + $c - 1) Next If $bNeg = 1 Then $fOutPut = $fOutPut * - 1 Return $fOutPut EndFunc ;==>_Any2Dec Func _Only($string, $aItems) $aItems = StringSplit($aItems, '|') Local $bOk, $c, $c2, $char For $c = 1 To StringLen($string) $char = StringMid($string, $c, 1) $bOk = 0 For $c2 = 1 To $aItems[0] If $aItems[$c2] = $char Then $bOk = 1 ExitLoop EndIf Next If $bOk = 0 Then Return 0 EndIf Next Return 1 EndFunc ;==>_Only Func _Dec2Any($sNum, $iBase) If $iBase < 2 Or $iBase > 36 Then Return 0 $sNum = StringReplace($sNum, ' ', '') Local $aParts[3], $iDigit, $sOutPut, $bNeg = 0 If StringLeft($sNum, 1) = '-' Then $bNeg = 1 $sNum = StringTrimLeft($sNum, 1) EndIf If StringInStr($sNum, '.') Then $aParts = StringSplit($sNum, '.') $aParts[1] = Int($aParts[1]) $aParts[2] = $aParts[2] / 10 ^ StringLen($aParts[2]) Else $aParts[1] = Int($sNum) $aParts[2] = 0 EndIf While $aParts[1] <> 0 $iDigit = Mod($aParts[1], $iBase) If $iDigit >= 10 Then $iDigit = Chr(55 + $iDigit);65 is A EndIf $sOutPut = $iDigit & $sOutPut $aParts[1] = Int($aParts[1] / $iBase) Wend If $aParts[2] <> 0 Then $sOutPut = $sOutPut & '.' While $aParts[2] <> 0 $aParts[2] = $aParts[2] * $iBase $iDigit = Int($aParts[2]) $aParts[2] = $aParts[2] - $iDigit If $iDigit >= 10 Then $iDigit = Chr(55 + $iDigit);65 is A EndIf $sOutPut = $sOutPut & $iDigit Wend EndIf If $bNeg = 1 Then $sOutPut = '-' & $sOutPut Return $sOutPut EndFunc ;==>_Dec2Any #endregion Func _Fat($iNum) If $iNum<=0 Then Return 0 $iNum = Int($iNum) Local $c, $iOutPut = 1 For $c = 2 to $iNum $iOutPut = $iOutPut * $c Next Return $iOutPut EndFunc Edited January 4, 2005 by ezzetabi Link to comment Share on other sites More sharing options...
SumTingWong Posted January 4, 2005 Author Share Posted January 4, 2005 (edited) @ezzetabi See my updated code above. I have re-uploaded the attachment as well if you don't want to copy/paste Good to see you are extending it with more functions. Edited January 4, 2005 by pacman Link to comment Share on other sites More sharing options...
ezzetabi Posted January 4, 2005 Share Posted January 4, 2005 Oh dear... You are indeed the best. If I'll ever go to London I'll drop a message, you deserve a gift... (The same in the case you come here to Italy, eh?) Link to comment Share on other sites More sharing options...
SumTingWong Posted January 4, 2005 Author Share Posted January 4, 2005 (edited) Oh dear... You are indeed the best.If I'll ever go to London I'll drop a message, you deserve a gift...(The same in the case you come here to Italy, eh?)<{POST_SNAPBACK}>@ezzetabiHave a look at my EDIT5 above for a small update which will affect you.My wife and I are going to Rome for a "romantic" weekend this coming weekend but no gifts are neccessary. I will just enjoy your beautiful country instead. Edited January 4, 2005 by pacman Link to comment Share on other sites More sharing options...
ezzetabi Posted January 4, 2005 Share Posted January 4, 2005 About edit5. I fixed the problem before reading it, but thanks about the 4th... I could not do it alone. About Rome, a fine city indeed... but a little too away from where am I for confortable gift giving... Well. I hope you enjoy your stay, welcome. Link to comment Share on other sites More sharing options...
ezzetabi Posted January 4, 2005 Share Posted January 4, 2005 (edited) And here the PacManEz Calculator! (Notice how the PacMan name prevales.... ) Next post of mine. Edited January 5, 2005 by ezzetabi Link to comment Share on other sites More sharing options...
SumTingWong Posted January 4, 2005 Author Share Posted January 4, 2005 Cool.... Have a look at my updated code because I think you need to do number conversion for at least some of the core ops and formulas. I couldn't get a correct value with my example expression when I took the number conversion out. Link to comment Share on other sites More sharing options...
ezzetabi Posted January 5, 2005 Share Posted January 5, 2005 (edited) AHAHAHAHAHAHAHAHAHAHAHAHAHAHAHAH I had all needed Number() but I think it was not the problem... The main problem is that I removed Sqrt()... I dislike Sqrt since it is just a bad copy of ^ expandcollapse popupDim $n1, $n2, $n3 ; usage example ; calculate using AutoIT $n1 = (Log(1000+5*6)*Exp(ACos(5))/8)*(Sin(1)*Cos(1)*Tan(1))/(5*(20-7+Mod(20,35))) ; calculate using _CalcRPN $n2 = _CalcRPN("(Log(1000+5*6)*Exp(ACos(5))/8)*(Sin(1)*Cos(1)*Tan(1))/(5*(20-7+Mod(20,35)))") ; both results should match $n3 = _CalcRPN('ToHex('&$n2&')') MsgBox(4096, "Test" , "AutoIT "&@tab&"= " & $n1 & @LF & _ "_CalcRPN"&@TAB&"= " & $n2 & @lf & _ 'In hex: '& @tab &'=' &$n3);### Debug MSGBOX #region;PacManEz Calculator ; Reverse Polish Notation calculator Func _CalcRPN($sInfix) Local $sOps = "+-*/^" Local $sFormulas = "MOD SIN COS TAN ASIN ACOS ATAN LOG EXP FAT ToHex ToBin ToOct FrHex FrOct FrBin" Local $vaStack1[1] Local $vaStack2[1] Local $sChar Local $sNextChar Local $n, $i Local $nOperand1 Local $nOperand2 Local $sOp Local $bNum = 0 $sInfix = StringStripWS($sInfix, 8) For $n = 1 To StringLen($sInfix) $sChar = StringMid($sInfix, $n, 1) If (Asc($sChar) >= 48 And Asc($sChar) <= 57) Or _ (Asc($sChar) >= 65 And Asc($sChar) <= 90) Or _ (Asc($sChar) >= 97 And Asc($sChar) <= 122) Or _ $sChar = "." Then ; if alphanumeric character, assume operand or formula ; get remaining characters While $n <= StringLen($sInfix) $sNextChar = StringMid($sInfix, $n+1, 1) If (Asc($sNextChar) >= 48 And Asc($sNextChar) <= 57) Or _ (Asc($sNextChar) >= 65 And Asc($sNextChar) <= 90) Or _ (Asc($sNextChar) >= 97 And Asc($sNextChar) <= 122) Or _ $sNextChar = "." Then $sChar = $sChar & $sNextChar $n = $n+1 Else ExitLoop EndIf WEnd If StringInStr($sFormulas, $sChar) Then ; push formula name into stack2 _PushStack($vaStack2, $sChar) Else ; push operand into stack1 ;_PushStack($vaStack1, Number($sChar)) _PushStack($vaStack1, $sChar) EndIf ElseIf $sChar = "(" Then ; push left bracket into stack2 _PushStack($vaStack2, $sChar) ElseIf $sChar = ")" Then ; pop operators from stack2 and push them into stack1 ; until left bracket is reached in stack2 While $vaStack2[0] > 0 And $vaStack2[$vaStack2[0]] <> "(" _PushStack($vaStack1, _PopStack($vaStack2)) WEnd ; pop left bracket from stack2 If $vaStack2[$vaStack2[0]] = "(" Then _PopStack($vaStack2) Else ; get position of operator. Higher position = higher precedence $i = StringInStr($sOps, $sChar) If $i > 0 Then ; pop higher precedence operators and formulas from stack2 ; and push them into stack1 While $vaStack2[0] > 0 And _ StringInStr($sFormulas, $vaStack2[$vaStack2[0]]) > 0 Or _ StringInStr($sOps, $vaStack2[$vaStack2[0]]) >= $i _PushStack($vaStack1, _PopStack($vaStack2)) WEnd ; push current operator into stack2 _PushStack($vaStack2, $sChar) EndIf EndIf Next ; pop remaining operators from stack2 and push them into stack1 While $vaStack2[0] > 0 _PushStack($vaStack1, _PopStack($vaStack2)) Wend ; clear stack2 ReDim $vaStack2[1] ; copy stack1 to stack2 so the stack order is reversed For $n = $vaStack1[0] To 1 Step - 1 _PushStack($vaStack2, $vaStack1[$n]) Next ; clear stack1 ReDim $vaStack1[1] While $vaStack2[0] > 0 If StringInStr($sOps, $vaStack2[$vaStack2[0]]) Or _ StringInStr($sFormulas, $vaStack2[$vaStack2[0]]) Then ; if top item is an operator or formula then pop it $sOp = _PopStack($vaStack2) Select Case $sOp = "+" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 + $nOperand2) Case $sOp = "-" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 - $nOperand2) Case $sOp = "*" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 * $nOperand2) Case $sOp = "/" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 / $nOperand2) Case $sOp = "^" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, $nOperand1 ^ $nOperand2) Case $sOp = "MOD" ; pop the second operand $nOperand2 = Number(_PopStack($vaStack1)) ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Mod($nOperand1, $nOperand2)) Case $sOp = "SIN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Sin($nOperand1)) Case $sOp = "COS" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Cos($nOperand1)) Case $sOp = "TAN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Tan($nOperand1)) Case $sOp = "ASIN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, ASin($nOperand1)) Case $sOp = "ACOS" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, ACos($nOperand1)) Case $sOp = "ATAN" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, ATan($nOperand1)) Case $sOp = "LOG" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Log($nOperand1)) Case $sOp = "EXP" ; pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, Exp($nOperand1)) Case $sOp = "ToHex" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Dec2Any($nOperand1, 16)) Case $sOp = "ToBin" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Dec2Any($nOperand1, 2)) Case $sOp = "ToOct" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Dec2Any($nOperand1, 8)) Case $sOp = "FrHex" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Any2Dec($nOperand1, 16)) Case $sOp = "FrBin" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Any2Dec($nOperand1, 2)) Case $sOp = "FrOct" ;pop the first operand $nOperand1 = _PopStack($vaStack1) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Any2Dec($nOperand1, 8)) Case $sOp = "Fat" ;pop the first operand $nOperand1 = Number(_PopStack($vaStack1)) ; perform calculation and push result into stack1 _PushStack($vaStack1, _Fat($nOperand1)) EndSelect Else ; pop operand from stack2 and push into stack1 _PushStack($vaStack1, _PopStack($vaStack2)) EndIf Wend ; the last remaining item in stack1 is the final result Return _PopStack($vaStack1) EndFunc ;==>_CalcRPN Func _PopStack(ByRef $vaStack) Local $vValue If Not IsArray($vaStack) Then SetError(1); invalid stack Else $vValue = $vaStack[UBound($vaStack) - 1] If UBound($vaStack) > 1 Then ReDim $vaStack[UBound($vaStack) - 1] $vaStack[0] = UBound($vaStack) - 1 Else $vaStack[0] = 0 EndIf EndIf Return $vValue EndFunc ;==>_PopStack ; Add value to stack Func _PushStack(ByRef $vaStack, $vValue) If Not IsArray($vaStack) Then SetError(1); invalid stack Return 0 EndIf ReDim $vaStack[UBound($vaStack) + 1] $vaStack[UBound($vaStack) - 1] = $vValue ; first element contains stack count $vaStack[0] = UBound($vaStack) - 1 Return 1 EndFunc ;==>_PushStack #endregion #region;Fatt func... Func _Fat($iNum) If $iNum<=0 Then Return 0 $iNum = Int($iNum) Local $c, $iOutPut = 1 For $c = 2 to $iNum $iOutPut = $iOutPut * $c Next Return $iOutPut EndFunc #endregion #region;_Any2Dec, _Dec2Any Func _Any2Dec($sNum, $iBase) If $iBase < 2 Or $iBase > 36 Then Return 0 $sNum = StringReplace($sNum, ' ', '') Local $iSep, $fOutPut = 0, $iDigit, $c, $iL, $bNeg = 0, $sValidDigits If StringLeft($sNum, 1) = '-' Then $bNeg = 1 $sNum = StringTrimLeft($sNum, 1) EndIf If $iBase <= 10 Then For $c = 0 to ($iBase - 1) $sValidDigits = $sValidDigits & '|' & $c Next $sValidDigits = StringTrimLeft($sValidDigits, 1) Else $sValidDigits = '0|1|2|3|4|5|6|7|8|9' For $c = 10 To $iBase - 1 $sValidDigits = $sValidDigits & '|' & Chr(55 + $c) Next EndIf If Not _Only($sNum, $sValidDigits & '|.') Then Return 0 EndIf $iSep = StringInStr($sNum, '.') If $iSep <> 0 Then $sNum = StringReplace($sNum, '.', '') $iSep = (StringLen($sNum) - $iSep + 1) * - 1 EndIf $iL = StringLen($sNum) For $c = 1 To StringLen($sNum) $iDigit = StringMid($sNum, $iL - $c + 1, 1) Select Case Asc($iDigit) >= 97 $iDigit = Asc($iDigit) - 87 CAse Asc($iDigit) >= 65 $iDigit = Asc($iDigit) - 55 Case Else $iDigit = Int($iDigit) EndSelect $fOutPut = $fOutPut + $iDigit * $iBase^ ($iSep + $c - 1) Next If $bNeg = 1 Then $fOutPut = $fOutPut * - 1 Return $fOutPut EndFunc;==>_Any2Dec Func _Only($string, $aItems) $aItems = StringSplit($aItems, '|') Local $bOk, $c, $c2, $char For $c = 1 To StringLen($string) $char = StringMid($string, $c, 1) $bOk = 0 For $c2 = 1 To $aItems[0] If $aItems[$c2] = $char Then $bOk = 1 ExitLoop EndIf Next If $bOk = 0 Then Return 0 EndIf Next Return 1 EndFunc;==>_Only Func _Dec2Any($sNum, $iBase) If $iBase < 2 Or $iBase > 36 Then Return 0 $sNum = StringReplace($sNum, ' ', '') Local $aParts[3], $iDigit, $sOutPut, $bNeg = 0 If StringLeft($sNum, 1) = '-' Then $bNeg = 1 $sNum = StringTrimLeft($sNum, 1) EndIf If StringInStr($sNum, '.') Then $aParts = StringSplit($sNum, '.') $aParts[1] = Int($aParts[1]) $aParts[2] = $aParts[2] / 10 ^ StringLen($aParts[2]) Else $aParts[1] = Int($sNum) $aParts[2] = 0 EndIf While $aParts[1] <> 0 $iDigit = Mod($aParts[1], $iBase) If $iDigit >= 10 Then $iDigit = Chr(55 + $iDigit);65 is A EndIf $sOutPut = $iDigit & $sOutPut $aParts[1] = Int($aParts[1] / $iBase) Wend If $aParts[2] <> 0 Then $sOutPut = $sOutPut & '.' While $aParts[2] <> 0 $aParts[2] = $aParts[2] * $iBase $iDigit = Int($aParts[2]) $aParts[2] = $aParts[2] - $iDigit If $iDigit >= 10 Then $iDigit = Chr(55 + $iDigit);65 is A EndIf $sOutPut = $sOutPut & $iDigit Wend EndIf If $bNeg = 1 Then $sOutPut = '-' & $sOutPut Return $sOutPut EndFunc;==>_Dec2Any #endregion Edited January 5, 2005 by ezzetabi Link to comment Share on other sites More sharing options...
NewKreation Posted January 22, 2008 Share Posted January 22, 2008 I love this script!Is there a way to support scientific notation?For example, 2e-1 currently gives the same result as 2-1.Can it be modified to ignore the "e/E"?Thank you kindly for the script. It is excellent as it stands. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now