Arithmetic evaluation: Difference between revisions

(5 intermediate revisions by 5 users not shown)
Line 299:
<pre>
euler's number is about: 2.71828182845899446428546958
</pre>
 
=={{header|Amazing Hopper}}==
Hopper no soporta números muy grandes, por decisión de diseño, pero es posible realizar una aproximación aplicando el Límite de Euler para calcular un factorial de un número real, hecho para uno de los ejemplos.
<syntaxhighlight lang="c">
#include <basico.h>
 
#proto verificarconstante(_X_)
#synon _verificarconstante se verifica constante en
 
#proto verificarfunción(_X_)
#synon _verificarfunción se verifica función en
 
algoritmo
 
pila de trabajo 50
 
números (largo de datos)
decimales '13'
preparar datos(DATA_EXPRESIONES)
obtener tamaño de datos, guardar en 'largo de datos'
imprimir ("Negativos deben escribirse entre parentesis\nEjemplo: (-3)\n\n")
iterar
matrices ( pila, p, q )
cadenas (expresión)
obtener dato, copiar en 'expresión'
ir a subs ( convierte a matriz --> convierte a notación polaca \
--> evalúa expresión --> despliega resultados )
--largo de datos
mientras ' largo de datos'
 
terminar
 
subrutinas
 
convierte a matriz:
 
argumentos 'expr'
transformar(" ","",\
transformar("(-","(0-",expr)), guardar en 'expr'
 
l=0, #( l = len(expr) )
v="", num="", cte=""
para cada caracter (v, expr, l)
cuando ( #(typechar(v,"digit") || v==".")){
num, v, concatenar esto, guardar en 'num'
continuar
}
cuando ( #(typechar(v,"alpha") )){
cte, v, concatenar esto, guardar en 'cte'
continuar
}
cuando (num) {num, meter en 'q', num=""}
cuando (cte) {cte, meter en 'q', cte=""}
v, meter en 'q'
siguiente
cuando (num) {num, meter en 'q'}
cuando (cte) {cte, meter en 'q'}
"(", meter en 'pila'
")", meter en 'q'
// imprimir( "Q = {", q, "}\n" )
retornar
 
convierte a notación polaca:
 
l="", m=""
iterar mientras '#( not(is empty(q)) )'
sw = 1
 
///imprimir("P = ",p,"\nQ = ",q,"\nPILA = ",pila,NL)
 
extraer tope 'q' para 'l'
// ¿es un operando?
cuando ' #(not( occurs(l,"+-*^/)(%") )) ' {
si ' se verifica constante en (l) '
meter en 'p'
sino si ' se verifica función en (l) '
l, meter en 'pila'
sino
#( number(l) ), meter en 'p'
fin si
continuar
}
// es un simbolo...
 
// es un parentesis izquierdo?
cuando ( #( l=="(" ) ) {
l, meter en 'pila'
continuar
}
// es un operador?
cuando ( #( occurs(l,"+-*^/%")) ) {
iterar mientras ' sw '
extraer cabeza 'pila' para 'm'
 
cuando ' #(m=="(") '{
m,l, apilar en 'pila'
sw=0, continuar
}
cuando ' #(l=="^") '{
si ' #(m=="^") '
//m,l, apilar en 'p'
m, meter en 'p'
sino
m,l, apilar en 'pila'
sw=0
fin si, continuar
}
cuando ' #(l=="*") ' {
si ' #(occurs(m, "^*/%"))'
m, meter en 'p'
sino
m,l, apilar en 'pila'
sw=0
fin si, continuar
}
//cuando ' #(l=="/") ' {
// decisión de diseño para resto módulo
cuando ' #( occurs(l,"/%")) ' {
si ' #( occurs(m, "/^*%") )'
m, meter en 'p'
l, meter en 'pila'
sino
m,l, apilar en 'pila'
fin si
sw=0, continuar
}
 
cuando ' #(occurs(l, "+-"))' {
m, meter en 'p'
// saber si ya hay un símbolo "-" en pila
tmp=0
tope(pila), mover a 'tmp'
si ' #( occurs(tmp,"+-") ) '
extraer cabeza (pila)
meter en 'p'
fin si
l, meter en 'pila'
sw=0
}
reiterar
si ' #( length (pila)==0 ) '
"(", meter en 'pila'
fin si
continuar
}
// es un paréntesis derecho?
cuando( #(l==")") ) {
extraer cabeza (pila) para 'm'
iterar mientras ' #( m<>"(") '
m, meter en 'p'
extraer cabeza 'pila' para 'm'
reiterar
}
reiterar
retornar
 
