Tafsirkan StackyMath!

14

Saatnya Anda menerapkan bahasa berbasis tumpukan baru saya! Ini disebut StackyMath. Ini akan menjadi bahasa berbasis stack dengan 8 operasi pada stack dan cara-cara untuk menambahkan angka ke stack.

Daftar operasi:

  • /: Divisi. Dilakukan di 2 angka teratas tumpukan. Dorong kembali hasilnya di tumpukan.
  • *: Perkalian. Dilakukan di 2 angka teratas tumpukan. Dorong kembali hasilnya di tumpukan
  • -: Pengurangan. Dilakukan di 2 angka teratas tumpukan. Dorong kembali hasilnya di tumpukan
  • +: Penambahan. Dilakukan di 2 angka teratas tumpukan. Dorong kembali hasilnya di tumpukan
  • ^: Eksponensial. Dilakukan di 2 angka teratas tumpukan. Dorong kembali hasilnya di tumpukan
  • %: Modulo. Dilakukan di 2 angka teratas tumpukan. Dorong kembali hasilnya di tumpukan
  • !: Faktorial. Dilakukan di nomor atas di tumpukan. Dorong kembali hasilnya di tumpukan
  • D: Gandakan nomor teratas di tumpukan

Operasi yang didefinisikan dalam kode semu:

  • /: push(pop divided by pop)
  • *: push(pop times pop)
  • -: push(pop minus pop)
  • +: push(pop plus pop)
  • ^: push(pop to the pop)
  • %: push(pop mod pop)
  • !: push(factorial pop)
  • D: t = pop; push(t); push(t)

Cara mendorong angka ke tumpukan:

Menambahkan nomor ke tumpukan itu mudah, cukup masukkan angka mentah di program Anda di mana Anda membutuhkannya. Jika Anda perlu meletakkan beberapa angka di tumpukan, Anda dapat memisahkannya dengan koma ( ,). Program Anda tidak perlu memproses -angka dalam input, Jika pengguna menginginkannya, mereka harus menekan angka yang ingin dinegasikan, nol, dan -. Angka dalam input program juga dibatasi untuk bilangan bulat positif.

Memasukkan:

Program Anda harus mengambil input pada baris perintah, atau dari std in. Input hanya akan terdiri dari angka (tidak ada notasi ilmiah atau desimal) yang dibatasi oleh ,sesuai kebutuhan, dan operasi yang ditentukan di atas.

Keluaran:

Program Anda harus mencetak nomor di bagian atas tumpukan.

Kasus kesalahan:

  • Jika program mencoba untuk over-pop stack, Anda harus mencetak StackUnderflowException!!!.
  • Jika Anda memiliki pembagian dengan nol, cetak DivisionByZeroException!!!
  • Jika angka yang melebihi 64-bit, baik saat menjalankan program atau memproses angka dalam input, cetak NumberOverflowException!!!
  • Jika entah bagaimana Anda mendapatkan angka negatif di bagian atas tumpukan dan Anda perlu melakukan faktorial, cetak NegativeFactorialException!!!
  • Jika Anda memiliki nomor floating point di bagian atas tumpukan dan operasi selanjutnya adalah faktorial, cetak FloatingFactorialException!!!
  • Jika tidak ada angka pada tumpukan ketika program keluar (mis. Program kosong) cetak EmptyProgram!!!

Catatan:

  • Semua output kesalahan harus mendapat kesalahan atau setara terdekat.
  • Semua angka dibatasi ke titik apung 64-bit.

Contoh program:

50,47*                 -> 2350
50,47/                 -> 0.94
100,8!                 -> 40320  
100D*                  -> 10000
!                      -> StackUnderflowException!!!
5,2/!                  -> FloatingFactorialException!!!  
4,3!2*/                -> 3 
654,489,48,43/5*7D+-*% -> 77.68749999999909
                       -> EmptyProgram!!!

(Saya dapat menambahkan lebih banyak jika diperlukan)

