고급 계산기


28

고급 계산기에 입력 할 문자열을 평가하는 프로그램을 작성해야합니다.

프로그램은 stdin을 사용하여 입력을 승인하고 정답을 출력해야합니다. 어떤 기능을 표준 입력 받아 들여야 않는 언어의 경우, 기능을 가정 할 수 readLineprint이러한 작업을 처리 할 수 있습니다.

요구 사항 :

  • "eval"함수를 사용하지 않습니다
  • 부동 소수점 및 음수 처리 가능
  • 최소한 +,-, *, / 및 ^ 연산자 지원
  • 일반 주문을 재정의하기 위해 괄호와 괄호를 지원합니다
  • 연산자와 숫자 사이에 하나 이상의 공백이 포함 된 입력을 처리 할 수 ​​있습니다.
  • 표준 작업 순서를 사용하여 입력을 평가합니다

테스트 사례

입력

10 - 3 + 2

산출

9


입력

8 + 6 / 3 - 7 + -5 / 2.5

산출

1


입력

4 + [ ( -3 + 5 ) * 3.5 ] ^ 2 - 12

산출

41

1
출력 된 숫자 .0가 정수인 경우 끝에 후행이 있으면 괜찮 습니까? 또한 : 부동 소수점 정밀도와 관련하여 계산기의 정확도는 어느 정도입니까?
sepp2k

1
결과는 끝에 후행이있을 수 있습니다 .0. 나는 정밀도에 대해 확신이 없지만 더 많을수록 좋습니다.
케빈 브라운

1
스택 오버플로 버전은 수학 식 평가 기 (전체 PEMDAS) 였습니다. 그 하나에 대한 많은 대답이 줄을 세고 있지만 (?!?). 아직도 c에는 몇 가지 간단한 답변이 있습니다.
dmckee

PN / RPN 계산기에 대한 보너스?
Mateen Ulhaq

답변:


8

C ++, (640) 583

string k="[]()+-*/^";stack<double> m;stack<char> n;
#define C(o,x,y) ('^'==o?x<y:x<=y)
#define Q(a) double a=m.top();m.pop();
#define R(o) {Q(b)Q(a)m.push(o=='+'?a+b:o=='-'?a-b:o=='*'?a*b:o=='/'?a/b:o=='^'?pow(a,b):0);n.pop();}
while(!cin.eof()){string s;getline(cin,s,' ');if(s.empty())continue;if('\n'==*--s.end())s.erase(--s.end());(s.size()==1&&s.npos!=k.find(s[0]))?({char c=s[0]=='['?'(':s[0]==']'?')':s[0];while(!n.empty()&&'('!= c&&C(c,k.find(c),k.find(n.top())))R(n.top());')'==c?n.pop():n.push(c);}):m.push(strtod(s.c_str(),0));}while(!n.empty())R(n.top());cout<<m.top()<<endl;

들여 쓰기

string k="[]()+-*/^";
stack<double> m;
stack<char> n;
#define C(o,x,y) ('^'==o?x<y:x<=y)
#define Q(a) double a=m.top();m.pop();
#define R(o) {Q(b)Q(a)m.push(o=='+'?a+b:o=='-'?a-b:o=='*'?a*b:o=='/'?a/b:o=='^'?pow(a,b):0);n.pop();}
while(!cin.eof())
{
    string s;
    getline(cin,s,' ');
    if(s.empty())continue;
    if('\n'==*--s.end())s.erase(--s.end());
    (s.size()==1&&s.npos!=k.find(s[0]))?({
        char c=s[0]=='['?'(':s[0]==']'?')':s[0];
        while(!n.empty()&&'('!= c&&C(c,k.find(c),k.find(n.top())))
            R(n.top());
        ')'==c?n.pop():n.push(c);
    }):m.push(strtod(s.c_str(),0));
}
while(!n.empty())
    R(n.top());
cout<<m.top()<<endl;

내 첫 번째 코드 골프이므로 의견과 비판을 기대합니다!


JB의 Perl 솔루션이 보이지 않는 지수 연산자의 오른쪽 연관성을 처리합니다.
drspod

문제 설명이나 링크 된 wikipedia 페이지 언급 지수가 오른쪽 연관이 될 필요는 없습니다. 또한 위키 백과 페이지에는 상용 계산기에서 두 가지 방법을 모두 찾을 수 있다고 명시되어 있습니다.
JB

1
+1은 멋지게 골프를 쳤지 만 ... 포함 만 빼고 using namespace std주요 기능은 실제로 좋지 않습니다.
반 시계 회전을 중지

2

PHP- 394 354 312 자

<?=e(!$s=preg_split('#\s+#',`cat`,-1,1),$s);function e($P,&$s){$S='array_shift';if(($a=$S($s))=='('|$a=='['){$a=e(0,$s);$S($s);}while($s&&($p=strpos(' +-*/^',$o=$s[0]))&&$p>=$P){$b=e($p+($S($s)!='^'),$s);if($o=='+')$a+=$b;if($o=='-')$a-=$b;if($o=='*')$a*=$b;if($o=='/')$a/=$b;if($o=='^')$a=pow($a,$b);}return$a;}