evalúa expresión:
 
l = " ", a=0, b=0
iterar mientras ' #( not(is empty(p)) ) '
extraer tope 'p' para 'l'
si ' es numérico (l) '
l, meter en 'pila'
sino
si ' se verifica función en (l) '
extraer cabeza 'pila' para 'b'
seleccionar 'l'
caso ("sqrt"){ #(sqrt(b)), salir }
caso ("log"){ #(log10(b)), salir }
caso ("ln"){ #(log(b)), salir }
caso ("fact"){
si ' #(int(b)<>b) ' // límite de Euler
x=0,i=2, xb=1,
// aproximación muy burda.
#basic{
b = b + 1
x = fact(163)*(163^b)
xb = b*(b+1)
while( i<=163 )
xb = xb * ( i+b )
i+=1
wend
x/xb
}
sino // normal
#(fact(b))
fin si
salir
}
fin seleccionar
sino
extraer cabeza 'pila' para 'b'
extraer cabeza 'pila' para 'a'
seleccionar 'l'
caso ("+"){ #(a+b), salir }
caso ("-"){ #(a-b), salir }
caso ("*"){ #(a*b), salir }
// n/0 = inf, no es necesario detectar esto:
caso ("/"){ #(a/b), salir }
caso ("^"){ #(a^b), salir }
caso ("%"){ #(a%b), salir }
fin seleccionar
fin si
meter en 'pila'
fin si
 
reiterar
 
retornar
 
despliega resultados:
 
imprimir(expresión," : ", \
tomar si( #(length(pila)==1),pila, \
#(utf8("expresión mal formada!"))), NL)
retornar
 
verificar constante (x)
seleccionar 'x'
caso ("pi"){ M_PI, 1, salir }
caso ("e") { M_E, 1, salir }
caso ("phi"){ M_PHI, 1, salir }
// etcétera...
caso por defecto{ 0, salir }
fin seleccionar
retornar
 
verificar función (f)
seleccionar 'f'
caso ("sqrt"){ '1', salir }
caso ("log"){ '1', salir }
caso ("ln"){ '1', salir }
caso ("fact"){ '1', salir }
// etcétera...
caso por defecto { '0', salir }
fin seleccionar
retornar
 
DATA_EXPRESIONES:
datos("((30+4.5) * ( 7 / 9.67 )+3)-4*(-1)") //31.9741468459168
datos("1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1") // 60!
datos("(1 - 5) * 2 / (20 + 1)") // -8/21
datos("(3 * 2) - (1 + 2) / (4") // error!
datos("(3 * 2) a - (1 + 2) / 4") // error!
datos("(6^2)*2/3") //24
datos("6^2*2/3") //24
datos("(6^2)*2/0") //inf
datos("2 * (3 + ((5) / (7 - 11)))") // 3.5
datos("1 - 5 * 2 / 20 + 1") //1,5!
datos ("(1 + 2) * 10 / 100") // 0.3
datos("1+3.78") // 4.78
datos("2.5 * 2 + 2 * pi") // 11.28
datos("1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10") // 71
datos("1+1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1/15)/14)/13)/12)/11)/10)/9)/8)/7)/6)/5)/4)/3)/2") // 2.7182818284589946
datos("((11+15)*15)*2-(3)*4*1") // 768
datos(" 2*(-3)-(-4)+(-0.25)") //-2.25
datos(" 2-25 % 3+1") // 2
datos(" 2-(25 % 3)+1") // 2
datos(" (2-25) % (3+1)") // -3
datos(" 2- 25 % 3 % 2") // 1
datos(" 2- 25 / 3 % 2") // 1.66666
datos(" 2- ((25 / 3) % 2)") // 1.66666
datos(" 2- 25 / 3 / 2") // 2.166666
datos(" (-23) %3") // -2
datos(" (6*pi-1)^0.5-e") // 1,506591651...
datos("2^2^3^4")
datos("(4-2*phi)*pi") // 2,3999632297286
datos("( (1+sqrt(5))/2)^(2/pi)") // 1.3584562741830
datos("1-(1+ln(ln(2)))/ln(2)") // 0.0860713320559
datos("pi / (2 * ln(1+sqrt(2)))") // 1,7822139781 ....
datos("( (e^(pi/8)) * sqrt(pi)) /(4 * (2^(3/4)) * (fact(1/4))^2) ") //0,47494 93799...
datos(" fact(1/2)") // 0.906402477055...
back
</syntaxhighlight>
{{out}}
<pre>
Negativos deben escribirse entre parentesis
Ejemplo: (-3)
 
((30+4.5) * ( 7 / 9.67 )+3)-4*(-1) : 31.9741468459168
1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1 : 60.0000000000000
(1 - 5) * 2 / (20 + 1) : -0.3809523809524
(3 * 2) - (1 + 2) / (4 : expresión mal formada!
(3 * 2) a - (1 + 2) / 4 : expresión mal formada!
(6^2)*2/3 : 24.0000000000000
6^2*2/3 : 24.0000000000000
(6^2)*2/0 : inf
2 * (3 + ((5) / (7 - 11))) : 3.5000000000000
1 - 5 * 2 / 20 + 1 : 1.5000000000000
(1 + 2) * 10 / 100 : 0.3000000000000
1+3.78 : 4.7800000000000
2.5 * 2 + 2 * pi : 11.2831853071796
1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 : 71.0000000000000
1+1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1/15)/14)/13)/12)/11)/10)/9)/8)/7)/6)/5)/4)/3)/2 : 2.7182818284590
((11+15)*15)*2-(3)*4*1 : 768.0000000000000
2*(-3)-(-4)+(-0.25) : -2.2500000000000
2-25 % 3+1 : 2.0000000000000
2-(25 % 3)+1 : 2.0000000000000
(2-25) % (3+1) : -3.0000000000000
2- 25 % 3 % 2 : 1.0000000000000
2- 25 / 3 % 2 : 1.6666666666667
2- ((25 / 3) % 2) : 1.6666666666667
2- 25 / 3 / 2 : -2.1666666666667
(-23) %3 : -2.0000000000000
(6*pi-1)^0.5-e : 1.5065916514856
2^2^3^4 : 16777216.0000000000000
(4-2*phi)*pi : 2.3999632297286
( (1+sqrt(5))/2)^(2/pi) : 1.3584562741830
1-(1+ln(ln(2)))/ln(2) : 0.0860713320559
pi / (2 * ln(1+sqrt(2))) : 1.7822139781915
( (e^(pi/8)) * sqrt(pi)) /(4 * (2^(3/4)) * (fact(1/4))^2) : 0.4831858606252
fact(1/2) : 0.8761319893678
 
