Jump to content
Sign in to follow this  
darthwhatever

RPN Calculator

Recommended Posts

darthwhatever

Reverse Polish Notation (RPN) is a math notation in which each operator follows its two operands. I own an HP 48G calculator which uses RPN, and when I tried to use the windows calculator I had so much trouble that I wrote my own calculator. Basically, it has a stack of numbers; any time an operator is pressed, that operation is carried out immediately on the two items on the bottom of the stack, or the stack and the input if there is anything in the input. This method reduces the requirements for parenthesis and makes calculating equations/functions relatively easy: instead of

(sqrt(5+8))/(8*9)

you would enter

5 ENTER 8 + SQRT 8 ENTER 9 * /

Practical implications

Suggestions/advice/criticisms are greatly appreciated!

calc2.au3

Edited by darthwhatever
  • Like 1

[font=arial, sans-serif]How is education supposed to make me feel smarter? Besides, every time I learn something new, it pushes some old stuff out of my brain. Remember when I took that home winemaking course, and I forgot how to drive?[/font][font=arial, sans-serif]<div>This is how you annoy a web developer.</span>[/font]

Share this post


Link to post
Share on other sites
darthwhatever

Whoops. I was going to add the option for the user to add functions, but decided that was too much of a pain. Attached file is updated.


[font=arial, sans-serif]How is education supposed to make me feel smarter? Besides, every time I learn something new, it pushes some old stuff out of my brain. Remember when I took that home winemaking course, and I forgot how to drive?[/font][font=arial, sans-serif]<div>This is how you annoy a web developer.</span>[/font]

Share this post


Link to post
Share on other sites
TheAutomator

if you just type a minus:

---------------------------
AutoIt Error
---------------------------
Line 265  (File "calc2.au3"):
 