들여 쓰기 :

<?
preg_match_all('#\d+(\.\d+)?|\S#',`cat`,$m);
$s=$m[0];
function e($P) {
        global $s;
        if (strpos(" ([",$s[0])){
                array_shift($s);
                $a=e(0);
                array_shift($s);
        } else {
                $a=array_shift($s);
                if ($a=='-')$a.=array_shift($s);
        }
        while ($s && ($p=strpos(' +-*/^',$o=$s[0])) && $p >= $P) {
                array_shift($s);
                $b = e($p+($o!='^'));
                switch($o){
                case'+':$a+=$b;break;
                case'-':$a-=$b;break;
                case'*':$a*=$b;break;
                case'/':$a/=$b;break;
                case'^':$a=pow($a,$b);
                }
        }
        return $a;
}
echo e(0);

2

포스트 스크립트, 446

이것은 션팅 야드 알고리즘을 사용합니다.

[/*[/p
2/e{mul}>>/d[/p
2/e{div}>>/+[/p
1/e{add}>>/-[/p
1/e{sub}>>/o[/p
9/e{}>>/c[/p
-1/e{}>>/^[/p
3/e{exp}>>/p
0>>begin/s(%stdin)(r)file 999 string readline pop def
0 1 s length 1 sub{s exch[0 1 255{}for]dup[(\(o)([o)(\)c)(]c)(/d)]{{}forall
put dup}forall
pop
3 copy pop
get
get
put}for{s token not{exit}if
exch/s exch store{cvr}stopped{load
dup/p get
p
le{currentdict end
exch begin/e get exec}{begin}ifelse}if}loop{{e end}stopped{exit}if}loop
=

골프를 치지 않고 댓글을 달았습니다.

% We associate the operators with their precedence /p and the executed commend /e
[
  (*)[/p  2 /e{mul}>>
  (d)[/p  2 /e{div}>> % This is division
  (+)[/p  1 /e{add}>>
  (-)[/p  1 /e{sub}>>
  (o)[/p  9 /e{   }>> % This is open bracket
  (c)[/p -1 /e{   }>> % This is close bracket
  (^)[/p  3 /e{exp}>>
  /p 0
>>begin

% Let's read the input string
/s(%stdin)(r)file 999 string readline pop def

% If we want to use the token operator, we have to replace (, [, ), ] and / to get meaningful results
% We use kind of an encoding array (familiar to PostScripters) to map those codes to o, c, and d.
0 1 s length 1 sub{        % index
  s exch                   % string index
  [0 1 255{}for] dup       % string index translationArray translationArray
  [(\(o)  ([o)  (\)c)  (]c)  (/d)] % string index translationArray translationArray reencodeArray
  {                        % string index translationArray translationArray translationString
    {}forall               % string index translationArray translationArray charCode newCharCode
    put dup                % string index translationArray translationArray
  }forall                  % string index translationArray translationArray
  pop                      % string index translationArray
  3 copy pop               % string index translationArray string index
  get                      % string index translationArray charCode
  get                      % string index translatedCharCode
  put                      % -/-
}for

% Now we can actually start interpreting the string
% We use the stack for storing numbers we read and the dictionary stack for operators that are "waiting"
{                          % number*
  s token not{exit}if      % number* string token
  exch /s exch store       % number* token
  % We try to interpret the token as a number
  {cvr}stopped{            % number* token
    % If interpretation as number fails, we have an operator
    load                   % number* opDict
    % Compare operator precedence with last operator on dictstack
    dup /p get             % number* opDict opPrec
    p                      % number* opDict opPrec prevOpPrec
    le {                   % number* opDict
      % If the last operator on the stack has at least the same precedence, execute it
      currentdict end      % number* opDict prevOpDict
      exch begin           % number* prevOpDict
      /e get exec          % number*
    }{                     % number* opDict
      % If last operator doesn't have higher precedence, put the new operator on the dictstack as well
      begin
    }ifelse
  }if
}loop
% If we're finished with interpreting the string, execute all operators that are left on the dictstack
{{e end}stopped{exit}if}loop
=

TODO : 지수의 오른쪽 연관


아 ... dictstack : 훌륭합니다!
luser droog

나는 stackoverflow에 대해 언급 할 수 있었기 때문에 약간 혼란 스러웠다. 평판이 별도로 관리되는 것이 정상입니까, 아니면 로그인을 망쳤습니까?
Thomas W.

위에 주어진 세 가지 테스트 사례가 모두 실패하기 때문에 솔루션에 문제가 있어야한다고 말하고 싶습니다. 그러나, 나는 당신이 아직하고있는 것을 이해하려고하지 않았습니다 (일부 의견은 멋질 것입니다 ;-)).
Thomas W.

1) 어느 사이트에서든 200을 누르면 모든 사이트에서 101에서 시작합니다. 또는 여기 50을 누르십시오. 2) 8 월! 나는 그것이 기본 계산기의 빠른 확장이라고 생각했습니다. 나는 대괄호가 필요하다는 것을조차 보지 못했습니다! 그리고 나는 그것을 잘 테스트하지 않았습니다. 아. 내 바지는 깨끗해!
luser droog

@luserdroog : "@ThomasW"는 나를 초대하지 않습니다.
Thomas W.

1

파이썬 2 , 339,335 바이트

import re
x,s=input(),re.sub
def f(y):
 y,r=s('- ','+ -',y).split(),['^','*','/','+','-']
 for c in r:
  while c in y:d=y.index(c)-1;a,b=map(float,[y[d],y[d+2]]);y=y[:d]+[((a,-a)[a<0]**b,a*b,a/b,a+b,a-b)[r.index(c)]]+y[d+3:]
 return`y[0]`
w=lambda b:s("[([]+[\d+\-*/^ .]*[)\]]",lambda m:f(m.group()[1:]),s(' +',' ',b))
print f(w(w(x)))

