¡Damas, hagan un poco de matemáticas!

19

El orden de las operaciones, PEMDAS, es una regla básica en matemáticas que nos dice qué operaciones de orden deben realizarse:

"Paréntesis, exponentes, multiplicación y división, y suma y resta"

El problema es que PEMDAS no es muy versátil. ¿Y si quisieras hacerlo en otro orden? No nos meteremos con los paréntesis, por lo que los mantenemos donde están (primero).

Cree un programa que tome dos argumentos:

  • Una cadena que indica en qué orden deben seguir las operaciones. Algunos ejemplos son "DAMES", "SAD, ME", "ME SAD", "MEADS". Sí, los espacios y las comas están bien, ya que hace que el orden sea más fácil de recordar.
    • Siguiendo las sugerencias en el chat: los espacios de apoyo y las comas ahora son opcionales.
    • Si falta una de las letras, o si hay letras adicionales que no deberían estar allí, puede considerar que la entrada no es válida y tratarla como desee.
  • Una cadena o una expresión que contiene la expresión que debe evaluarse.

Devuelve el resultado de la expresión como un número decimal o un entero. Si la respuesta no es un número entero, debe devolverse como un número decimal.

Reglas:

  • Está bien combinar los dos argumentos de entrada en uno, si eso es más fácil en su idioma.
  • No tiene que ser una cadena, pero debe tener letras. No puedes sustituir Adición con 1, División con 2, etc.
  • Puede elegir qué entrada es primero.
  • La expresión se evalúa de derecha a izquierda de izquierda a derecha. (Cambio de regla. Cualquier póster de envío de las primeras 12 horas que tenga esto al revés es aceptado)
  • Las operaciones utilizan los símbolos: ( ) ^ * / + -. Por ejemplo, no puede usar en ¤lugar de +para sumar.
  • Los espacios en la expresión de entrada no son válidos como entrada
  • Unario +/- no es válido como entrada si sigue directamente a + o -. Considerar 3+-2como entrada no válida. Se puede tratar como quiera (no tiene que producir un error). Si +o -sigue cualquier otro operador que más o menos, se trató de la forma habitual: 3*-3 = -9,sin(-2)=-0.909
  • El programa debe seguir estrictamente las letras, así "EMDAS", 1-3+4 => -6, y "EMDSA", 1-3+4 => 2.

Ejemplos:

Input:   "EMDAS", "3+6*2/4-1"   // -> 3+12/4-1 -> 3+3-1 -> 6-1 -> 5
Output:  5

Input:   "DAMES", "3+6*2/4-1"   // -> 3+6*0.5-1 -> 9*0.5-1 -> 4.5-1 -> 3.5
Output:  3.5

Input:   "SAD, ME", "3+6*2/4-1"  // -> 3+6*2/3 -> 9*2/3 -> 9*0.66667 -> 6   
Output:  6

Input:   "ME ADS", "3+5^4/2-3*2 // -> 3+5^4/2-6 -> 3+625/2-6 -> 628/2-6 -> 314-6 -> 308
Output:  308

Input:   "AM EDS", "4*3-sin(0.5^2)*3+1" // -> 4*3-sin(0.5^2)*4 -> 12-sin(0.5^2)*4 -> 4*3-(4*sin(0.5^2)) -> 12-(4*sin(0.5^2)) -> 12-(4*sin(0.25)) -> 12-(4*0.24740) -> 12-0.98961 -> 11.01038
Output:  11.01038

Input:   "DAMES", "4-5-6"   // -> (4-5)-6 -> = -7  
Output:  -7                  // NOT: -> 4-(5-6) -> 4-(-1) -> 5

Tenga en cuenta que los paréntesis se agregaron para mostrar que la multiplicación 4*sin(0.5^2)se evalúa antes de la exponenciación.

Este es el código de golf, por lo que gana el código más corto en bytes.

