Interpretiere StackyMath!


14

Zeit für Sie, meine neue Stack-basierte Sprache zu implementieren! Es heißt StackyMath. Dies ist eine stapelbasierte Sprache mit 8 Operationen auf dem Stapel und Möglichkeiten, dem Stapel Zahlen hinzuzufügen.

Liste der Operationen:

  • /: Einteilung. Wird auf den obersten 2 Nummern des Stapels ausgeführt. Schiebt das Ergebnis auf den Stapel zurück.
  • *: Multiplikation. Wird auf den obersten 2 Nummern des Stapels ausgeführt. Schiebt das Ergebnis auf den Stapel zurück
  • -: Subtraktion. Wird auf den obersten 2 Nummern des Stapels ausgeführt. Schiebt das Ergebnis auf den Stapel zurück
  • +: Ergänzung. Wird auf den obersten 2 Nummern des Stapels ausgeführt. Schiebt das Ergebnis auf den Stapel zurück
  • ^: Potenzierung. Wird auf den obersten 2 Nummern des Stapels ausgeführt. Schiebt das Ergebnis auf den Stapel zurück
  • %: Modulo. Wird auf den obersten 2 Nummern des Stapels ausgeführt. Schiebt das Ergebnis auf den Stapel zurück
  • !: Fakultät. Wird auf der obersten Zahl des Stapels ausgeführt. Schiebt das Ergebnis auf den Stapel zurück
  • D: Dupliziere die oberste Zahl auf dem Stapel

Im Pseudocode definierte Operationen:

  • /: 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)

So legen Sie Zahlen auf den Stapel:

Das Hinzufügen von Zahlen zum Stapel ist ganz einfach. Geben Sie einfach die Rohzahl in Ihr Programm ein, wo Sie sie benötigen. Wenn Sie mehrere Zahlen auf den Stapel legen müssen, können Sie diese durch ein Komma ( ,) trennen . Ihr Programm muss keine -Zahlen in der Eingabe verarbeiten. Wenn der Benutzer eine will, muss er die zu negierende Zahl, Null und drücken -. Zahlen in der Eingabe des Programms sind ebenfalls auf positive ganze Zahlen beschränkt.

Eingang:

Ihr Programm sollte die Eingabe in der Befehlszeile oder von std in übernehmen. Die Eingabe besteht nur aus Zahlen (keine wissenschaftliche Notation oder Dezimalstellen), die nach ,Bedarf durch und die oben definierten Operationen begrenzt werden.

Ausgabe:

Ihr Programm sollte die Nummer oben auf dem Stapel drucken.

Fehlerfälle:

  • Wenn das Programm versucht, den Stapel zu überladen, sollten Sie drucken StackUnderflowException!!!.
  • Wenn Sie eine Division durch Null haben, drucken Sie DivisionByZeroException!!!
  • Wenn eine Zahl größer als 64 Bit ist, drucken Sie sie, entweder während Sie das Programm ausführen oder wenn Sie eine Zahl in der Eingabe verarbeiten NumberOverflowException!!!
  • Wenn Sie auf irgendeine Weise eine negative Zahl oben auf dem Stapel haben und eine Fakultät erstellen müssen, drucken Sie NegativeFactorialException!!!
  • Wenn Sie eine Gleitkommazahl oben auf dem Stapel haben und die nächste Operation faktoriell ist, drucken Sie FloatingFactorialException!!!
  • Wenn sich beim Beenden des Programms keine Zahlen auf dem Stapel befinden (dh das Programm war leer), wird gedruckt EmptyProgram!!!

Anmerkungen:

  • Alle Fehler, die ausgegeben werden sollen, sollten "std err" oder ein gleichwertiges Ergebnis haben.
  • Alle Zahlen sind auf 64-Bit-Gleitkommazahlen beschränkt.

Beispielprogramme:

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!!!

(Ich kann bei Bedarf weitere hinzufügen)


3
Wenn es die Fehlerfälle nicht gäbe, könnte Vitsy dies natürlich tun (mit Ausnahme der Konvertierung !in F).
Addison Crump

Ich dachte, das ist zum Teil der Grund, warum ich sie aufgenommen habe.
J Atkin

