Sign in to follow this  
Followers 0
martin

a simple calculator function

4 posts in this topic

#1 ·  Posted (edited)

EDIT:27th Jan 2008

This 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.

Const $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

    
EndFunc

EDIT: replaced experimental antilog function with exp. Removed Max & Min which didn't work, a some improvements.

Edited 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.

Share this post


Link to post
Share on other sites



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! :whistle:

Share this post


Link to post
Share on other sites

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.

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  
Followers 0