## Recommended Posts

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 EXP

It 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 _CalcRPN

EDIT4: 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.

```Dim \$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 = UBound(\$vaStack)-1
Else
\$vaStack = 0
EndIf
EndIf
Return \$vValue
EndFunc

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 = 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
Local \$vaStack2
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 And \$vaStack2[\$vaStack2] <> "("
_PushStack(\$vaStack1, _PopStack(\$vaStack2))
WEnd
; pop left bracket from stack2
If \$vaStack2[\$vaStack2] = "(" 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 And _
StringInStr(\$sFormulas, \$vaStack2[\$vaStack2]) > 0 Or _
StringInStr(\$sOps, \$vaStack2[\$vaStack2]) >= \$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
_PushStack(\$vaStack1, _PopStack(\$vaStack2))
WEnd

; clear stack2
Redim \$vaStack2
; copy stack1 to stack2 so the stack order is reversed
For \$n = \$vaStack1 To 1 Step -1
_PushStack(\$vaStack2, \$vaStack1[\$n])
Next

; clear stack1
ReDim \$vaStack1

While \$vaStack2 > 0
If StringInStr(\$sOps, \$vaStack2[\$vaStack2]) Or _
StringInStr(\$sFormulas, \$vaStack2[\$vaStack2]) 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)
EndFunc```

Attached is the source file if you don't want to copy/paste

Rpn.au3

Edited by pacman

##### Share on other sites

It looks very interesting. Excellent! ##### Share on other sites

Hmmm .. Reverse Polish! Exciting looks, this does ##### Share on other sites

Thanks PacMan, as usual you are the best. Great program!

Can I use this code in Run! ?

Edited by ezzetabi

##### Share on other sites

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.

##### Share on other sites

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 = _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

##### Share on other sites

Duhh!

Use this:

```Case \$get=\$button_26

\$result = _CalcRPN(\$sum)
GUICtrlSetData (\$edit_23, \$result, 1)```

I changed the variables because that's the only way to avoid these bugs.

##### Share on other sites

tanks slim im just a little tired today...

FootbaG

##### Share on other sites

pacman.

How do you think is the best way of adding operators that act over a single number?

E.g. sin, cos, !, ect...

##### Share on other sites

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 by pacman

##### Share on other sites

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?

```MsgBox(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 = UBound(\$vaStack) - 1
Else
\$vaStack = 0
EndIf
EndIf
Return \$vValue
EndFunc  ;==>_PopStack

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 = 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
Local \$vaStack2
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 And \$vaStack2[\$vaStack2] <> "("
_PushStack(\$vaStack1, _PopStack(\$vaStack2))
Wend
; pop left bracket from stack2
If \$vaStack2[\$vaStack2] = "(" 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 And _
StringInStr(\$sFormulas, \$vaStack2[\$vaStack2]) > 0 Or _
StringInStr(\$sOps, \$vaStack2[\$vaStack2]) >= \$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
_PushStack(\$vaStack1, _PopStack(\$vaStack2))
Wend

; clear stack2
ReDim \$vaStack2
; copy stack1 to stack2 so the stack order is reversed
For \$n = \$vaStack1 To 1 Step - 1
_PushStack(\$vaStack2, \$vaStack1[\$n])
Next

; clear stack1
ReDim \$vaStack1

While \$vaStack2 > 0
If StringInStr(\$sOps, \$vaStack2[\$vaStack2]) Or _
StringInStr(\$sFormulas, \$vaStack2[\$vaStack2]) 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
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, \$iDigit, \$sOutPut, \$bNeg = 0

If StringLeft(\$sNum, 1) = '-' Then
\$bNeg = 1
\$sNum = StringTrimLeft(\$sNum, 1)
EndIf

If StringInStr(\$sNum, '.') Then
\$aParts = StringSplit(\$sNum, '.')
\$aParts = Int(\$aParts)
\$aParts = \$aParts / 10 ^ StringLen(\$aParts)
Else
\$aParts = Int(\$sNum)
\$aParts = 0
EndIf

While \$aParts <> 0
\$iDigit = Mod(\$aParts, \$iBase)
If \$iDigit >= 10 Then
\$iDigit = Chr(55 + \$iDigit);65 is A
EndIf
\$sOutPut = \$iDigit & \$sOutPut
\$aParts = Int(\$aParts / \$iBase)
Wend
If \$aParts <> 0 Then
\$sOutPut = \$sOutPut & '.'
While \$aParts <> 0
\$aParts = \$aParts * \$iBase
\$iDigit = Int(\$aParts)
\$aParts = \$aParts - \$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 by ezzetabi

##### Share on other sites

@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 by pacman

##### Share on other sites

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?)

##### Share on other sites

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}>

@ezzetabi

Have 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 by pacman

##### Share on other sites

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.

##### Share on other sites

And here the PacManEz Calculator!

(Notice how the PacMan name prevales.... )

Next post of mine.

Edited by ezzetabi

##### Share on other sites

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.

##### Share on other sites

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 ^

```Dim \$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
Local \$vaStack2
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 And \$vaStack2[\$vaStack2] <> "("
_PushStack(\$vaStack1, _PopStack(\$vaStack2))
WEnd
; pop left bracket from stack2
If \$vaStack2[\$vaStack2] = "(" 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 And _
StringInStr(\$sFormulas, \$vaStack2[\$vaStack2]) > 0 Or _
StringInStr(\$sOps, \$vaStack2[\$vaStack2]) >= \$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
_PushStack(\$vaStack1, _PopStack(\$vaStack2))
Wend

; clear stack2
ReDim \$vaStack2
; copy stack1 to stack2 so the stack order is reversed
For \$n = \$vaStack1 To 1 Step - 1
_PushStack(\$vaStack2, \$vaStack1[\$n])
Next

; clear stack1
ReDim \$vaStack1

While \$vaStack2 > 0
If StringInStr(\$sOps, \$vaStack2[\$vaStack2]) Or _
StringInStr(\$sFormulas, \$vaStack2[\$vaStack2]) 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 = UBound(\$vaStack) - 1
Else
\$vaStack = 0
EndIf
EndIf
Return \$vValue
EndFunc  ;==>_PopStack

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 = 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
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, \$iDigit, \$sOutPut, \$bNeg = 0

If StringLeft(\$sNum, 1) = '-' Then
\$bNeg = 1
\$sNum = StringTrimLeft(\$sNum, 1)
EndIf

If StringInStr(\$sNum, '.') Then
\$aParts = StringSplit(\$sNum, '.')
\$aParts = Int(\$aParts)
\$aParts = \$aParts / 10 ^ StringLen(\$aParts)
Else
\$aParts = Int(\$sNum)
\$aParts = 0
EndIf

While \$aParts <> 0
\$iDigit = Mod(\$aParts, \$iBase)
If \$iDigit >= 10 Then
\$iDigit = Chr(55 + \$iDigit);65 is A
&nbsp;    EndIf
\$sOutPut = \$iDigit & \$sOutPut
\$aParts = Int(\$aParts / \$iBase)
Wend
If \$aParts <> 0 Then
\$sOutPut = \$sOutPut & '.'
While \$aParts <> 0
\$aParts = \$aParts * \$iBase
\$iDigit = Int(\$aParts)
\$aParts = \$aParts - \$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 by ezzetabi

##### Share on other sites

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.

## Create an account

Register a new account

• ### Recently Browsing   0 members

×

• Wiki

• Back

• #### Beta

• Git
• FAQ
• Our Picks
×
• Create New...