Máy tính nâng cao


28

Bạn phải viết một chương trình đánh giá một chuỗi sẽ được nhập vào một máy tính nâng cao.

Chương trình phải chấp nhận đầu vào bằng stdin và đưa ra câu trả lời đúng. Đối với các ngôn ngữ không có chức năng chấp nhận stdin, bạn có thể đảm nhận các chức năng readLineprintđể xử lý các tác vụ này.

Yêu cầu:

  • Không sử dụng bất kỳ loại chức năng "eval"
  • Có thể xử lý số dấu phẩy động và số âm
  • Hỗ trợ ít nhất các toán tử +, -, *, / và ^
  • Hỗ trợ dấu ngoặc và dấu ngoặc đơn để ghi đè thứ tự bình thường
  • Có thể xử lý đầu vào chứa một hoặc nhiều khoảng trắng giữa các toán tử và số
  • Đánh giá đầu vào bằng cách sử dụng thứ tự hoạt động tiêu chuẩn

Các trường hợp thử nghiệm

Đầu vào

10 - 3 + 2

Đầu ra

9


Đầu vào

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

Đầu ra

1


Đầu vào

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

Đầu ra

41

1
Có ổn không nếu các số xuất ra có dấu .0ở cuối nếu chúng là số nguyên? Ngoài ra: độ chính xác của máy tính phải như thế nào (liên quan đến độ chính xác của dấu phẩy động và như vậy)?
sepp2k

1
Đầu ra có thể có một dấu .0ở cuối. Tôi không chắc lắm về độ chính xác, nhưng nhiều hơn là tốt hơn.
Kevin Brown

1
Phiên bản Stack Overflow là bộ đánh giá biểu thức toán học (PEMDAS đầy đủ) . Mặc dù nhiều câu trả lời cho câu hỏi đó là đếm dòng (?!?). Vẫn có một số câu trả lời nhỏ gọn trong c.
dmckee

Tiền thưởng cho máy tính PN / RPN?
Mateen Ulhaq

Câu trả lời:


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;

Thụt lề

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;

Golf mã đầu tiên của tôi, rất mong nhận được ý kiến ​​và phê bình!


Xử lý tính kết hợp đúng của toán tử lũy thừa, mà giải pháp Perl của JB dường như không có.
drspod

Cả tuyên bố vấn đề và trang wikipedia được liên kết đều đề cập đến lũy thừa phải là liên kết đúng. Hơn nữa, trang wikipedia nói rõ ràng cả hai cách được tìm thấy trên máy tính thương mại.
JB

1
+1 chơi golf độc đáo, nhưng ... chỉ cần thả bao gồm, using namespace stdvà một chức năng chính không thực sự ổn, phải không?
đã ngừng quay ngược chiều

2

PHP - 394 354 312 ký tự

<?=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;}

Thụt lề:

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

Bản tin, số 446

Điều này sử dụng thuật toán sân shunting.

[/*[/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
=

Un-golfed và nhận xét:

% 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 : Quyền kết hợp của lũy thừa


À ... The dictstack: rực rỡ!
luser droog

Tôi được phép bình luận về stackoverflow, vì vậy tôi có một chút bối rối. Có phải bình thường là danh tiếng được quản lý riêng, hoặc tôi đã làm hỏng thông tin đăng nhập của mình?
Thomas W.

Tôi muốn nói với bạn rằng phải có điều gì đó không đúng với giải pháp của bạn bởi vì cả ba trường hợp thử nghiệm được đưa ra ở trên đều thất bại. Tuy nhiên, tôi đã không cố gắng hiểu những gì bạn đang làm (một số ý kiến ​​sẽ rất tuyệt ;-)).
Thomas W.

1) Khi bạn đạt 200 trên bất kỳ trang web nào, bạn sẽ bắt đầu ở 101 trên mỗi trang. Hoặc đánh 50 ở đây. 2) THÁNG 8! Tôi nghĩ rằng nó là một phần mở rộng nhanh chóng của Máy tính cơ bản. Tôi thậm chí không thấy rằng dấu ngoặc là bắt buộc! Và tôi đã không kiểm tra nó rất tốt. Ồ, tốt; quần xuống, ít nhất quần lót của tôi sạch sẽ!
luser droog

@luserdroog: "@ThomasW" không mời tôi nhận xét.
Thomas W.

1

Python 2 , 339 335 byte

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

Hãy thử trực tuyến!

  • -4 byte bằng cách thay đổi str (x) bằng backticks ``!

0

Bản tin, 1000 695 665 494

Lấy trộm ý tưởng từ ThomasW. Đã thêm tính năng: chấp nhận chuỗi có hoặc không có khoảng trắng xung quanh toán tử.[loại bỏ tính năng]


Sử dụng ARGUMENTSngắn hơn %stdinvà dễ dàng hơn để kiểm tra, để khởi động!


Đơn giản hóa việc thay thế để chỉ thay thế dấu ngoặc bằng parens.

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

Mã số:

/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 và bình luận:

%!
%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 Tôi tự hỏi nếu điều này hoạt động để mời bạn bình luận. (?)
luser droog

Tôi đã đăng một triển khai đầy đủ hơn về cùng một ý tưởng trong comp.lang.postscript .
luser droog
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.