</pre>
 
Line 592 ⟶ 922:
 
=={{header|C++}}==
{{works with|g++|clang++}}
This version does not require boost.
It works by:
- converting infix strings to postfix strings using shunting yard algorithm
- converting postfix expression to list of tokens
- builds AST bottom up from list of tokens
- evaluates expression tree by performing postorder traversal.
 
<syntaxhighlight lang="cpp">
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
 
template <class T>
class stack {
private:
vector<T> st;
T sentinel;
public:
stack() { sentinel = T(); }
bool empty() { return st.empty(); }
void push(T info) { st.push_back(info); }
T& top() {
if (!st.empty()) {
return st.back();
}
return sentinel;
}
T pop() {
T ret = top();
if (!st.empty()) st.pop_back();
return ret;
}
};
 
//determine associativity of operator, returns true if left, false if right
bool leftAssociate(char c) {
switch (c) {
case '^': return false;
case '*': return true;
case '/': return true;
case '%': return true;
case '+': return true;
case '-': return true;
default:
break;
}
return false;
}
 
//determins precedence level of operator
int precedence(char c) {
switch (c) {
case '^': return 7;
case '*': return 5;
case '/': return 5;
case '%': return 5;
case '+': return 3;
case '-': return 3;
default:
break;
}
return 0;
}
 