$aStack[uBound($aStack) - 1] -= $iLast
$aStack[^ ERROR
 
Error: Variable subscript badly formatted.
---------------------------
OK   
---------------------------
 
regards,
TheAutomator
Edited by TheAutomator

Share this post


Link to post
Share on other sites
DreamVB

Thank you for shareing this will help a lot as I am also trying to make a Math Evalulator for a project I am working on.


On Error Resume Pulling Hair Out.

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Similar Content

    • imitto
      By imitto
      Hello all!
      I use Autoit for a while, already made some automation for a TV station's master control room with it. I made a UDF to easily work with PAL timecode and time with milliseconds, convert, add or subtract them. Feel free to use it if you want something like this
      #Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Res_Description=PAL Timecode Calculator UDF #AutoIt3Wrapper_Res_LegalCopyright=horvath.imre@gmail.com #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ; ; #FUNCTION# ; Name...........: _tcAdd ; Description....: Returns addition of two timecodes ; Syntax.........: _tcAdd($fTc1, fTc2 [, $fFormat = "P"]) ; ; Parameters.....: $fTc1 - First timecode in hh:mm:ss.ff format ; $fTc2 - Second timecode in hh:mm:ss.ff format ; $fFormat - Time base - "P" (default): PAL (25 fps) ; "M" : millisecond ; ; Return value...: Sum of the two timecode in the selected format Func _tcAdd($fTc1, $fTc2, $fFormat = "P", $fHourFormat = 1) Local $fMs1 = _tcToMs($fTc1) Local $fMs2 = _tcToMs($fTc2) Local $fSumMs = $fMs1 + $fMs2 Return _msToTc($fSumMs, $fFormat, $fHourFormat) EndFunc ; #FUNCTION# ; Name...........: _tcsSub ; Description....: Returns addition of two timecodes ; Syntax.........: _tcSub($fTc1, fTc2 [, $fFormat = "P"]) ; ; Parameters.....: $fTc1 - First timecode in hh:mm:ss.ff format ; $fTc2 - Second timecode in hh:mm:ss.ff format ; $fFormat - Time base - "P" (default): PAL (25 fps) ; "M" : millisecond ; ; Return value...: Subtract $fTc2 from $fTc1 in the source format Func _tcSub($fTc1, $fTc2, $fFormat = "P") Local $fMs1 = _tcToMs($fTc1) Local $fMs2 = _tcToMs($fTc2) Local $fSumMs = $fMs1 - $fMs2 If $fSumMs < 0 Then $fSumMs = _tcToMs("24:00:00.00") - ($fSumMs * -1) EndIf Return _msToTc($fSumMs, $fFormat) EndFunc ; #FUNCTION# ; Name...........: _tcToMs ; Description....: Returns timecode converted to total milliseconds ; Syntax.........: _tcToMs($fTc) ; ; Parameters.....: $fTc - Timecode in hh:mm:ss.ff or hh:mm:ss:xxx format, where xxx are milliseconds ; ; Return value...: Milliseconds as an integer value Func _tcToMs($fTc) Local $fTemp = StringSplit($fTc, ":.") Local $fChr = StringLen($fTemp[4]) Switch $fChr Case 2 Return ($fTemp[4] * 40) + ($fTemp[3] * 1000) + ($fTemp[2] * 60000) + ($fTemp[1] * 3600000) Case 3 Return ($fTemp[4]) + ($fTemp[3] * 1000) + ($fTemp[2] * 60000) + ($fTemp[1] * 3600000) EndSwitch EndFunc ; #FUNCTION# ; Name...........: _msToTc ; Description....: Converts total milliseconds to timecode ; Syntax.........: _msToTc($fIn, $fFormat = "P", $fHourFormat = 1) ; ; Parameters.....: $fIn - Time in milliseconds ; $fFormat - Output format "P": PAL TC (default) ; "M": hh:mm:ss.xxx where xxx are milliseconds ; $fHourFormat - Hour format "1": max. value is 23, then starts from 0 (default) ; "0": hours can be more then 23 ; ; Return value...: Timecode as string in the selected format Func _msToTc($fIn, $fFormat = "P", $fHourFormat = 1) Switch $fFormat Case "P" Local $fFr = StringFormat("%02i", (StringRight($fIn, 3) - Mod(StringRight($fIn, 3), 40)) / 40) Case "M" Local $fFr = StringFormat("%03i", StringRight($fIn, 3)) EndSwitch $fIn = StringTrimRight($fIn, 3) Local $fSec = StringFormat("%02i", Mod($fIn, 60)) $fIn -= $fSec Local $fMinTot = $fIn / 60 Local $fMin = StringFormat("%02i", Mod($fMinTot, 60)) $fIn -= $fMin*60 Local $fHourTot = $fIn / 60 / 60 Switch $fHourFormat Case 1 $fHour = StringFormat("%02i", Mod($fHourTot, 24)) Case 0 $fHour = StringFormat("%02i", $fHourTot) EndSwitch Return($fHour & ":" & $fMin & ":" & $fSec & "." & $fFr) EndFunc ; #FUNCTION# ; Name...........: _tcFormatChange ; Description....: Toggle TC format ; Syntax.........: _tcFormatChange($fTc) ; ; Parameters.....: $fTc - Timecode in hh:mm:ss.ff or hh:mm:ss:xxx format, where xxx are milliseconds ; ; Return value...: PAL timecode or time with milliseconds as string, depends on input Func _tcFormatChange($fTc) Local $fTemp = StringSplit($fTc, ":.") Local $fChr = StringLen($fTemp[4]) Switch $fChr Case 2 Return $fTemp[1]&":"&$fTemp[2]&":"&$fTemp[3]&"."&StringFormat("%03i", $fTemp[4]*40) Case 3 Return $fTemp[1]&":"&$fTemp[2]&":"&$fTemp[3]&"."&StringFormat("%02i", ($fTemp[4]-Mod($fTemp[4], 40))/40) EndSwitch EndFunc And the example script:
      #include<_PAL_TC_Calc.au3> $palTC1 = "00:01:12.20" $palTC2 = "23:59:50.02" $msTC1 = "00:01:12.800" $msTC2 = "23:59:50.120" MsgBox(0, "1", _tcAdd($palTC1, $palTC2)); Adds $palTC1 to $palTC2, turns hour back to 0 after 23, returns PAL TC format MsgBox(0, "2", _tcAdd($palTC1, $palTC2, "M")); Adds $palTC1 to $palTC2, turns hour back to 0 after 23, returns time with milliseconds format MsgBox(0, "3", _tcAdd($palTC1, $palTC2, "M", 0)); Adds $palTC1 to $palTC2, hours can be infinite, returns time with milliseconds format MsgBox(0, "4", _tcAdd($msTC1, $msTC2)); Adds $palTC1 to $palTC2, turns hour back to 0 after 23, returns PAL TC format MsgBox(0, "5", _tcAdd($msTC1, $msTC2, "M")); Adds $palTC1 to $palTC2, turns hour back to 0 after 23, returns time with milliseconds format MsgBox(0, "6", _tcAdd($msTC1, $msTC2, "M", 0)); Adds $palTC1 to $palTC2, hours can be infinite, returns time with milliseconds format MsgBox(0, "7", _tcSub($palTC2, $palTC1)); Subtract $palTC1 from $palTC2, returns PAL TC format MsgBox(0, "8", _tcSub($palTC2, $palTC1, "M")); Subtract $palTC1 from $palTC2, time with milliseconds format MsgBox(0, "9", _tcSub($msTC1, $msTC2)); Subtract $palTC1 from $palTC2, returns PAL TC format - when hits zero, counts back from 24:00:00.00 MsgBox(0, "10", _tcSub($msTC1, $msTC2, "M")); Subtract $palTC1 from $palTC2, time with milliseconds format - when hits zero, counts back from 24:00:00.000 MsgBox(0, "11", _tcFormatChange($palTC2)); Convert PAL TC to time with milliseconds and back MsgBox(0, "12", _tcFormatChange($msTC2)); Convert PAL TC to time with milliseconds and back  
      TC_CALC_example.au3
      _PAL_TC_Calc.au3
    • TheAutomator
      By TheAutomator
      hi everyone!
      I need some help with my rpn calculator.
      I first translated it from vbscript to autoitscript and that's when i stumbled on problem one:
      (46) : ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
      $Stack[ubound($Stack)] = $Item
      ^ ERROR
      After that (and i know this from testing it as a vbscript) it can't work with negative numbers:
      "1 - - 2" to Reverse Polish notation = "1 - 2 -" gives me the build in error...
       
      Can you guy's help me with my code pleas?
      Func Print($what,$er = 0) $t = '' if $err <> 0 then $t = 'ERROR!' MsgBox($er,$st,$what) EndFunc Func RPN($Tokenarray) Local $Stack = [] Local $Result Local $Operator_B Local $Operator_A For $Token = 0 To Ubound($Tokenarray) If Isoperator($Tokenarray[$Token]) Then $Operator_B = Pop($Stack) $Operator_A = Pop($Stack) If $Operator_A = "" Then Print("The user has not input sufficient values in the expression.",16) exit EndIf Switch $Tokenarray[$Token] Case "+" $Result = Number($Operator_A,3) + Number($Operator_B,3) Case "-" $Result = Number($Operator_A,3) - Number($Operator_B,3) Case "*" $Result = Number($Operator_A,3) * Number($Operator_B,3) Case "/" $Result = Number($Operator_A,3) / Number($Operator_B,3) Case "^" $Result = Number($Operator_A,3) ^ Number($Operator_B,3) EndSwitch Push($Result,$Stack) Else Push($Tokenarray[$Token],$Stack) EndIf Next If Ubound($Stack) > 1 Then Print("The user input has too many values.",16) Exit EndIf Return pop($Stack) EndFunc Func Push($Item, Byref $Stack) If Ubound($Stack) > -1 Then Redim $Stack[Ubound($Stack) + 1] $Stack[Ubound($Stack)] = $Item Else Local $Stack = [$Item] EndIf EndFunc Func Pop($Stack) $pop = "" If Ubound($Stack) > -1 Then $Pop = $Stack[Ubound($Stack)] Redim $Stack[Ubound($Stack) - 1] EndIf Return $pop EndFunc Func Peek($Stack) $peek = "" If Ubound($Stack) > -1 Then $Peek = $Stack(Ubound($Stack)) EndIf Return $peek EndFunc Func Isoperator($Operator) Return StringInstr("+-*/^&<=>", $Operator) <> 0 And StringLen($Operator) = 1 EndFunc Func Precedence($Operator) If Isoperator($Operator) Then Switch $Operator case "^" Return 4 case "*","/" Return 3 case "+","-" Return 2 case "&" Return 1 case "<","=",">" Return 0 EndSwitch EndIf EndFunc ;################################################################################################## ; (4 - -5) = (4|-|-|5) = (4|-|5|-) ; input tokens rpn Global $calculate_this = ["4","-","5","-"] Print(rpn($calculate_this)) thanks in advance ,
      TheAutomator
    • guinness
      By guinness
      I initially created this to improve my C# understanding and what a learning curve it was. So I decided to directly translate the C# source code I had into AutoIt as a way of showing off the >Stack UDF (which you will need). Of course it can be changed not to use the Stack UDF, but why reinvent the wheel and make life even more difficult.
       
      If you don't understand RPN or the Shunting-Yard algorithm, then please look at the links below.
       
      Sources: https://en.wikipedia.org/wiki/Shunting_yard_algorithm, https://en.wikipedia.org/wiki/Reverse_Polish_notation and http://www.slideshare.net/grahamwell/shunting-yard

      #include <StringConstants.au3> #include "Stack.au3" Example() Func Example() ; Create postfix notation (RPN) from infix notation. ConsoleWrite(StringFormat('%s: == %s', '3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3', ShuntingYard_Parse('3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3')) & @CRLF) ConsoleWrite('Reference: 3 4 2 * 1 5 - 2 3 ^ ^ / +' & @CRLF) ConsoleWrite(@CRLF); A new line. ConsoleWrite(StringFormat('%s: == %s', '3 + 4', ShuntingYard_Parse('3 + 4')) & @CRLF) ConsoleWrite('Reference: 3 4 +' & @CRLF) ConsoleWrite(@CRLF); A new line. ; Expression from: http://www.slideshare.net/grahamwell/shunting-yard. ConsoleWrite(StringFormat('%s: == %s', '2 + (3 * (8 - 4))', ShuntingYard_Parse('2 + (3 * (8 - 4))')) & @CRLF) ConsoleWrite('Reference: 2 3 8 4 - * +' & @CRLF) ConsoleWrite(@CRLF); A new line. ; Calculate postfix notation (RPN) examples. ConsoleWrite('3 4 + == ' & ShuntingYard_Calculate('3 4 +') & @CRLF) ConsoleWrite('3 4 2 * 1 5 - 2 3 ^ ^ / + == ' & ShuntingYard_Calculate('3 4 2 * 1 5 - 2 3 ^ ^ / +') & @CRLF) ConsoleWrite('2 3 8 4 - * + == ' & ShuntingYard_Calculate('2 3 8 4 - * +') & @CRLF) EndFunc ;==>Example Func ShuntingYard_Calculate($sExpression) Local $aChar = StringSplit($sExpression, '', $STR_NOCOUNT), _ $hStack = Stack(), _ ; Create a stack to push/pop to. $iNumber1 = 0, $iNumber2 = 2, _ $sDigits = '', _ ; Hold string digits e.g. in case there are numbers greater than 1 digit long. $sToken = '' ; Token. For $i = 0 To UBound($aChar) - 1 $sToken = $aChar[$i] If StringIsDigit($sToken) Then $sDigits &= $sToken ElseIf __ShuntingYard_IsOperator($sToken) Then $iNumber2 = Stack_Pop($hStack) $iNumber1 = Stack_Pop($hStack) Stack_Push($hStack, __ShuntingYard_Eval($iNumber1, $iNumber2, $sToken)) ElseIf StringIsSpace($sToken) And Not ($sDigits == '') Then If StringIsInt($sDigits) Or StringIsFloat($sDigits) Then $iNumber1 = Number($sDigits) Stack_Push($hStack, $iNumber1) EndIf $sDigits = '' $iNumber1 = 0 EndIf Next Return Stack_Pop($hStack) EndFunc ;==>ShuntingYard_Calculate Func ShuntingYard_Parse($sExpression) Local $aChar = StringSplit($sExpression, '', $STR_NOCOUNT), _ $bIsBracket = False, _ ; Is parenthesis. $hStack = Stack(), _ ; Create a stack to push/pop to. $sOutput, _ ; Output string. $sToken = '' ; Token. For $i = 0 To UBound($aChar) - 1 $sToken = $aChar[$i] If StringIsDigit($sToken) Then ; If a digit add to the output string. $sOutput &= $sToken ElseIf __ShuntingYard_IsOperator($sToken) Then ; Check if a valid token. If __ShuntingYard_IsBracket($sToken) Then $bIsBracket = $sToken == '(' ; True if open bracket else False if closing. If $bIsBracket Then ; Open bracket. Stack_Push($hStack, $sToken) Else ; Closing bracket. $sOutput &= ' ' Do ; Repeat until '(' is found. $sOutput &= Stack_Pop($hStack) Until (Stack_Peek($hStack) == '(') Stack_Pop($hStack) EndIf Else $sOutput &= " " ; Workaround for spacing and certain expressions. If Stack_Count($hStack) > 0 And __ShuntingYard_HasHigherPrecedence($sToken, Stack_Peek($hStack)) Then $sOutput &= Stack_Pop($hStack) Stack_Push($hStack, $sToken) $sOutput &= " " ; Workaround for spacing and certain expressions. Else Stack_Push($hStack, $sToken) EndIf EndIf EndIf Next If Stack_Count($hStack) > 0 Then ; Append what is left on the stack in reverse order. $sOutput &= ' ' While (Stack_Count($hStack) > 0) $sOutput &= Stack_Pop($hStack) & ' ' WEnd EndIf Return $sOutput EndFunc ;==>ShuntingYard_Parse Func __ShuntingYard_Eval($iNumber1, $iNumber2, $sChar) Switch $sChar Case '+' Return $iNumber1 + $iNumber2 Case '-', ChrW(8722) ; Char 8722 is - but the unicode char code Return $iNumber1 - $iNumber2 Case '*' Return $iNumber1 * $iNumber2 Case '/' Return $iNumber1 / $iNumber2 Case '^' Return $iNumber1 ^ $iNumber2 Case Else Return $iNumber1 EndSwitch EndFunc ;==>__ShuntingYard_Eval Func __ShuntingYard_HasHigherPrecedence($sChar1, $sChar2) Local $iChar1 = __ShuntingYard_PrecendenceValue($sChar1), _ $iChar2 = __ShuntingYard_PrecendenceValue($sChar2) If $iChar1 = 0 And $iChar2 = 0 Then Return False EndIf Return $iChar1 <= $iChar2 And Not ($sChar1 == '^') EndFunc ;==>__ShuntingYard_HasHigherPrecedence Func __ShuntingYard_IsBracket($sChar) Return $sChar == '(' Or $sChar == ')' EndFunc ;==>__ShuntingYard_IsBracket Func __ShuntingYard_IsOperator($sChar) Return $sChar == '+' Or $sChar == '-' Or $sChar == ChrW(8722) Or $sChar == '*' Or $sChar == '/' Or $sChar == '^' Or $sChar == '(' Or $sChar == ')'; Char 8722 is - but the unicode char code. EndFunc ;==>__ShuntingYard_IsOperator Func __ShuntingYard_PrecendenceValue($sChar) Switch $sChar Case '+', '-' Return 2 Case '*', '/' Return 3 Case '^' Return 4 Case Else Return 0 EndSwitch EndFunc ;==>__ShuntingYard_PrecendenceValue
    • careca
      By careca
      Ohm's Law Calculator, clear the field you need to calculate, power may give out zero, if both fields of power and amps are empty, clear power, and try again.
×