Stewie Griffin
fuente
2
No es exactamente lo mismo, pero este desafío se trata de cambiar a otro orden de operaciones y fue la inspiración que me hizo la idea de hacer algo similar. Creo que la respuesta de Haskell podría ser modificada para responder esta pregunta tal vez ... No estoy seguro si es un duplicado estricto, ¡me gusta la idea de hacer este desafío sin la capacidad nativa de cambiar los operadores directamente!
Dom Hastings
2
Bonificación por funciones eliminadas, pero todavía hay sin () en los ejemplos.
edc65
Un poco más malvado que el desafío antes mencionado, y no voy a contestarlo como un duplicado (aunque se hubiera apreciado un enlace al original). Sin embargo, es fácil para todos ver que el malvado director de The 2560 no es otro que @Stewie Griffin. Tengo que decir que no estoy sorprendido.
Jake
En el Reino Unido a menudo se nos enseña como BODMASo BIDMASen la escuela. B= Paréntesis, Oo I= Orden o Índices.
BadHorsie
Es pnecesario? No está en los ejemplos
ev3commander

Respuestas:

7

JavaScript (ES6) 349353387 400

... tal vez todavía golfable

Este viejo analizador mío a veces es útil - (ya usado en otros 2 desafíos)

E=
(d,x,W=[],Q=['_'],h={'(':1,_:8,')':7},z=1,C=n=>{for(;h[q=Q.pop()]<=h[n];W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))a=W.pop(b=W.pop());Q.push(q,n)})=>([...d].map(l=>h[l='+-/*^'['ASDME'.search(l)]]=(d+=!!l),d=1),(x+')').replace(/\D|\d+/g,t=>(u=~~h[t])-1?u-7?u?z&&t=='-'?z=-z:C(t,z=1):(W.push(z*t),z=0):Q.pop(Q.pop(C(t),z=0)):z=!!Q.push('_')),W.pop())

// TEST
console.log=(...x)=>O.innerHTML+=x.join` `+'\n'

console.log(E('MDASE','3+4*5^2'))
console.log(E("EMDAS", "3+6*2/4-1")) // 5
console.log(E("DAMES", "3+6*2/4-1")) //3.5
console.log(E("SAD, ME", "3+6*2/4-1")) // 6
console.log(E("ME ADS", "3+5^4/2-3*2")) // 308
console.log(E("AM EDS", "4*3-sin(0.5^2)*3+1")) // 11.01038 sin not supported
console.log(E("DAMES", "4-5-6")) // -7

// MORE READABLE
U=(d,x,W=[],Q=['_'],h={'(':1,_:8,')':7},z=1,
  C=n=>{
    for(;h[q=Q.pop()]<=h[n];
        W.push(q=='^'?Math.pow(a,b):eval(`a${q}b`)))
      a=W.pop(b=W.pop());
    Q.push(q,n)
  }
)=>(
  [...d].map(l=>h[l='+-/*^'['ASDME'.search(l)]]=(d+=!!l),d=1),
  (x+')').replace(/\D|\d+/g,t=> 
     (u=~~h[t])-1
       ?u-7
         ?u
           ?z&&t=='-'?z=-z:C(t,z=1)
           :(W.push(z*t),z=0)
         :Q.pop(Q.pop(C(t),z=0))
       :(Q.push('_'),z=1)
  ),
  W.pop()
)
<pre id=O></pre>

Sin golf

