Dames, fais un peu de maths!

19

L'ordre des opérations, PEMDAS, est une règle de base en mathématiques nous indiquant quelles opérations d'ordre doivent être effectuées:

"Parenthèses, exposants, multiplication et division, et addition et soustraction"

Le problème est que PEMDAS n'est pas très polyvalent! Et si vous vouliez le faire dans un autre ordre? Nous ne jouerons pas avec les parenthèses, nous les gardons donc là où elles sont (d'abord).

Créez un programme qui prend deux arguments:

  • Une chaîne indiquant l'ordre dans lequel les opérations doivent suivre. Quelques exemples sont "DAMES", "SAD, ME", "ME SAD", "MEADS". Oui, les espaces et les virgules sont OK, car cela rend la commande plus facile à retenir.
    • Suggestions suivantes dans le chat: La prise en charge des espaces et des virgules est désormais facultative.
    • Si l'une des lettres est manquante ou s'il y a des lettres supplémentaires qui ne devraient pas s'y trouver, vous pouvez considérer l'entrée comme non valide et la traiter comme vous le souhaitez.
  • Une chaîne ou une expression contenant l'expression à évaluer.

Renvoie le résultat de l'expression sous la forme d'un nombre décimal ou d'un entier. Si la réponse n'est pas un entier, elle doit être renvoyée sous forme de nombre décimal.

Règles:

  • C'est OK de combiner les deux arguments d'entrée en un seul, si c'est plus facile dans votre langue.
  • Ce ne doit pas être une chaîne, mais il doit avoir des lettres. Vous ne pouvez pas remplacer Addition par 1, Division par 2, etc.
  • Vous pouvez choisir quelle entrée est la première.
  • L'expression est évaluée de droite à gauche de gauche à droite. (Changement de règle. Toute affiche des soumissions des 12 premières heures qui ont ceci dans l'autre sens est acceptée).
  • Les opérations utilisent les symboles: ( ) ^ * / + -. Par exemple, vous ne pouvez pas utiliser ¤au lieu de +pour l'ajout.
  • Les espaces dans l'expression d'entrée ne sont pas valides comme entrée
  • Unaire +/- n'est pas valide comme entrée s'il suit directement + ou -. Considérez 3+-2comme entrée non valide. Il peut être traité comme vous le souhaitez (ne doit pas produire d'erreur). Si +ou -suit tout autre opérateur que plus ou moins, il est traité de la manière habituelle: 3*-3 = -9,sin(-2)=-0.909
  • Le programme doit suivre strictement les lettres, donc "EMDAS", 1-3+4 => -6, et "EMDSA", 1-3+4 => 2.

Exemples:

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

Notez que les parenthèses ont été ajoutées pour montrer que la multiplication 4*sin(0.5^2)est évaluée avant l'exponentiation.

C'est le golf de code, donc le code le plus court en octets gagne.

Stewie Griffin
la source
2
Ce n'est pas exactement la même chose, mais ce défi consiste à passer à un autre ordre de fonctionnement et a été l'inspiration qui m'a fait aimer l'idée de faire quelque chose de similaire. Je pense que la réponse Haskell pourrait être retravaillée pour répondre à cette question peut-être ... Je ne sais pas s'il s'agit d'un doublon strict, j'aime bien l'idée de faire ce défi sans la capacité native de changer directement les opérateurs!
Dom Hastings du
2
Bonus pour les fonctions supprimées, mais il y a toujours sin () dans les exemples.
edc65
Un peu plus maléfique que le défi susmentionné, et je ne vais pas le contester en double (même si un lien vers l'original aurait été apprécié). Cependant, il est clair pour tout le monde que le méchant réalisateur de The 2560 n'est autre que @Stewie Griffin. Je dois dire que je ne suis pas surpris.
Jake
Au Royaume-Uni, on nous l'apprend souvent à l'école BODMASou BIDMASà l'école. B= Supports, Oou I= Ordre ou Indices.
BadHorsie
Est pnécessaire? Ce n'est pas dans les exemples
ev3commander

Réponses:

7

JavaScript (ES6) 349 353 387 400

... peut-être encore jouable au golf

Cet ancien analyseur est parfois utile - (déjà utilisé dans 2 autres défis)

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>

Non 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
la source
Je pense que vous pouvez supprimer l'espace (t=>t=='('?(z=1, Q.push('_')), ainsi que toutes les nouvelles lignes.
Conor O'Brien
1
@ CᴏɴᴏʀO'Bʀɪᴇɴ y travaille. Merci
edc65
Je pense que vous pouvez changer le Math.pow(a,b)àa**b
Kritixi Lithos
@KritixiLithos oui mais ce ne serait plus
ES6
6

R 3.3.2: 209 196 187 177 octets

L'idée est de "mal utiliser" les opérateurs non arithmétiques <, &, |, ~,? où nous connaissons la priorité (voir ?Syntaxdans R - mais avant la substitution;)) et les remplacer avec les opérateurs arithmétiques donnés. Le mappage est conforme à l'ordre des opérations souhaité.

Les espaces et les virgules dans l'entrée ne sont pas pris en charge.

Version golfée

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))}

Non golfé et commenté:

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))
}

Exemples:

> 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
la source