StackyMath를 해석하십시오!


14

새로운 스택 기반 언어를 구현할 시간입니다! 그것을 StackyMath라고합니다. 이것은 스택에 8 개의 연산과 스택에 숫자를 추가하는 방법을 가진 스택 기반 언어입니다.

작업 목록 :

  • /: 부서. 스택의 상위 2 개 숫자에서 수행됩니다. 결과를 스택으로 다시 푸시합니다.
  • *: 곱셈. 스택의 상위 2 개 숫자에서 수행됩니다. 스택에서 결과를 다시 푸시
  • -: 빼기. 스택의 상위 2 개 숫자에서 수행됩니다. 스택에서 결과를 다시 푸시
  • +: 추가. 스택의 상위 2 개 숫자에서 수행됩니다. 스택에서 결과를 다시 푸시
  • ^: 지수. 스택의 상위 2 개 숫자에서 수행됩니다. 스택에서 결과를 다시 푸시
  • %: 모듈로. 스택의 상위 2 개 숫자에서 수행됩니다. 스택에서 결과를 다시 푸시
  • !: 계승. 스택의 최상위 번호에서 수행됩니다. 스택에서 결과를 다시 푸시
  • D: 스택에서 최상위 번호를 복제

의사 코드로 정의 된 연산 :

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

숫자를 스택에 푸시하는 방법 :

스택에 숫자를 추가하는 것은 쉽습니다. 필요한 경우 프로그램에 원시 숫자를 넣으십시오. 스택에 여러 숫자를 입력해야하는 경우 쉼표 ( ,) 로 구분할 수 있습니다 . 프로그램은 -입력에서 숫자 를 처리 할 필요가 없습니다 . 사용자가 1을 원하면 부정하고 싶은 숫자를 0으로 밀어야합니다 -. 프로그램 입력의 숫자도 양의 정수로 제한됩니다.

입력:

프로그램은 명령 행 또는 표준 입력에서 입력을 가져와야합니다. 입력은 다음으로 구분 된 숫자 (과학적 표기법 또는 소수 없음)로만 구성됩니다. , 필요에 따라 와 위에 정의 된 연산으로 .

산출:

프로그램은 스택 상단에 번호를 인쇄해야합니다.

오류 사례 :

  • 프로그램이 용지를 너무 많이 넣으려고하면 인쇄해야합니다. StackUnderflowException!!! .
  • 0으로 나누면 인쇄 DivisionByZeroException!!!
  • 프로그램을 실행하거나 입력에서 숫자를 처리하는 동안 64 비트를 초과하는 숫자가 인쇄되면 NumberOverflowException!!!
  • 어떻게 든 스택 상단에 음수가 생기고 계승을 해야하는 경우 인쇄하십시오. NegativeFactorialException!!!
  • 스택 상단에 부동 소수점 숫자가 있고 다음 작업이 계승 인 경우 인쇄 FloatingFactorialException!!!
  • 프로그램이 종료 될 때 스택에 숫자가없는 경우 (예 : 프로그램이 비어 있음) 인쇄 EmptyProgram!!!

노트:

  • 에 대한 모든 오류 출력에 오류가 발생하거나 가장 가까운 값을 가져야합니다.
  • 모든 숫자는 64 비트 부동 소수점으로 제한됩니다.

예제 프로그램 :

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

(필요한 경우 더 추가 할 수 있습니다)


3
는 경우 오류 아니었다면, Vitsy는 (변환을 제외하고 자연적으로이 작업을 수행 할 수 !F).
Addison Crump

나는 그것이 부분적으로 내가 그것들을 포함시킨 이유라고 생각했다.
J Atkin

3
이 논쟁의 여지가있을 수 있지만 당신은 범위가 다소 넓다 자사의 중복 : codegolf.stackexchange.com/questions/221/...
디지털 외상

와우, 나는 그것에 대해 잊었다. 그러나 오류를 처리해야하고 더 많은 연산자가 내 정의되어 있기 때문에 그것들이 속박이라고 생각하지 않습니다.
J Atkin

654,489,48,43/5*7D+-*%반환해야합니다 77.6875. ( 43/48*5-(7+7)해야한다 (7+7)-43/48*5)
user81655

답변:


4

루비 412 개 410 404 392 380 377 문자

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

이것은를 사용하는 일반 정밀 버전 Float입니다. 결과 정밀도는 샘플 코드와 같지만 숫자 오버플로 감지는 정확하지 않습니다.

샘플 실행 :

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

루비, 378 377 자

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

를 사용하는 고정밀 버전 Rational입니다. 결과 정밀도는 항상 샘플 코드와 동일하지 않지만 숫자 오버플로 감지는 정확합니다.

샘플 실행 :

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

3

자바 스크립트 (ES6), 430 바이트

ES7에서 422 바이트 Math.pow(2,2)2**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!!!`

설명

용도는 eval특정 일반적인 문구를 교체합니다. ungolfed와 eval그것 없이 다음과 같이 보입니다 :

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

ES7로 업그레이드하려는 경우 ES7 지수 연산자 를 사용하여 로 바꿀 수 Math.pow(p(),p())있습니다 p()**p().
usandfriends

1
@usandfriends 나는 그것에 대해 생각하고 있었지만 브라우저에서 작동하지 않으므로 생략했습니다. : P 나는 그런 말을하는 메모를 추가 할 것입니다.
user81655 5

1

Groovy, 718 바이트 전부!

내 임프 골프도 게시 할 수 있습니다. 내 큰 벽을 만나보십시오.

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

언 골프 드 :

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

편집 1 : @Doorknob 덕분에 ~ 15 바이트 저장
편집 2 : 몇 가지 추가 트릭으로 ~ 130 바이트 삭제


Groovy를 모르지만 불필요한 공백이 많이있는 것 같습니다. 예를 들어, for/ 다음 if과 같은 연산자 주위
Doorknob

방금 공백을 제거 할 곳이 더 많이 발견되었습니다. 팁 고마워.
J Atkin

System.in.text대신 사용할 수 있습니다 System.in.newReader().readLine().
스파게티

실제로는 아닙니다. .text탐욕스럽고 독자의 데이터가 있으면 반환되지 않습니다.
J Atkin

맞습니다. 그러나 이것은 코드 골프입니다. 사람들이 입력 후 Control-D를 입력 해야하는 경우별로 중요하지 않습니다.
스파게티

1

사탕 , 298 348 392 바이트

Candy는 스택 기반이지만 실제로 도움이되었는지 확실하지 않습니다 ...

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

비트를 포맷하면 약간의 구조가 나타납니다.

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

실제 수학은 마지막 두 줄에서 발생합니다. 세 번째 줄의 점프 테이블에 의해 구동됩니다.


Dang, DivisionByZero, NegativeFactorial 및 Overflow를 놓친 것을 알았습니다. 나는 단지 테스트 사례를보고 있었다!
데일 존슨

와우, 이거 멋지다. 사탕을 찾아야 할 수도 있습니다.
J Atkin

나는 여전히 오버플로를 정확하게 정의 하는 방법을 연구하고 있습니다.
데일 존슨

사실 나는 내 대답에서 같은 문제가있었습니다. 내 답변 아래의 의견을 참조하십시오.
J Atkin

오버플로를 수정했습니다. 루비와 같은 접근법을 사용했는데, 각 작업이 끝날 때 2 ^ 64와 비교하는 것입니다.
데일 존슨
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.