온라인으로 사용해보십시오!

  • 역 따옴표로 str (x)를 변경하여 -4 바이트``!

0

포스트 스크립트, 1000 695 665 494

ThomasW의 아이디어를 훔쳤습니다. 추가 된 기능 : 연산자 주위에 공백이 있거나없는 문자열을 허용합니다.[기능 제거]


사용하는 ARGUMENTS것이 %stdin부팅 보다 짧고 테스트하기 더 쉽습니다!


대괄호를 괄호로 바꾸기 만하면 대체가 간단 해졌습니다.

575(1)10:36 PM:ps 0> gsnd -q -- calc2bg.ps '10 - 3 + 2'
9
576(1)10:37 PM:ps 0> gsnd -q -- calc2bg.ps '8 + 6 / 3 - 7 + -5 / 2.5'
1.0
577(1)10:37 PM:ps 0> gsnd -q -- calc2bg.ps '4 + [ ( -3 + 5 ) * 3.5 ] ^ 2 - 12'
41.0

암호:

/T[/^[/C{exp}/P 4/X{le}>>/*[/C{mul}/P 3/X{lt}>>/[/C{div}/P
3/X{lt}>>/+[/C{add}/P 2/X{lt}>>/-[/C{sub}/P
2/X{lt}>>>>def[/integertype{}/realtype{}/stringtype{V}/nametype{cvlit/N
exch store{P T N get dup/P get exch/X get exec{exit}if C end}loop T N get
begin}91 40 93 41>>begin/V{0 1 2 index length 1 sub{2 copy get
dup where{exch get}if 3 copy put pop pop}for[/N 0/R 0/P 0/C{}>>begin{token
not{exit}if exch/R exch store dup type exec R}loop{P 0 eq{end exit}if C
end}loop}def ARGUMENTS{V ==}forall

Ungolfed 및 댓글 :

%!
%Shunting-Yard Algorithm using dictstack for operators
%invoke with %gsnd -q -- calc2bg.ps [ 'expr1' ]*

%The operator table. C:code P:precedence X:test(implements associativity)
/T[
    /^[/C{exp}/P 4/X{le}>>
    /*[/C{mul}/P 3/X{lt}>>
    /[/C{div}/P 3/X{lt}>>
    /+[/C{add}/P 2/X{lt}>>
    /-[/C{sub}/P 2/X{lt}>>
>>def

%The type-dispatch dictionary
%numbers: do nothing
%string: recurse
%name: process op
[%/integertype{}/realtype{} %now uses `where` below
/stringtype{V}/nametype{
pstack()=
    cvlit/N exch store %stash cur-op
    {
        P %prec(tos)
        T N get %prec(tos) cur-op-dict
        dup/P get %prec(tos) cur-op-dict prec(cur-op)
        exch/X get %prec(tos) prec(cur-op) test(cur-op)
        exec{exit}if %exit if prec(tos) < || <= prec(cur-op)
/C load ==
        C %pop-and-apply
        end
pstack()=
    } loop
    T N get begin %push cur-op
}>>begin

%substitutions
[91 40 93 41>>begin %replace brackets with parens
/V {
    %pre-process
    0 1 2 index length 1 sub {
        2 copy get
        dup where { exch get } if
        3 copy put pop pop
    } for
dup ==

    [/N 0/R 0/P 0/C{}>>begin %dummy base operator and storage
    { token not{exit}if exch /R exch store %extract token, stash Remainder
pstack(>)=
        %dispatch type procedure
        dup type dup where { pop exec }{ pop } ifelse
    R }loop
pstack()=
    {
        P 0 eq{end exit}if %hit dummy op: exit
/C load ==
        C end %pop and apply
    } loop
} def

ARGUMENTS{V ==}forall %iterate through the command-line arguments

@ThomasW 이것이 당신 을 의견 으로 초대 하는 것이 효과가 있는지 궁금합니다 . (?)
luser droog

comp.lang.postscript에 동일한 아이디어의 완전한 구현을 게시했습니다 .
luser droog
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.