Evaluate=(oprec,expr)=>
{
  var tokens = expr.match(/\D|\d+/g).concat(')')
  var t,a,b,v, SignV
  var vstack=[]
  var ostack=['_']
  var op={ '(':8, _: 1, ')':2}
  oprec.match(/\w/g).map((l,p)=>op['+-/*^'['ASDME'.search(l)]]=7-p)
  var OPush=o=>ostack.push(o)
  var OPop=_=>ostack.pop()
  var VPush=v=>vstack.push(v)
  var VPop=v=>vstack.pop()

  var Scan=i=>
  {
    SignV = 1
    for (; t=tokens[i++]; )
    {
      if (t == '(')  
      {
        OPush('_')
        SignV = 1
      }
      else if (t == ')')
      {
        CalcOp(t);
        OPop();
        OPop();
        SignV = 0
      }
      else if (op[t])
      {
        if (SignV && t=='-')
          SignV = -SignV
        else
          CalcOp(t), SignV = 1
      }  
      else
      {
        VPush(SignV*t)
        SignV=0
      }
    }
  }
  var CalcOp=nop=>
  {
    for (; op[po = OPop()] >= op[nop];)
      b=VPop(), a=VPop(), CalcV(a,b,po);
    OPush(po), OPush(nop);
  }
  var CalcV=(a,b,o)=>
  {
//    console.log('CV',a,b,o)
    if (o=='+')
      a+=b
    if (o=='-')
      a-=b
    if (o=='*')
      a*=b
    if (o=='/')
      a/=b
    if (o=='^')
      a=Math.pow(a,b)
    VPush(a)
  }
  Scan(0)

  return VPop()
}

console.log=(...x)=>O.innerHTML+=x.join` `+'\n'

console.log(Evaluate('MDASE','3+4*5^2'))
console.log(Evaluate('EMDAS','3+6*2/4-1')) // 5
console.log(Evaluate("DAMES", "3+6*2/4-1")) //3.5
console.log(Evaluate("SAD, ME", "3+6*2/4-1")) // 6
console.log(Evaluate("ME ADS", "3+5^4/2-3*2")) // 308
console.log(Evaluate("AM EDS", "4*3-sin(0.5^2)*3+1")) // 11.01038 sin not supported
console.log(Evaluate("DAMES", "4-5-6")) // -7
<pre id=O></pre>

edc65
fuente
Creo que puede eliminar el espacio (t=>t=='('?(z=1, Q.push('_')), junto con todas las líneas nuevas.
Conor O'Brien el
1
@ CᴏɴᴏʀO'Bʀɪᴇɴ trabajando en ello. Gracias
edc65
Creo que puedes cambiarlo Math.pow(a,b)aa**b
Kritixi Lithos
@KritixiLithos sí, pero ya no sería ES6
edc65
6

R 3.3.2: 209 196 187 177 bytes

La idea es "mal uso" de los operadores no aritméticos <, &, |, ~,? donde sabemos la precedencia (ver ?Syntaxen R - pero antes de la anulación;)) y anularlos con los operadores aritméticos dados. El mapeo se realiza según el orden deseado de operaciones.

No se admiten espacios ni comas en la entrada .

Versión de golf

f=function(a,b){s=substr;l=list(E='^',M='*',D='/',A='+',S='-');q="<&|~?";for(i in 1:5){x=s(q,i,i);y=l[[s(a,i,i)]];assign(x,.Primitive(y));b=gsub(y,x,b,,,T)};eval(parse(text=b))}

Ungolfed y comentó:

f = function(a,b) {
  s = substr
  # All arithmetic operators
  l = list(E = '^', M = '*', D = '/', A = '+', S = '-')
  # Some non-arithmetic R operators in descending precedence
  q = "<&|~?"
  for (i in 1:5) {
    # The substituted symbol
    x = s(q, i, i)
    # The original operator which has to be substituted
    y = l[[s(a, i, i)]]
    # Substitute the operator for the R interpreter
    assign(x, .Primitive(y))
    # Substitute the operator in the input string
    b = gsub(y, x, b, , , T)
  }
  # Parse and evaluate
  eval(parse(text = b))
}

Ejemplos:

> f("EMDAS", "3+6*2/4-1")
[1] 5
> f("DAMES", "3+6*2/4-1")
[1] 3.5
> f("SADME", "3+6*2/4-1")
[1] 6
> f("MEADS", "3+5^4/2-3*2")
[1] 308
> f("AMEDS", "4*3-sin(0.5^2)*3+1")
[1] 11.01038
> f("DAMES", "4-5-6")
[1] -7
Patrick Roocks
fuente