เครื่องคิดเลขขั้นสูง


28

คุณต้องเขียนโปรแกรมที่ประเมินสตริงที่จะถูกป้อนลงในเครื่องคิดเลขขั้นสูง

โปรแกรมจะต้องยอมรับอินพุตโดยใช้ stdin และออกคำตอบที่ถูกต้อง สำหรับภาษาที่ไม่มีฟังก์ชั่นที่จะยอมรับ stdin คุณอาจถือว่าฟังก์ชั่นนั้นreadLineและprintจัดการงานเหล่านี้

ที่ต้องการ:

  • ห้ามใช้ฟังก์ชั่น "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ที่ท้าย ฉันไม่แน่ใจเกี่ยวกับความแม่นยำ แต่ยังดีกว่า
Kevin Brown

1
รุ่นกองมากเกินเป็นผู้ประเมินการแสดงออกทางคณิตศาสตร์ (PEMDAS เต็ม) แม้ว่าหลายคำตอบสำหรับคนนั้นกำลังนับจำนวนบรรทัด (?!?) ยังมีคำตอบย่อ ๆ หลายข้อในค
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;

รหัสกอล์ฟครั้งแรกของฉันดังนั้นรอคอยที่จะแสดงความคิดเห็นและวิจารณ์!


Handles the right-associativity of the exponentiation operator, which J B's Perl solution doesn't seem to.
drspod

ทั้งคำแถลงปัญหาและหน้าวิกิพีเดียที่เชื่อมโยงนั้นไม่จำเป็นต้องมีการเชื่อมโยง นอกจากนี้หน้าวิกิพีเดียอย่างชัดเจนบอกว่าทั้งสองวิธีที่พบในเครื่องคิดเลขเชิงพาณิชย์
JB

1
+1 golfed อย่างดี แต่ ... รวมถึงการลดลง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

Postscript, 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
=

สิ่งที่ต้องทำ : การเชื่อมโยงที่ถูกต้องของการยกกำลัง


Ah... The dictstack: brilliant!
luser droog

I'm allowed to comment on stackoverflow, so I was a little confused. Is it normal that the reputation is managed separately, or did I screw up my logins?
Thomas W.

I wanted to tell you that there must be something wrong with your solution because all three test cases given above fail. However, I didn't try to understand what you're doing yet (some comments would be cool ;-)).
Thomas W.

1) Once you hit 200 on any site, you'll start at 101 on every site. Or hit 50 here. 2) AUGHH! I thought it was a quick extension of the Basic Calculator. I didn't even see that brackets are required! And I didn't test it very well. Oh, well; pants down, at least my undies are clean!
luser droog

@luserdroog: "@ThomasW" does not invite me to comment.
Thomas W.

1

Python 2,339 335 bytes

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

Try it online!

  • -4 bytes by changing str(x) with backticks ``!

0

Postscript, 1000 695 665 494

Stole ideas from ThomasW. Added feature: accepts strings with or without spaces around operators.[feature removed]


Using ARGUMENTS is shorter than %stdin, and easier to test, to boot!


Simplified the substitution to just replace brackets with 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

Code:

/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 and commented:

%!
%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 I wonder if this works to invite you to comment. (?)
luser droog

I've posted a fuller implementation of the same idea in comp.lang.postscript.
luser droog
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.