Дамс, делай математику!

19

Порядок операций, PEMDAS, является основным правилом в математике, говорящим нам, какие операции порядка должны быть выполнены:

«Скобки, экспоненты, умножение и деление, а также сложение и вычитание»

Проблема в том, что PEMDAS не очень универсален! Что делать, если вы хотите сделать это в другом порядке? Мы не будем связываться с круглыми скобками, поэтому мы держим их там, где они есть (сначала).

Создайте программу, которая принимает два аргумента:

  • Строка, указывающая, в каком порядке должны следовать операции. Вот некоторые примеры "DAMES", "SAD, ME", "ME SAD", "MEADS". Да, с пробелами все в порядке, так как порядок легче запомнить.
    • Следующие предложения в чате: Поддержка пробелов и запятых теперь не является обязательной.
    • Если одна из букв отсутствует или есть дополнительные буквы, которых не должно быть, вы можете считать введенные данные недействительными и обрабатывать их по своему усмотрению.
  • Строка или выражение, содержащее выражение, которое должно быть оценено.

Возвращает результат выражения в виде десятичного числа или целого числа. Если ответ не является целым числом, он должен быть возвращен как десятичное число.

Правила:

  • Можно объединить два входных аргумента в один, если это проще на вашем языке.
  • Это не обязательно должна быть строка, но в ней должны быть буквы. Вы не можете заменить сложение на 1, деление на 2 и т. Д.
  • Вы можете выбрать, какой вход является первым.
  • Выражение вычисляется справа налево слева направо. (Изменение правила. Принимаются любые постеры, подающие первые 12 часов с обратным ходом).
  • Операции использовать символы: ( ) ^ * / + -. Например, вы не можете использовать ¤вместо +добавления.
  • Пробелы во входном выражении недопустимы в качестве входных
  • Унарный +/- недопустим в качестве ввода, если он непосредственно следует за + или -. Считать 3+-2неверным ввод. Это можно обработать как угодно (не должно выдавать ошибку). Если +или -следует какой - либо другой оператор , чем плюс или минус, он рассматривается как обычно: 3*-3 = -9,sin(-2)=-0.909
  • Программа должна строго следовать буквам, а значит "EMDAS", 1-3+4 => -6и "EMDSA", 1-3+4 => 2.

Примеры:

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

Обратите внимание, что скобки добавлены, чтобы показать, что умножение 4*sin(0.5^2)вычисляется до возведения в степень.

Это код гольф, поэтому выигрывает самый короткий код в байтах.

Стьюи Гриффин
источник
2
Это совсем не то же самое, но эта проблема связана с переходом на другой порядок операций, и именно это вдохновило меня на мысль сделать что-то подобное. Я думаю, что ответ на Haskell может быть переработан, чтобы ответить на этот вопрос, возможно ... Не уверен, что если строгий дубликат, мне очень нравится идея выполнить эту задачу без встроенной способности напрямую менять операторов!
Дом Гастингс
2
Бонус за функции удален, но в примерах все еще есть sin ().
edc65
Несколько больше зла, чем вышеупомянутый вызов, и я не собираюсь оспаривать его как дубликат (хотя ссылка на оригинал была бы оценена). Однако всем ясно, что злой режиссер The 2560 - не кто иной, как @Stewie Griffin. Я должен сказать, я не удивлен.
Джейк,
В Великобритании нас часто учат этому как BODMASили BIDMASв школе. B= Скобки Oили I= порядок или индексы.
BadHorsie
Является ли это pнеобходимо? Это не в примерах
ev3commander

Ответы:

7

JavaScript (ES6) 349 353 387 400

... возможно все еще играем в гольф

Этот старый мой парсер иногда пригодится - (уже использовался в двух других задачах)

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>

Ungolfed

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
источник
Я думаю, что вы можете удалить пробел (t=>t=='('?(z=1, Q.push('_')), вместе со всеми новыми строками.
Конор О'Брайен,
1
@ CᴏɴᴏʀO'Bʀɪᴇɴ работает над этим. Спасибо
edc65
Я думаю , что вы можете изменить , Math.pow(a,b)чтобыa**b
Kritixi Lithos
@KritixiLithos да, но это не будет ES6 больше
edc65
6

R 3.3.2: 209 196 187 177 байтов

Идея состоит в том, чтобы «неправильно использовать» неарифметические операторы <, &, |, ~,? где мы знаем приоритет (см. ?Syntaxв R - но перед переопределением;)) и переопределяем их с помощью заданных арифметических операторов. Отображение осуществляется в соответствии с желаемым порядком операций.

Пробелы и запятые на входе не поддерживаются.

Гольф версия

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

Развернулся и прокомментировал:

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

Примеры:

> 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
Патрик Рукс
источник