martin Posted July 16, 2007 Share Posted July 16, 2007 (edited) EDIT:27th Jan 2008This was only intended as a 'mental' exercise to see how to do all this using recursion when I had some time to waste. It only reproduces what Execute can do much more simply and in only one line. I never fully tested this so I can't say how well it works. I hadn't expected anyone to copy it as the way to make a calculator. When I said below 'entirely in AutoIt' I meant using basic instructions to calculate a result without using Execute. At the time I even tried to make my own antilog function before I lost interest in the whole idea.Original post follows-There has been some interest in the online calculators but they all seem a bit restricted. Google for example doesn't know about Arcsin or Asin etc as far as I can see. Anyway, I thought there aught to be an example of a calculator which is entirely in Autoit, and I didn't find anything so here is an attempt.Not the most exciting script in the world and I'm already sick of it but it seems to work. It takes a string like "(3*12.7^3.63/7)*cos(41.9)" and returns the answer.expandcollapse popupConst $pi = 3.141592653589793, $pifactor = $pi/180; Global $stringtocalc,$splitcalc,$pp #region front end for demo While 1 $string= InputBox('enter the calculation to make','allowed operators and functions' _ & @LF & ' *, /, +, pi, sin(degrees), cos(degrees), tan(degrees), arcsin(degrees), ' _ & @CR & 'arccos(degrees), arctan(degrees), ^, (, ) ' _ & @CR & @CR & ' Eg ((45- 3^2.6)/17)*cos(23.7)',"","",450,200) If $string = '' Then Exit $string = StringStripWS($string,8) If StringRight($string,1) = '=' Then $string = StringMid($string,1,StringLen($string)-1) EndIf MsgBox(0,$string & ' = ',calculate($string)) ;MsgBox(0,antilog(Log($String)),Exp(Log($string))) WEnd #endregion front end for demo ;rest of script is the calculator function ;return the clulcation result of $stringin ;very little error checking, just a sample to show a way to make a calculator Func calculate($stringin) $stringin = StringUpper($stringin) $stringin = StringReplace($stringin,'^','**') $stringin = StringReplace($stringin,'#','+') $stringtocalc = $stringin & '=' $splitcalc = StringSplit($stringtocalc,"") $pp = 1 Return compute(0,0) EndFunc func compute($actual,$rank); Local $mtt,$tem1,$tem2,$pnum2,$bracketset,$f1,$f2,$dum $tem1=0; ;$tem2=0; $bracketset=0; if ($actual > 2) then $actual = 2; while(True) $pp += 1; Switch $splitcalc[$pp-1] Case ' ' ;ignore Case 'S' ;sin? ConsoleWrite('got the s for sin' &@CRLF) If StringMid($stringtocalc,$pp - 1,3) = "SIN" then $pp += 2 $tem1 = sin($pifactor * compute($actual,3)); EndIf Case 'T';tan? If StringMid($stringtocalc,$pp - 1,3) = "TAN" then $pp += 2 $tem1 = Tan($pifactor * compute($actual,3)); EndIf If $pp < $splitcalc[0] Then while( $splitcalc[$pp] = '.') or StringIsDigit($splitcalc[$pp]) $pp += 1; WEnd EndIf Case 'A' If StringMid($stringtocalc,$pp - 1,6) = "ARCTAN" then $pp += 5; $tem1 = atan(compute($actual,3))/$pifactor; elseif StringMid($stringtocalc,$pp - 1,6) = 'ARCSIN' then $pp += 4; ConsoleWrite('at arcsin pp = ' & $splitcalc[$pp] & @CRLF) $mtt = compute($actual,3); ConsoleWrite('$mtt = ' & $mtt & @CRLF) $tem1 = ASin($mtt)/$pifactor; elseif (StringMid($stringtocalc,$pp - 1,6) = 'ARCCOS') then $pp += 5 $tem1 = ACos(compute($actual,3))/$pifactor; EndIf If $pp < $splitcalc[0] Then while( $splitcalc[$pp] = '.') or StringIsDigit($splitcalc[$pp+1]) $pp += 1; {get past the Add bit} WEnd EndIf Case 'P';pi? if ($splitcalc[$pp] = 'I') then $tem1 = $PI; $pp += 1; Case 'C';cos? if StringMid($stringtocalc,$pp - 1,3) = 'COS' then $pp += 2 $tem1 = cos($pifactor * compute($actual,3)); EndIf Case '(' $bracketset = 1; $tem1 = compute($actual,0); Case ')' if ($bracketset = 1) then $bracketset = 0 else $pp -= 1; $result = $tem1; Return $result EndIf Case '/' if ($rank >= 2) then $pp -= 1; $result = $tem1; Return $result else $tem2 = compute($actual,2); if ($tem2 = 0) then MsgBox(0,'Error','divide by 0!'); $divzero = True; $result = 0; Return $result; else $tem1 = $tem1/$tem2; EndIf EndIf Case '*' if $splitcalc[$pp] = '*' then ;exponent required $pp += 1;point to exp ConsoleWrite('actual for power = ' & $splitcalc[$pp] & @CRLF) If $splitcalc[$pp] = '-' Then $pp += 1 $tem2 = -compute($actual,4) ElseIf $splitcalc[$pp] = '+' Then $pp += 1 $tem2 = compute($actual,4) Else $tem2 = compute($actual,4); EndIf $tem1 = Power($tem1,$tem2); ;Return $tem1 else if ($rank >= 3) then $pp -= 1; $result = $tem1; Return $result; else $mtt = compute($actual,3); $tem1 = $tem1 * $mtt; EndIf; EndIf; Case '+' if ($rank >= 1) then $pp -= 1; $result = $tem1; Return $result else $tem1 = $tem1 + compute($actual,1); EndIf; Case '-'; consolewrite('rank= ' & $rank & '$tem =' & $tem1 & @CRLF) if ($rank >= 1) then $pp -= 1 $result = - $tem1; Return $result else $tem1 = $tem1 - compute($actual,1); EndIf; Case '=' ;{CR LF NULL} $pp -= 1;{set back to end of line or compute will go crashing through the comments} $result = $tem1; if ($bracketset = 1)then MsgBox(0,'ERROR','Unmatched brackets') EndIf; Return $result Case '0' To '9'; $pp -= 1; $pnum2 = $pp; while( $splitcalc[$pp] = '.') or StringIsDigit($splitcalc[$pp]) $pp += 1; WEnd $tem1 = StringMid($stringtocalc,$pnum2,$pp-$pnum2) Case '.' ; $pp -= 1; $pnum2 = $pp; while( $splitcalc[$pp] = '.') or StringIsDigit($splitcalc[$pp]) $pp += 1; WEnd $tem1 = StringMid($stringtocalc,$pnum2,$pp-$pnum2) Case ',';this bit doesn't work yet ;$pp -= 1; $result = $tem1; Return $result EndSwitch; wend; #region #endregion EndFunc; Func Max($a,$B) ConsoleWrite('a,b = ' & $a & ', ' & $b & @CRLF) If $a > $b Then Return $a Return $b EndFunc Func Min($a,$B) ConsoleWrite('a,b = ' & $a & ', ' & $b & @CRLF) If $a < $b Then Return $a Return $b EndFunc Func power($a,$B) ConsoleWrite('a,b = ' & $a & ', ' & $b &@CRLF) ;returns $a to the power of $b If $a < 1 Then $sign = -1 Else $sign = 1 EndIf If $b = 0 Then Return $sign If $b < 0 Then Return $sign /Exp(Log($a)*$b*-1) Else Return $sign * Exp(Log($a)*$B) EndIf EndFuncEDIT: replaced experimental antilog function with exp. Removed Max & Min which didn't work, a some improvements. Edited January 27, 2008 by martin Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script. Link to comment Share on other sites More sharing options...
WeMartiansAreFriendly Posted July 17, 2007 Share Posted July 17, 2007 (edited) Well... I'd like to say this will come into use, great work. Edited July 17, 2007 by mrRevoked Don't bother, It's inside your monitor!------GUISetOnEvent should behave more like HotKeySet() Link to comment Share on other sites More sharing options...
zatorg Posted July 19, 2007 Share Posted July 19, 2007 This is nice because this can be used in other languages as well.. I mean AutoIt has Execute() but this is AutoIt-specific. Nice and thanks! Link to comment Share on other sites More sharing options...
Paulie Posted July 19, 2007 Share Posted July 19, 2007 Google for example doesn't know about Arcsin or Asin etc as far as I can see.go to google and type "asin(1)="You are correct in that it will not evaluate it if you just enter "asin(1)" but it forces it to calculate if you add a "=" on the end. 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