Search code examples
matlaboperator-precedence

Disregard mathematical precedence in MATLAB


Does anyone have any idea about how to make MATLAB take in a string suppose

f(x) = 3*x + 5*(2+100) ,where x = 5

But disregard all rules of precedence (including parenthesis) and solely calculate from left to right. So the answer to above would be 140 instead of 525

I was thinking that it would be along the lines of

[s,r] = strtok(myString,'0123456789');

put in a for loop but i haven't been able to figure out exactly how to do it.

Please Help! Thank You


Solution

  • Well, for a simple expression, one way to do it is to:

    • strip the expression of all the parenthesis
    • split the digits and the operators
    • rebuild an expression with parenthesis constructing a strict left to right precedence.

    Of course in your case we also first have to handle the case of the "function expression". It means detecting the "variable" (x in your case), and retrieving it value. So the code proposed get quite longer just because of that.

    It works fine on your example, and should be ok for different expressions as long as they respect the same style. In any case it will only works for function of one variable.

    You may have to add a few of the characters to ignore. Only parenthesis ( and ) are ignored at the moment, but you could add brackets [] and any other symbols that your expression may include and you want to ignore. (add that in the "Tidy up" paragraph.)

    %% // starting point
    myStr = 'f(x) = 3*x + 5*(2+100) ,where x = 5' ;
    
    %% // find "input variables" in the header
    strVar = regexp(myStr, '\(([^\)]+)\)' , 'tokens' , 'once' ) ;
    strVar = char(strVar) ;  %// =>  strVar='x'
    
    %% // isolate only the function expression (without the header or the x assignation )
    ibeg = strfind( myStr , '=' )+1 ;  %// ibeg= 7      find the last position of the expression
    iend = strfind( myStr , ',' )-1 ;  %// iend= 23     find the last position of the expression
    fstr = myStr(ibeg(1):iend(1)) ;    %// now fstr='3*x+5*(2+100)'   separate only function expression
    
    %% // get the value of the variable at the end of the expression
    var  = regexp( myStr(iend:end) , [ strVar '\s*=\s*(\d+)'] , 'tokens' ) ;
    %// then replace it in the function expression
    fstr = regexprep(fstr, ['(' strVar ')' ] , var{1} ) ; %// Now you function looks like this: "3*5 + 5*(2+100)"
    
    %% // THIS IS THE INTERESTING BIT
    %// everything before was only to extract the specific expression
    
    %% // now tidy up
    fstr(isspace(fstr)) = [] ;                              %// remove white space characters
    idx2remove = [ strfind(fstr,'(') strfind(fstr,')') ];   %// get indices of characters to ignore/remove
    fstr( idx2remove ) = [] ;                               %// Now you function looks like this: "3*5+5*2+100"
    
    %% // get the digits and the operators separately
    digits = regexp( fstr , '(\d+)' , 'tokens' ) ; %// extract the numbers
    oper   = regexp( fstr , '(\d+)' , 'split' ) ;  %// extract the operators
    oper   = oper(2:end) ;                         %// remove first empty cell
    
    %% // now rebuild the expression with pure left to right precedence
    strFinalFunction = [ '(' char(digits{1}) , char(oper{1}) , char(digits{2}) ')' ] ;
    for op = 3:length(digits)
        strFinalFunction = ['(' strFinalFunction char(oper{op-1}) char(digits{op}) ')'] ;
    end
    %// now your function look like: "((((3*5)+5)*2)+100)"
    result = eval( strFinalFunction ) %// then evaluate
    

    note: It will not work if your expression contains function (like cos or sqrt etc...). The power operator ^ will work though, and its precedence will also be overridden.