3
Ihr Anwendungsbereich ist etwas breiter, obwohl es möglicherweise um ein Duplikat geht: codegolf.stackexchange.com/questions/221/…
Digitales Trauma

Wow, ich habe das vergessen. Aber ich denke nicht, dass es sich um Dupes handelt, da Sie Fehler verarbeiten müssen und mehr Operatoren in meinen definiert sind.
J Atkin

654,489,48,43/5*7D+-*%sollte zurückkehren 77.6875. ( 43/48*5-(7+7)sollte sein (7+7)-43/48*5)
user81655

Antworten:


4

Ruby, 412 410 404 392 380 377 Zeichen

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

Dies ist eine reguläre Präzisionsversion Float. Die Ergebnisgenauigkeit ist wie im Beispielcode, die numerische Überlauferkennung ist jedoch nicht genau.

Probelauf:

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

Ruby, 378 377 Zeichen

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

Dies ist eine hochpräzise Version Rational. Die Ergebnisgenauigkeit ist nicht immer dieselbe wie im Beispielcode, aber die numerische Überlauferkennung ist genau.

Probelauf:

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

3

JavaScript (ES6), 430 Byte

422 Bytes mit ES7 durch Ändern Math.pow(2,2)auf2**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!!!`

Erläuterung

Ersetzt evalbestimmte gebräuchliche Phrasen. Ungolfed und ohne das evalsieht es so aus:

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

Wenn Sie ein Upgrade auf ES7 durchführen möchten, können Sie den ES7-Exponentiationsoperator verwenden , um ihn Math.pow(p(),p())durch zu ersetzen p()**p().
Usandfriends

1
@usandfriends Ich habe darüber nachgedacht, aber es bedeutete, dass es in meinem Browser nicht funktionieren würde, also habe ich es weggelassen. : P Ich werde eine Notiz hinzufügen, die das sagt.
user81655

1

Groovy, 718 Bytes. Vordergrund!

Kannst auch mein Gerät abschicken. Lernen Sie meine große Code-Mauer kennen:

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!!!')

Ungolfed:

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!!!')

Edit 1: speichere ~ 15 Bytes dank @Doorknob
Edit 2: lösche ~ 130 Bytes mit ein paar weiteren Tricks


Ich kenne Groovy nicht, aber Sie scheinen viele unnötige Leerzeichen zu haben. Zum Beispiel in der Nähe von Betreibern, nach for/ if, usw.
Türknauf

Hoppla, habe gerade viel mehr Stellen zum Entfernen von Leerzeichen bemerkt. Danke für den Tipp.
J Atkin

Sie können System.in.textanstelle von verwenden System.in.newReader().readLine().
ein Spaghetto

Nicht wirklich. .textist gierig und solange Daten im Reader sind, werden sie nicht zurückgegeben.
J Atkin

Richtig, aber das ist Code-Golf. Es ist keine große Sache, wenn Leute nach ihrer Eingabe Control-D eingeben müssen.
ein Spaghetto

1

Candy , 298 348 392 Bytes

Obwohl Candy stapelbasiert ist, bin ich mir nicht sicher, ob das wirklich geholfen hat ...

&{|"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*).

Ein bisschen formatiert offenbart ein bisschen 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*).

Die eigentliche Berechnung erfolgt in den letzten beiden Zeilen. Es wird dort von einem Sprungtisch in der dritten Zeile gefahren.


Verdammt, ich sehe, dass ich DivisionByZero, NegativeFactorial und Overflow verpasst habe. Ich habe mir nur die Testfälle angesehen!
Dale Johnson

Wow, das ist cool. Ich muss vielleicht Süßigkeiten nachschlagen.
J Atkin

Ich arbeite immer noch daran, wie man den Überlauf genau definiert .
Dale Johnson

Eigentlich hatte ich das gleiche Problem in meiner Antwort. Siehe die Kommentare unter meiner Antwort.
J Atkin

Der Überlauf wurde behoben. Ich habe den gleichen Ansatz wie der Ruby verwendet, der nur am Ende jeder Operation mit 2 ^ 64 verglichen werden soll.
Dale Johnson
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.