注文の操作


13

前書き

あなたが足し算と掛け算をマスターしたと思うとき、子供時代にポイントが来ます、そして、誰かが一緒に来て、あなたにそれを知らせます:

a * b + c =(a * b)+ c!= a *(b + c)、

そして、それはあなたが以前に教えられたほど単純または線形のプロセスではなかった。操作順序と呼ばれるものがあることを学びます。これは、括弧がすべての邪魔になることなく、一定レベルの一貫性と式を維持するための非常に重要な方法です。

一般的なストーリー

ある日、あなたは路上でパニックの音に目覚めます。「The 2560」という名前の過激派グループ(「作戦命令に反する組織」の略で、不気味な六角形のひねりを加えたもの)は、世界中のすべての核兵器を支配するために悪の手法を使用しています。彼らは惑星全体を人質にしており、単純な要求があります。受け入れられた作戦の順序を逆にするか、根絶に直面します(括弧は優先順位を維持するためです)。新しいシステムはPSADME(括弧、減算/加算、除算/乗算、指数)と呼ばれ、式は右から左に評価します。

a - b - c = a - (b - c) = a + c - b

数日が経過し、移行が進行中です。数学者と物理学者はすべて方程式を書き直すのに忙しいのですが、コンピューター科学者は数式がコンピューターによって解釈される方法を変えるという課題に直面しています。偶然、あなたがランダムで選択されていると、 -あなたは、新しいグローバル君主のために多くの苦しみとして原因を目指して秘密の反乱プログラミング・グループに属している2560とベンチマーク計算プログラムを生成するために任務。

あなたの使命

13+4=17=6。

簡単にするために、提供されるすべての数値は整数であり、計算により整数の結果が生成されます。

ルールとスコアリング

  • プログラムは、最大128文字の長さの入力を受け入れる必要があります-言語/プラットフォームの最大入力長が短い場合、それは許容できる言い訳です。
  • 標準的な抜け穴は禁止されています。
  • 受賞コードは、11月18日に選択されます(この投稿日から4週間)。
  • ゴルフに値するとは思われないコードを投稿してください。これは楽しいことです。これを行う興味深い方法があるが、自分で(または方法の性質によって)ゴルフできない場合は、とにかく投稿できます。

いつものように、勝利コードはバイト数が最も少ないもので、エンターテイメント価値のボーナスがあります:

  • -5は、提供された式での文字の使用を避けるために:+-^*/
  • -5を計算するために、標準のコンピューターで計算するのに5分以上(ただし10分以内)かかりますが、方法は明らかではありません(クロックまたは不要なループを使用)。目的は、あなたが運命の計算を混乱させようとしていないことを新しい支配者に納得させることです。
  • -(5 + N)を使用して、コード内でわかりやすい形で記述される2560のメンバーに関する直接攻撃メッセージ(長さN、先頭/末尾の空白を含まない)、およびそれが必要な理由についてのばかげた説明そこ。削除された場合、コード正しく機能してはなりません。はい、エンターテイメント価値の無料ポイント。

例と説明

[program] 2 - 2 - 2
2

2-(2-2)= 2

[program] (2 + 2 * 3 + 3) / 3 + 3
4

(4 * 6)/(3 + 3)= 4

[program] 3 + 2 + 1 ^ 3
216

(3 + 2 + 1)^ 3 = 216

[program] -5^2
25

(-5)^ 2 = 25

[program] 32 / 8 * 3 - 1
2

32 /(8 *(3-1))= 32/16 = 2


1 - 3 + 4 = 1 - 7?右から左にそのように提案されますが、それはPSADMEとは反対に、減算よりも加算を優先しているのですか?
LLlAMnYP

1
@LLlAMnYP加算と減算はPEMDASの場合と同様に同じ「グループ」内にあるため、右から左に発生します。乗算/除算でも同じです。のようなものP(SA)(DM)Eです。
ジオビット

2
このステートメントは、右から左に処理されることを意図したものではありません-むしろ、同等の優先順位の操作は右から評価されます。4/2 = 2、2-1 = 1ですが、通常の(a / b)* cではなくa / b c = a /(b c)です。これで問題が解決することを願っています。
ジェイク

これを行う最も簡単な方法は、おそらくflex / bisonまたはlex / yacc文法を作成することです。

5
頭字語をPADMEに変更する必要があります。このような悪の組織のメンバーは、オリジナルよりも新しいスターウォーズの3部作を好むからです。覚えやすいです。
mbomb007

回答:


9

Haskell、134バイト

import qualified Prelude as P
infixl 6 ^
(^)=(P.^)
infixr 8 + 
(+)=(P.+)
infixr 8 - 
(-)=(P.-)
infixr 7 /
(/)=P.div
infixr 7 *
(*)=(P.*)

新しい修正と優先順位を使用して数学演算子を再定義します。今:

*Main> 32 / 8 * 3 - 1
2

1
ワオ。ただ、すごい。これは他の言語でも可能ですか?+1
ETHproductions

Mathematicaで、または少なくとも同様のアプローチで可能だったと確信していましたが、すぐに気付きました。
LLlAMnYP

1
私はここで十分に新しいので、このフォーラムで次の提案が通常受け入れられるかどうか確信が持てません。コードに完全に基づいていますが、Perlを使用してHaskellファイルを生成し、GHCiに渡すbashスクリプトです。そうすることで、全体のバイトを保存します。 perl -e'$_="import qualified Prelude as Pl 6^r 8+r 8-r 7*r 7/";s/(. \d(.))/\ninfix\1\n(\2)=(P.\2)/g;s~\./~.div~;print'>a.hs;ghci a.hs あいにく、タイプミスにより、生成されたコードには数字と記号の間にスペースがありませんが、それでも正常に動作します。これは、コードが5バイトを失う可能性があることを意味し、私の「改善」に打ち勝ちます。
ジェイク