J Atkin
sumber
3
Jika bukan karena kasus Kesalahan, Vitsy dapat melakukan ini secara alami (kecuali mengonversi !ke F).
Addison Crump
Saya pikir, itu sebabnya saya memasukkan mereka.
J Atkin
3
Ruang lingkup Anda agak lebih luas, meskipun dapat diperdebatkan bahwa ini merupakan duplikat: codegolf.stackexchange.com/questions/221/…
Digital Trauma
Wow, saya lupa tentang itu. Tetapi saya tidak berpikir mereka adalah dupes karena Anda harus memproses kesalahan dan lebih banyak operator didefinisikan di tambang.
J Atkin
654,489,48,43/5*7D+-*%harus kembali 77.6875. ( 43/48*5-(7+7)seharusnya (7+7)-43/48*5)
user81655

Jawaban:

4

Ruby, 412 410 404 392 380 377 karakter

def e m,x='Exception';warn m+x+?!*3;exit;end
def o;e'StackUnderflow'if$*==[];$*.pop;end
u=->n{e'DivisionByZero'if n.infinite?;e'NumberOverflow'if n>2**64;$*<<n}
f=->n{e'NegativeFactorial'if n<0;e'FloatingFactorial'if n.to_i<n;n<2?1:f[n-1]*n}
gets.gsub(/(\d+)|([+*\/%^-])|(!)|D/){$1?u[$1.to_f]:$2?u[eval"o#{$2>?A?:**:$2}o"]:$3?u[f[o]]:u[x=o]+u[x]}
e'EmptyProgram',''if$*==[]
p o

Ini adalah versi presisi reguler yang digunakan Float. Ketepatan hasil seperti pada kode sampel, tetapi deteksi numerik tidak tepat.

Contoh dijalankan:

bash-4.3$ ruby StackyMath.rb <<< '654,489,48,43/5*7D+-*%'
77.68749999999909

Ruby, 378 377 karakter

def e m,x='Exception';warn m+x+?!*3;exit;end
def o;e'StackUnderflow'if$*==[];$*.pop;end
u=->n{e'NumberOverflow'if n>2**64;$*<<n}
f=->n{e'NegativeFactorial'if n<0;e'FloatingFactorial'if n.to_i<n;n<2?1:f[n-1]*n}
gets.gsub(/(\d+)|([+*\/%^-])|(!)|D/){$1?u[Rational$1]:$2?u[eval"o#{$2>?A?:**:$2}o"]:$3?u[f[o]]:u[x=o]+u[x]}rescue e'DivisionByZero'
e'EmptyProgram',''if$*==[]
p o.to_f

Ini adalah versi presisi tinggi yang digunakan Rational. Ketepatan hasil tidak selalu sama dengan dalam kode sampel, tetapi deteksi numerik overflow tepat.

Contoh dijalankan:

bash-4.3$ ruby StackyMath-hi.rb <<< '654,489,48,43/5*7D+-*%'
77.6875
manatwork
sumber
3

JavaScript (ES6), 430 byte

422 byte dengan ES7 dengan mengubah Math.pow(2,2)ke2**2

e=m=>{throw alert(m)};u=prompt();u?alert(eval('u.match(/\\d+|[^,]/g).map(o=>s.push(t=o=="/"?(b=p(a=2))?a/b:e`DivisionByZero43*"?2*23-"?2-23+"?2+23%"?2%23^"?Math.pow(2,2)3D"?s.push(r=2)&&r3!"?eval("for(r=i=2;i<0?e`Negative54:i%1?e`Floating54:--i;)r*=i;r"):+o)&&t==Infinity&&e`NumberOverflow4,s=[],p=_=>s.length?s.pop():e`StackUnderflow4);t'.replace(/[2-5]/g,x=>[,,'p()',':o=="','Exception!!!`','Factorial'][x]))):e`EmptyProgram!!!`

Penjelasan

Penggunaan evaluntuk mengganti frasa umum tertentu. Tidak disatukan dan tanpa evalitu terlihat seperti ini:

e=m=>{throw alert(m)};                           // e = throw error, alert displays
                                                 //     message, throw stops execution
