Gå til innhold

Kalkulator-skript for PHP


Anbefalte innlegg

Finnes det noe open-source kalkulator-skript/klasse for PHP som fungerer omtrent som Calc? Det vil si at jeg ønsker en slags "kommandolinjekalkulator", hvor man skriver inn et regnestykke (f eks "(215.3-64)/27*(78.1*(299-2))/1-2") og få resultatet.

 

Har begynt å skrive et skript, men vet ikke om jeg har tid og får til å fullføre det.

Lenke til kommentar
Videoannonse
Annonse

Finnes helt sikkert script der ute som regner ut infix-uttrykk, men det er relativt lett å lage det selv også da. Straks du får gjort det om til postfix så er det jo basic stack-operasjoner for å regne det ut. Akkurat nå kjeder jeg meg en smule så har ingenting imot å lage det :)

Endret av Ernie
Lenke til kommentar

Okey :) Sitter selv og knoter med det her, og det er visst ikke like trivielt som jeg trodde. Å regne ut et postfix-uttryk er enkelt. Å konvertere et infix-uttryk til postfix er derimot ikke fult så enkelt. Dog, i teorien skal det være mulig å regne ut infix-uttryk direkte, men det er overhode ikke enkelt.

 

Forøvrig, hvis du ikke veit det er infix måten vi mennesker skriver opp regnestykk. Postfix kan du lese mer om her siden jeg ikke klarer å forklare det enkelt :p (involverer datastrukturen tre og traverseringen av det, noe jeg har en følelse av at du ikke veit helt hva er)

Endret av Ernie
Lenke til kommentar

Leser denne artikkelen nå, og det ser ut til å være ganske komplisert, ja.

 

Men i tilfelle jeg får til å konvertere fra infix til postfix, hvordan regner jeg ut et postfix-uttrykk?

 

Hvordan gjør andre matematikkprogrammer (Mathematica, Maple, calc, bc osv.) det? Regner de ut infix-uttrykket direkte, eller går de også veien om postfix? Eller finnes det andre metoder?

Lenke til kommentar

Jøss ... Jeg tror trekker tilbake at det her var lett. Infix -> prefix var en hard nøtt gitt :hm: Uannsett, vil nesten anta at man bruker den algoritmen du linket til, bare sliter litt med å implementere den i PHP :blush:

 

Edit: Baaaah :angry: Ser feilen nå, men jeg hater PHPs elendige utvalg av datastrukturer. Struct hadde vært noe, men får vel nøye meg med array.

Endret av Ernie
Lenke til kommentar

Weee ... endelig fikk jeg det til å funke :w00t: Så lenge input er uten snarveier i skrivemåten (f.eks 3(2+1)) skal det funke. Jeg har ikke giddet å kommentere koden (ja, fyyyyy meg). Mulig jeg gjør det når jeg er litt mindre trøtt.

 

//Infix:  5 + ((1 + 2) * 4) + 3
//Postfix:	5 1 2 + 4 * + 3 +
echo CalculateInfix("5 + ((1 + 2) * 4) + 3");

function CalculateInfix($infix)
{
$stack = array('#');
$valid_op = array('-', '+', '*', '/', '^', '(', ')');
$mp = 1;
$temp = $temp2 = $postfix = '';
$i = $j = 0;
$size = strlen($infix);
while ($i < $size)
{
 if (is_numeric($infix[$i]))
 	do 
   $temp .= $infix[$i++];
 	while (is_numeric($temp.$infix[$i]) && $i < $size);
 else 
 	$temp = $infix[$i++];
 
 if (in_array($temp, $valid_op) || is_numeric($temp))
 {
 	if (SetValue($temp, 1) > $stack[count($stack)-1][0])
   array_push($stack, array(SetValue($temp, 2)*$mp, $temp));
 	else 
 	{
   while (SetValue($temp, 1)*$mp <= $stack[count($stack)-1][0])
   {
   	list(, $temp2) = array_pop($stack);
   	if ($temp2 != '(' && $temp2 != ')')
     $postfix[$j++] = $temp2;
   	elseif ($temp2 == ')')
     $mp /= 10;
   	elseif ($temp2 == '(')
     $mp *= 10;
   }
   array_push($stack, array(SetValue($temp, 2)*$mp, $temp));
 	}
 }
 $temp = '';
}

while ($stack[count($stack)-1] != '#')
 list(, $postfix[$j++]) = array_pop($stack);

$stack = array();
for ($i = 0; $i < $j; $i++)
{
 if (is_numeric($postfix[$i]))
 	array_push($stack, $postfix[$i]);
 else 
 {
 	$num1 = array_pop($stack);
 	$num2 = array_pop($stack);

 	switch ($postfix[$i])
 	{
   
   case '*': array_push($stack, $num2 * $num1); break;
   case '/': array_push($stack, $num2 / $num1); break;
   case '-': array_push($stack, $num2 - $num1); break;
   case '+': array_push($stack, $num2 + $num1); break;
   case '^': array_push($stack, $num2 ^ $num1); break;
 	}
 }
}
return array_pop($stack);
}

function SetValue($input, $type)
{
$add = array('-', '+');
$multi = array('*', '/');
if ($input == '#')
 return 0;
elseif (in_array($input, $add))
 return 3;
elseif (in_array($input, $multi))
 return 4;
elseif ($input == '^')
 return 5;
elseif (is_numeric($input))
 return 9;
elseif (($input =='(' && $type == 1) || ($input ==')' && $type == 2))
 return 9;
else 
 return 2;
}

 

 

Edit: Bare så det er sagt: Ja, det er nok et potensial for optimalisering :)

Endret av Ernie
Lenke til kommentar

Ser bra ut. Men den sliter litt med negative tall. Det kan løses ved å sette en "0" foran det negative tallet, men det er jo litt tungvindt... F eks: 2*-2 eller 2*(-2) fungerer ikke, men 2*(0-2) fungerer. (Jeg har selv skrevet et skript som regner ut infix-uttrykk direkte, og da var det dette med negative tall som gjorde at jeg ikke kom noe videre.)

 

I tillegg sliter den når det er en parentes på slutten av et uttrykk, f eks "2*(3+4)". Dette kan løses ved å legge til "*1" på slutten, men det er jo også litt tungvindt.

Lenke til kommentar

Hmm ... det her var litt mer komplisert :hm: Jeg tror nesten jeg må skrive hele greia om når jeg kommer hjem. Å regne det ut direkte ble plutselig mindre komplisert. Det jeg tenker meg ut her blir å hente ut mellom ( og motsående ) og erstatte det med et tall v.hj.a rekursjon. Problemområdet blir rett og slett def. av tall. Finnes endel string-funksjoner som funker fett til det her (substr_replace, substr, strpos).

Endret av Ernie
Lenke til kommentar

Hva med denne lille "skumle" snutten, da ? :)

<?
$regnestykke = "(215.3-64)/27*(78.1*(299-2))/1-2"; 
eval("\$resultat = ".$regnestykke.";");
echo $regnestykke." = ".$resultat;
?>

Takler ihvertfall parenteser greit ;). Men dòg så er det jo ikke anbefalt å bruke eval, da...

Koden gir dette i output:

(215.3-64)/27*(78.1*(299-2))/1-2 = 129979.83

Stemmer kanskje ? Har ikke fått sjekket det så veldig nøye...

 

Dersom input fra bruker brukes, må det valideres nøye (Bare lov med tall og operatorer f.eks...)

Endret av kakkle
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...