@JArkinstallその価値については、sedシェルコードの生成と評価に効果的に使用しています。おそらく良いメタ質問です。
デジタル外傷

それは事実であり、私はあなたのアプローチが本当に好きです-しかし、ツール(perlまたはsed)を使用して言語のファイルを生成し、それを別の言語に読み込むと、さらに一歩進んだようです。別のジェネレーターを介して上記のコードを生成する方法が存在する場合(メソッドは私には明らかではありませんが!)、過度に驚くことはありません。これが許容できる場合は、このアプローチをコードに適用することもできます(このボード上のいくつかの課題に対する読みやすい言語の回答で見たいくつかの例)。
ジェイク

2

GNU sed -r、exec拡張付き、398

s@ *\^ *@ ** @
:
s@\((-?[0-9]+)\)@\1@
t
s@(-?[0-9]+ - )+(-?[0-9]+ - -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [-+] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ / )+(-?[0-9]+ / -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ [*/] -?[0-9]+)(.*)@echo '\1'$((\3))'\4'@e
t
s@(-?[0-9]+ \*\* )+(-?[0-9]+ \*\* -?[0-9]+)@\1(\2)@
t
s@(.*(^| |\())(-?[0-9]+ \*\* -?[0-9]+)(.*)@bash -c 'echo \1$[\3]\4'@e
t

特に短いわけではありませんが、仕事は完了です。

sedは優先順位を解析するのには問題ありませんが、算術は行いません。したがって、sコマンドにGNU sed exec拡張機能を使用して、必要な演算をシェルにアウトソースします。

とりあえず^、前と後ろにちょうど1つのスペースがあることを除いて、すべてのオペレーターを想定しています。

テスト出力:

$ cat psadme.txt 
2 - 2 - 2
(2 + 2 * 3 + 3) / 3 + 3
3 + 2 + 1 ^ 3
-5^2
32 / 8 * 3 - 1
$ sed -rf psadme.sed psadme.txt 
2
4
216
25
2
$ 

素敵なプロフィール写真。xD
オリバーNi

1

JavaScript(ES6)287 300

編集バグを修正しました(単にタイプミス、6が4となっているはずですが) -スニペットの最後に完全な説明を追加しました

編集2別の課題に取り組んでいるいくつかの改善を発見

わずかな違いを除いて、同じパーサーの別の移植。(これと比較してください

f=(x,W=[],Q=['('],z=1,h=p=>'+-*/^^))('.indexOf(p)>>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());z&&Q.push(q,n)})=>((x+')').replace(/\d+|\S/g,t=>t>'('?t>'('?~h(t)?z&&t=='-'?z=-z:C(t,z=1):(W.push(z*t),z=0):C(t,z=0):(Q.push(t),z=1)),W.pop())

// More readable
U=(x,W=[],Q=['('],z=1,
  h=p=>'+-*/^^))('.indexOf(p)>>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());
    z&&Q.push(q,n)
  }
)=>(
  (x+')')
  .replace(/\d+|\S/g,t=> 
       t>'('
       ?t>'('
       ?~h(t)
       ?z&&t=='-'?z=-z:C(t,z=1)
       :(W.push(z*t),z=0)
       :C(t,z=0)
       :(Q.push(t),z=1)
  ),
  W.pop()
)

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

console.log(f('1 - 3 + 4')) // -6
console.log(f('2-2-2')) // 2
console.log(f('(2 + 2 * 3 + 3) / 3 + 3')) // 4
console.log(f('3 + 2 + 1 ^ 3')) // 216
console.log(f('-5^2')) // 25
console.log(f('32 / 8 * 3 - 1')) // 2

// Explained
X=(x,W=[],Q=['('],z=1,
  h=p=> // operator priority '+-:1, */:3, ^:5, ):7, (:9. If an operand then -1
     '+-*/^^))('.indexOf(p)>>1,
  C=n=>{ // Evaluate operators present on stack if they have upper priority, then push new operator on stack
    //console.log('Operand '+n)
    while( h(q = Q.pop()) < h(n) ) // pop operator from op stack and compare priority with current
    {
      // Pop operands from stack and push result
      b = W.pop();
      a = W.pop();
      r = q=='^' ? Math.pow(a,b) : eval('a'+q+'b')
      // console.log('Evaluate '+a+q+b+'='+r)
      W.push(r);
    }
    // if z == 0 do nothing, because the current operands are '(' and ')' that must be discarded
    // else Push again the last operator popped and the current one
    z && Q.push(q, n) // 
  }
)=>(
  (x+')')
  .replace(/[\d.]+|\S/g,t=> {
    //console.log('Q:'+Q,'W:'+W,'T:'+t,'U:'+h(t),'Z:'+z), // display status
    if (t == '(') 
    { // open parenthesis
      z = 1
      Q.push(t) // push a operator, its the highest priority
    }
    else if (t == ')')
    { //close parenthesis
      z = 0
      C(t) 
    }
    else if (h(t) < 0)
    { // operand
      W.push(z*t) // push operand with right sign
      z = 0 // set z to 0 to mark that we just pushed an operand, so next '-' (if present) is a binary operator 
    }
    else
    { // operator
      if (z && t=='-') // the minus is an unary operator (the only unary operator allowed is '-', '+' will not work)
        z =-z // change the sign
      else
        z = 1, // no unary minus
        C(t)
    }    
  }),
  W.pop() // return the value at top of operand stack
)
<pre id=O></pre>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.