u=prompt();                                      // u = received input
u?alert(                                         // display the result
  u.match(/\d+|[^,]/g)                           // get array of numbers and operators
    .map(o=>                                     // iterate over operators
      s.push(t=                                  // t = last pushed value

        // Execute operator
        o=="/"?(b=p(a=p()))?a/b:                 // make sure argument B is not 0
          e`DivisionByZeroException!!!`:
        o=="*"?p()*p():
        o=="-"?p()-p():
        o=="+"?p()+p():
        o=="%"?p()%p():
        o=="^"?Math.pow(p(),p()):
        o=="D"?s.push(r=p())&&r:
        o=="!"?eval("                            // eval to enable for loop in ternary
          for(                                   // no factorial in JS so do this manually
            r=i=p();
            i<0?e`NegativeFactorialException!!!` // check for errors
              :i%1?
                e`FloatingFactorialException!!!`
                :--i;
          )
            r*=i;
          r"):                                   // return r
        +o                                       // if not an operator cast as a number
      )&&t==Infinity&&                           // JS turns anything over 64 bit float
        e`NumberOverflowException!!!`,           //     max value into Infinity
      s=[],                                      // s = stack array
      p=_=>s.length?s.pop():                     // p = check stack then pop
        e`StackUnderflowException!!!`
    )&&t                                         // return top stack element
  ):e`EmptyProgram!!!`                           // error if input length is 0
pengguna81655
sumber
Jika Anda ingin meng-upgrade ke ES7, Anda bisa menggunakan operator yang ES7 exponentiation untuk menggantikan Math.pow(p(),p())dengan p()**p().
usandfriends
1
@usandfriends saya sedang memikirkannya, tapi itu berarti itu tidak akan berfungsi di browser saya jadi saya meninggalkannya. : P Saya akan menambahkan catatan yang mengatakan itu.
user81655
1

Groovy, 718 byte. Depan!

Semoga posting golf saya jadi golf. Temui tembok besar kode saya:

g='Exception!!!'
a={System.err.print(it);System.exit(1)}
b=new Stack()
c={b.push(it)}
v=2d**64d
d={b.pop()}
e={if(b.size()<it)a('StackUnderflow'+g)}
f={a('NumberOverflow'+g)}
h={e(2)
c(Eval.xy(d(),d(),"x$it y"))
if(b.peek()>v)f()}
k={i->if(i<0)a('NegativeFactorial'+g)
if(Math.abs(i-(i as long))>1E-6)a('FloatingFactorial'+g)
(2..i).inject{x,y->(v/x<y)?f():x*y}}
l=['/':{e(2)
m=d()
n=d()
if(n==0)a('DivisionByZero'+g)
c(m/n)},'!':{e(1)
c(k(d()))},'D':{e(1)
c(b.peek())}]
System.in.newReader().readLine().findAll(~/\d+|[^,]/).each{x->if(x.matches(/\d+/))try{c(x as double)}catch(Exception e){f()}
else if("+-*%^".contains(x))h(x.replace('^','**'))
else l[x]()}
if(b){o=d()
if(Double.isInfinite(o))f()
println o}else a('EmptyProgram!!!')

Tidak Disatukan:

error = {System.err.print(it);System.exit(1)}

stack = new Stack()
maxVal = 2d**64d

push = {stack.push(it)}
pop = {stack.pop()}

checkAtLeast = {if (stack.size() < it) error('StackUnderflow'+exception)}
numberOverflow = {error('NumberOverflow'+exception)}

exception = 'Exception!!!'

def dArgOp(i) {
    checkAtLeast(2)
    push(Eval.xy(pop(), pop(), "x$i y"))
    if(stack.peek() > maxVal) numberOverflow
}

factorial = {i->
    if (i < 0)
        error('NegativeFactorial'+exception)
    if (Math.abs(i - (i as long)) > 1E-6)
        error('FloatingFactorial'+exception)
    (2..i).inject {acc, it ->
        (maxVal/acc < it)?numberOverflow():acc*it
    }
}

ops = [
'/' : {
    checkAtLeast(2)
    first = pop()
    second = pop()
    if (second == 0)
        error('DivisionByZero'+exception)
    push(first / second)
},
'!' : {
    checkAtLeast(1)
    push(factorial(pop()))
},
'D' : {
    checkAtLeast(1)
    push(stack.peek())
}]

input = System.in.newReader().readLine()
tokens = input.findAll(~/\d+|[^,]/)

tokens.each {
    print "current token: $it  \t stack before eval: $stack "
    if (it.matches(/\d+/))
        try {
            push(it as double)
        } catch (Exception e) {
            numberOverflow()
        }

    else if ("+-*%^".contains(it))
        dArgOp(it.replace('^','**'))
    else
        ops[it]()
    println "result: ${stack.peek()}"
}

if (stack) {
    top = pop()
    if (Double.isInfinite(top))
        numberOverflow()
    println top
} else
    error('EmptyProgram!!!')

Sunting 1: simpan ~ 15 byte berkat @Doorknob
Sunting 2: drop ~ 130 byte dengan beberapa trik lainnya

J Atkin
sumber
Saya tidak tahu Groovy, tetapi Anda tampaknya memiliki banyak ruang kosong yang tidak perlu. Misalnya, di sekitar operator, setelah for/ if, dll
Gagang Pintu
Aduh, baru saja memperhatikan lebih banyak tempat untuk menghapus spasi putih. Terima kasih atas tipnya.
J Atkin
Anda bisa menggunakan System.in.textbukan System.in.newReader().readLine().
spaghetto
Tidak juga. .textserakah dan selama data di dalam pembaca, itu tidak akan kembali.
J Atkin
Benar, tapi ini golf kode. Ini bukan masalah besar jika orang harus mengetik Control-D setelah masukan mereka.
spaghetto
1

Candy , 298 348 392 byte

Meskipun Candy berbasiskan tumpukan, aku tidak yakin itu benar-benar membantu ...

&{|"EmptyProgram!!!\n"(;).}(=bYZay0=zx4k"!%*+,-/D^"(iYe{Z=x})aYb=z=ya=X{Y{cZ0=yza}b212202221(i=ZXe{y})a0=zcY0j{XjZ{|D1b#64R(=c2*)c>{b"NumberOverFlow"(;)i}}|i}aZ{(=)"Exception!!!\n"(;).}0=yz|A#48-Z#10*+=z1=y})c?(=).@0&<{1|b"StackUnderflow"(;)c0}.@1~ALe{A0<{b"Negative"(;)i|1bAR(=cA*)}|b"Floating"(;)i}Z{b"Factorial"(;)}.@2W%.@3*.@4+@5.@6W-.@7WD{/|b"DivisionByZero"(;)i}.@8~A.@9=xK=y=1bA_(cX*).

Sedikit yang diformat memperlihatkan sedikit struktur:

&{|"EmptyProgram!!!\n"(;).}
(=bYZay0=zx4k
  "!%*+,-/D^"
  (iYe{Z=x})
  aYb=z=ya=X
  {
    Y{cZ0=yza}b
    212202221(i=ZXe{y})
    a0=zcY0j
    {XjZ{|D1b#64R(=c2*)c>{b"NumberOverFlow"(;)i}}|i}
    aZ{(=)"Exception!!!\n"(;).}
    0=yz|A#48-Z#10*+=z1=y
  }
)c?(=).
@0&<{1|b"StackUnderflow"(;)c0}.
@1~ALe{A0<{b"Negative"(;)i|1bAR(=cA*)}|b"Floating"(;)i}Z{"Factorial"(;)}.
@2W%.@3*.@4+@5.@6W-.@7WD{/|"DivisionByZero"(;)i}.@8~A.@9=xK=y=1bA_(cX*).

Matematika aktual terjadi pada dua baris terakhir. Di sana didorong oleh meja lompatan di baris ketiga.

Dale Johnson
sumber
Dang, saya melihat bahwa saya merindukan DivisionByZero, NegativeFactorial, dan Overflow. Saya hanya melihat-lihat test case!
Dale Johnson
Wow, ini keren. Aku mungkin perlu mencari permen.
J Atkin
Saya masih bekerja tentang bagaimana tepatnya mendefinisikan overflow.
Dale Johnson
Sebenarnya saya punya masalah yang sama dalam jawaban saya. Lihat komentar di bawah jawaban saya.
J Atkin
Memperbaiki Overflow sekarang. Saya menggunakan pendekatan yang sama dengan Ruby, yang hanya membandingkan dengan 2 ^ 64 pada akhir setiap operasi.
Dale Johnson