//converts infix expression string to postfix expression string
string shuntingYard(string expr) {
stack<char> ops;
string output;
for (char c : expr) {
if (c == '(') {
ops.push(c);
} else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%') {
if (precedence(c) < precedence(ops.top()) ||
(precedence(c) == precedence(ops.top()) && leftAssociate(c))) {
output.push_back(' ');
output.push_back(ops.pop());
output.push_back(' ');
ops.push(c);
} else {
ops.push(c);
output.push_back(' ');
}
} else if (c == ')') {
while (!ops.empty()) {
if (ops.top() != '(') {
output.push_back(ops.pop());
} else {
ops.pop();
break;
}
}
} else {
output.push_back(c);
}
}
while (!ops.empty())
if (ops.top() != '(')
output.push_back(ops.pop());
else ops.pop();
cout<<"Postfix: "<<output<<endl;
return output;
}
 
struct Token {
int type;
union {
double num;
char op;
};
Token(double n) : type(0), num(n) { }
Token(char c) : type(1), op(c) { }
};
 
//converts postfix expression string to vector of tokens
vector<Token> lex(string pfExpr) {
vector<Token> tokens;
for (int i = 0; i < pfExpr.size(); i++) {
char c = pfExpr[i];
if (isdigit(c)) {
string num;
do {
num.push_back(c);
c = pfExpr[++i];
} while (i < pfExpr.size() && isdigit(c));
tokens.push_back(Token(stof(num)));
i--;
continue;
} else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%') {
tokens.push_back(Token(c));
}
}
return tokens;
}
 
//structure used for nodes of expression tree
struct node {
Token token;
node* left;
node* right;
node(Token tok) : token(tok), left(nullptr), right(nullptr) { }
};
 
//builds expression tree from vector of tokens
node* buildTree(vector<Token> tokens) {
cout<<"Building Expression Tree: "<<endl;
stack<node*> sf;
for (int i = 0; i < tokens.size(); i++) {
Token c = tokens[i];
if (c.type == 1) {
node* x = new node(c);
x->right = sf.pop();
x->left = sf.pop();
sf.push(x);
cout<<"Push Operator Node: "<<sf.top()->token.op<<endl;
} else
if (c.type == 0) {
sf.push(new node(c));
cout<<"Push Value Node: "<<c.num<<endl;
continue;
}
}
return sf.top();
}
 
//evaluate expression tree, while anotating steps being performed.
int recd = 0;
double eval(node* x) {
recd++;
if (x == nullptr) {
recd--;
return 0;
}
if (x->token.type == 0) {
for (int i = 0; i < recd; i++) cout<<" ";
cout<<"Value Node: "<<x->token.num<<endl;
recd--;
return x->token.num;
}
if (x->token.type == 1) {
for (int i = 0; i < recd; i++) cout<<" ";
cout<<"Operator Node: "<<x->token.op<<endl;
double lhs = eval(x->left);
double rhs = eval(x->right);
for (int i = 0; i < recd; i++) cout<<" ";
cout<<lhs<<" "<<x->token.op<<" "<<rhs<<endl;
recd--;
switch (x->token.op) {
case '^': return pow(lhs, rhs);
case '*': return lhs*rhs;
case '/':
if (rhs == 0) {
cout<<"Error: divide by zero."<<endl;
} else
return lhs/rhs;
case '%':
return (int)lhs % (int)rhs;
case '+': return lhs+rhs;
case '-': return lhs-rhs;
default:
break;
}
}
return 0;
}
 
