Dames, zróbcie matematykę!

19

Kolejność operacji, PEMDAS, jest podstawową zasadą w matematyce, która mówi nam, które operacje kolejności należy wykonać:

„Nawiasy, wykładniki, mnożenie i dzielenie oraz dodawanie i odejmowanie”

Problem w tym, że PEMDAS nie jest bardzo wszechstronny! Co jeśli chcesz to zrobić w innej kolejności? Nie będziemy bałagać się nawiasami, więc trzymamy je tam, gdzie się znajdują (po pierwsze).

Utwórz program, który przyjmuje dwa argumenty:

  • Ciąg informujący, w jakiej kolejności powinny się odbywać operacje. Oto kilka przykładów "DAMES", "SAD, ME", "ME SAD", "MEADS". Tak, spacje i przecinki są w porządku, ponieważ ułatwia zapamiętanie kolejności.
    • Następujące sugestie na czacie: Obsługa spacji i przecinków jest teraz opcjonalna.
    • Jeśli brakuje jednej z liter lub istnieją dodatkowe litery, których nie powinno tam być, możesz uznać dane wejściowe za nieprawidłowe i traktować je tak, jak chcesz.
  • Ciąg lub wyrażenie zawierające wyrażenie, które należy ocenić.

Zwraca wynik wyrażenia jako liczbę dziesiętną lub liczbę całkowitą. Jeśli odpowiedź nie jest liczbą całkowitą, należy ją zwrócić jako liczbę dziesiętną.

Zasady:

  • Można połączyć dwa argumenty wejściowe w jeden, jeśli w twoim języku jest to łatwiejsze.
  • Nie musi to być ciąg znaków, ale musi mieć litery. Nie możesz zastąpić dodawania 1, dzielenia 2, itd.
  • Możesz wybrać, które wejście jest pierwsze.
  • Wyrażenie jest oceniane od prawej do lewej od lewej do prawej. (Zmiana reguły. Wszelkie zgłoszenia plakat z pierwszych 12 godzin, które mają odwrotnie, są akceptowane).
  • Operacje użyciu symboli: ( ) ^ * / + -. Na przykład nie można użyć ¤zamiast +dodawania.
  • Spacje w wyrażeniu wejściowym są niepoprawne jako dane wejściowe
  • Unary +/- nie jest poprawny jako dane wejściowe, jeśli bezpośrednio następuje po + lub -. Uważaj 3+-2za nieprawidłowe dane wejściowe. Można to traktować tak, jak chcesz (nie musi powodować błędu). Jeśli +lub -następuje żadnego innego operatora niż plus lub minus, jest traktowany w zwykły sposób: 3*-3 = -9,sin(-2)=-0.909
  • Program musi ściśle przestrzegać liter, więc "EMDAS", 1-3+4 => -6i "EMDSA", 1-3+4 => 2.

Przykłady:

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

Uwaga: nawiasy zostały dodane, aby pokazać, że mnożenie 4*sin(0.5^2)jest obliczane przed potęgowaniem.

To jest kod golfowy, więc wygrywa najkrótszy kod w bajtach.

Stewie Griffin
źródło
2
To nie jest dokładnie to samo, ale to wyzwanie polega na zmianie na inną kolejność operacji i było inspiracją, która sprawiła, że ​​podoba mi się pomysł zrobienia czegoś podobnego. Myślę, że odpowiedź Haskella mogłaby zostać przerobiona, by odpowiedzieć na to pytanie ... Może nie jestem pewien, czy to ścisły duplikat, podoba mi się pomysł zrobienia tego wyzwania bez natywnej możliwości bezpośredniej zmiany operatorów!
Dom Hastings,
2
Usunięto bonus za funkcje, ale w przykładach nadal występuje sin ().
edc65
Nieco więcej zła niż wyżej wspomniane wyzwanie i nie zamierzam kwestionować tego jako duplikatu (chociaż link do oryginału byłby mile widziany). Jednak dla każdego oczywiste jest, że złym reżyserem The 2560 jest nikt inny jak @Stewie Griffin. Muszę powiedzieć, że nie jestem zaskoczony.
Jake,
W Wielkiej Brytanii często uczy się nas w szkole BODMASlub BIDMASw szkole. B= Wsporniki Olub I= zamówienie lub indeksy.
BadHorsie,
Jest ppotrzebny? Nie ma tego w przykładach
ev3commander

Odpowiedzi:

7

JavaScript (ES6) 349 353 387 400

... może nadal gra w golfa

Ten mój stary parser czasem się przydaje - (już używany w innych 2 wyzwaniach)

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>

Nie golfił

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
źródło
Myślę, że możesz usunąć to miejsce (t=>t=='('?(z=1, Q.push('_'))wraz ze wszystkimi nowymi liniami.
Conor O'Brien
1
@ CᴏɴᴏʀO'Bʀɪᴇɴ pracuje nad tym. Dzięki
edc65,
Myślę, że można zmienić Math.pow(a,b), abya**b
Kritixi Lithos
@KritixiLithos tak, ale już nie będzie ES6
edc65
6

R 3.3.2: 209 196 187 177 bajtów

Chodzi o to, aby „niewłaściwie używać” nie arytmetycznych operatorów <, &, |, ~,? gdzie znamy pierwszeństwo (patrz ?SyntaxR - ale przed przesłonięciem;)) i zastępowanie ich za pomocą podanych operatorów arytmetycznych. Mapowanie odbywa się zgodnie z pożądaną kolejnością operacji.

Spacje i przecinki na wejściu nie są obsługiwane.

Wersja golfowa

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

Nie golfił i skomentował:

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

Przykłady:

> 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
źródło