...

View Full Version : caret (^) to pow() function

djh101
02-28-2012, 08:32 AM
Having to work with derivatives a lot, I made this nice, simple function for converting a^b form exponents in strings to eval'able pow(a,b) form. Enjoy. :)

function carToPow(\$expression){
//array of positions: start of base, position of ^, end of power
\$pos = array(null,null,null);
//array of parts: base and power
\$parts = array();

for(\$i=0; \$i<strlen(\$expression); \$i++){

if(\$expression[\$i] === '^'){
\$pos[1] = \$i;

//scan for base
if(\$expression[\$i-1] === ')'){ //base is a function
\$depth = 0;
for(\$j=\$i-1; \$j >= 0; \$j--){
if(\$expression[\$j] === ')') \$depth++;
if(\$expression[\$j] === '(') \$depth--;
if(\$depth == 0){
\$pos[0] = \$j;
\$parts[0] = substr(\$expression, \$j, \$i-\$j);
break;
}
}
} else if(\$expression[\$i-1] === 'x'){ //base is a variable
\$pos[0] = \$i-1;
\$parts[0] = "x";
} else { //base is a number
if(preg_match("/\\d*\\.{0,1}\\d+\\^/",\$expression,\$foo)){
\$pos[0] = \$i - strlen(\$foo[0]) + 1;
\$parts[0] = substr(\$foo[0],0,strlen(\$foo[0])-1);
} else return false;
}

//scan for power
if(\$expression[\$i+1] === '('){ //power is a function
\$depth = 0;
for(\$j=\$i+1; \$j < strlen(\$expression); \$j++){
if(\$expression[\$j] === '(') \$depth++;
if(\$expression[\$j] === ')') \$depth--;
if(\$depth == 0){
\$pos[2] = \$j;
\$parts[1] = substr(\$expression, \$i+1, \$j-\$i);
break;
}
}
} else if(\$expression[\$i+1] === 'x'){ //base is a variable
\$pos[2] = \$i+1;
\$parts[1] = "x";
} else { //power is a number
if(preg_match("/\\^\\d*\\.{0,1}\\d+/",\$expression,\$foo)){
\$pos[2] = \$i + strlen(\$foo[0]) - 1;
\$parts[1] = substr(\$foo[0],1,strlen(\$foo[0])-1);
} else return false;
}

if(\$parts[0] == null || \$parts[1] == null) return false;
\$expression = substr(\$expression,0,\$pos[0]).'pow('.\$parts[0].','.\$parts[1].')'.substr(\$expression,\$pos[2]+1,strlen(\$expression)-\$pos[2]);
return (\$expression = carToPow(\$expression)) ? \$expression : false;

}

}
return \$expression;

}

Fou-Lu
02-28-2012, 01:47 PM
I don't know if I'd recommend that the caret be replaced since you'll lose the concept of the xor, but why not just use a regex to match it completely?

\$sEquation = '452.2 ^ x + 14 - y';

\$sPattern = '/([a-z]|\d+(?:\.\d+)?)*\s*\^\s*([a-z]|\d+(?:\.\d+)?)/i';
\$sReplace = 'pow(\$1, \$2)';

\$sResult = preg_replace(\$sPattern, \$sReplace, \$sEquation);

print \$sResult;

That will give you the same result. Granted without using a stack for this, the behaviour becomes slightly unusual if you provide an unmarked multiplication.

djh101
02-28-2012, 06:23 PM
This is intended for strings of standard math functions, where ^ is used for exponential expressions (and xor is not used at all). Your code works fine for standard a^b expressions, but the stack is needed for converting functions where the base or exponent is a parenthetical expression.

Fou-Lu
02-28-2012, 08:22 PM
Ooh yeah I do see what you mean, never thought about parenthetical expressions for the exponent, and its a mess if you have pow of pow (...of pow...*).
I know this can be done in regex as well, but I'm afraid that's beyond my skills as a matcher for sure. Stack handling even iterating is probably faster than the pattern would be anyway.