int main() {
string expr = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3";
cout<<eval(buildTree(lex(shuntingYard(expr))))<<endl;
return 0;
}
 
Output:
Postfix: 3 4 2 * 1 5 - 2 3^^/+
Building Expression Tree:
Push Value Node: 3
Push Value Node: 4
Push Value Node: 2
Push Operator Node: *
Push Value Node: 1
Push Value Node: 5
Push Operator Node: -
Push Value Node: 2
Push Value Node: 3
Push Operator Node: ^
Push Operator Node: ^
Push Operator Node: /
Push Operator Node: +
Operator Node: +
Value Node: 3
Operator Node: /
Operator Node: *
Value Node: 4
Value Node: 2
4 * 2
Operator Node: ^
Operator Node: -
Value Node: 1
Value Node: 5
1 - 5
Operator Node: ^
Value Node: 2
Value Node: 3
2 ^ 3
-4 ^ 8
8 / 65536
3 + 0.00012207
3.00012
</syntaxhighlight>
 
{{Works with|g++|4.1.2 20061115 (prerelease) (SUSE Linux)}}
 
Line 1,325 ⟶ 1,906:
#
subr ntok
ifwhile ch$ = 0" "
tok$ = "eof"nch
else.
if ch >= while48 and ch$ <= " "58
tok$ = nch"n"
.s$ = ""
ifwhile ch >= 48 and ch <= 58 or ch$ = "."
toks$ &= "n"ch$
s$ = ""
while ch >= 48 and ch <= 58 or ch$ = "."
s$ &= ch$
nch
.
tokv = number s$
else
tok$ = ch$
nch
.
tokv = number s$
elif ch = 0
tok$ = "end of text"
else
tok$ = ch$
nch
.
.
Line 1,392 ⟶ 1,971:
.
ntok
else
err = 1
print "error: factor expected, got " & tok$
.
return nd
Line 1,452 ⟶ 2,034:
.
input_data
4 * 6
4.2 * ((5.3+8)*3 + 4)
2.5 * 2 + 2 * 3.14
Line 1,573 ⟶ 2,155:
^ weak self.newBracket().gotoStarting()
}
:! {
^ weak self.newToken().append(ch).gotoToken()
}
Line 1,599 ⟶ 2,181:
^ weak self.newFraction().gotoOperator()
}
:! {
^ weak self.append:(ch)
}
}
Line 1,616 ⟶ 2,198:
^ weak self.newToken().append("0").newDifference().gotoOperator()
}
:! {
^ weak self.newToken().append:(ch).gotoToken()
}
}
Line 1,683 ⟶ 2,265:
{
if (_level < 10)
{ InvalidArgumentException.new:("Invalid expression").raise() };
_level := _level - 10
Line 1,692 ⟶ 2,274:
if(ch >= $48 && ch < $58)
{
_token.append:(ch )
}
else
{
InvalidArgumentException.new:("Invalid expression").raise()
}
}
Line 1,702 ⟶ 2,284:
append(string s)
{
s.forEach::(ch){ self.append:(ch) }
}
Line 1,792 ⟶ 2,374:
var scope := Scope.new(self);
 
text.forEach::(ch){ scope.eval:(ch) };
 
^ scope.Number
Line 1,807 ⟶ 2,389:
try
{
console.printLine("=",parser.run:(text))
}
catch(Exception e)
{
console.writeLine:("Invalid Expression")
};
Line 6,717 ⟶ 7,299:
{{trans|Kotlin}}
{{libheader|Wren-pattern}}
<syntaxhighlight lang="ecmascriptwren">import "./pattern" for Pattern
 
/* if string is empty, returns zero */