Grundlegender Rechner

20

Sie müssen ein Programm schreiben, um eine Zeichenfolge auszuwerten, die in einen Taschenrechner eingegeben werden würde.

Das Programm muss Eingaben akzeptieren und die richtige Antwort ausgeben. Für Sprachen, die keine Standard-Eingabe- / Ausgabefunktionen haben, können Sie die Funktionen readLineund übernehmen print.

Bedarf

  • Verwendet keine Art von "Auswertungs" -Funktionen
  • Kann mit Fließkomma- und negativen Zahlen umgehen
  • Unterstützt mindestens die Operatoren +, -, * und /
  • Kann Eingaben verarbeiten, die ein oder mehrere Leerzeichen zwischen Operatoren und Zahlen enthalten
  • Wertet den Ausdruck von links nach rechts aus

Das kürzeste Programm gewinnt. Bei einem Gleichstand gewinnt das zuerst eingereichte Programm.

Sie können davon ausgehen, dass die Eingabe gültig ist und dem richtigen Format folgt

Testfälle

Eingang

-4 + 5

Ausgabe

1


Eingang

-7.5 / 2.5

Ausgabe

-3


Eingang

-2 + 6 / 2 * 8 - 1 / 2.5 - 18

Ausgabe

-12
Kevin Brown
quelle
Mein Rechner benutzt Postfix . Siehe auch Auswerten mathematischer Ausdrücke beim Stapelüberlauf für den Wettbewerb (obwohl ich nicht überprüft habe, ob die Regeln identisch sind).
dmckee
3
Der dritte Testfall ist falsch - unabhängig davon, ob Sie die Standardreihenfolge der Vorgänge einhalten oder alle Vorgänge von links nach rechts ausführen. Rundet Ihr Rechner im zweiten Testfall das Ergebnis jeder Operation?
PleaseStand
Der zweite und dritte Testfall behoben, das Ergebnis wird nicht gerundet.
Kevin Brown
Der dritte Testfall folgt nicht der Standardreihenfolge. Sollen unsere Antworten?
John
1
Was ist mit der Verwendung von Befehlszeilenargumenten ARGV? weil die Shell die Argumente automatisch aufteilt und auflistet.
Ming-Tang

Antworten:

7

Ruby - 74 69 67 65 Zeichen

a=0
("+ "+$<.read).split.each_slice 2{|b,c|a=a.send b,c.to_f}
p a
Arnaud Le Blanc
quelle
1
Anstelle der Verwendung b[0],b[1].to_fkönnen Sie ersetzen |b|mit |b,c|und Verwendungb,c.to_f
Nemo157
\Oh, danke ! :-)
Arnaud Le Blanc
1
a.send(b,c.to_f)Verwenden Sie stattdessen a.send b,c.to_f. Es spart eine char
Anonymous Coward
1
Sie können $<anstelle vonARGF
Dogbert
9

Befunge - 37 x 5 = 185, 38 x 3 = 114 Zeichen

Dies ist auf Ganzzahlen beschränkt, da Befunge keine Gleitkomma-Unterstützung bietet.

&v      /& _ #`&# "-"$# -#<          v
 >~:0`!#v_:" "`! #v_:","`#^_"*"`#v_&*>
 ^      ># $ .# @#<              >&+ 

Erläuterung

Das größte Unterscheidungsmerkmal von Befunge ist, dass es sich nicht wie bei den meisten Sprachen um einen linearen Befehlssatz handelt. Es ist ein 2D-Raster mit Einzelzeichenanweisungen, bei denen die Steuerung in jede Richtung fließen kann.

Der erste gibt &einfach die erste Zahl ein. Das Steuerelement vund >leiten dann auf den Hauptpfad in der zweiten Zeile um.

~:0`!#v_

Dies gibt ein Zeichen ein ( ~), dupliziert es ( :), legt eine Null auf den Stapel ( 0), fügt die beiden obersten Elemente ein und bestimmt, ob die zweite größer ist als die erste ( ` ich bin überrascht, dass Sie nicht `` `verwenden können, um zu erhalten Code Backticks. ), invertiert die Wahrheit des obersten Elements ( !), geht dann nach rechts, wenn es Null ist, andernfalls nach unten ( #v_).

Grundsätzlich wird geprüft, ob der Eingang -1keinen Eingang mehr darstellt.

># $ .# @

Wenn die Eingabe -1dann war, wird der duplizierte Eingabewert verworfen ( $), die Oberseite des Stapels wird als Ganzzahl ausgegeben ( .) und das Programm wird angehalten ( @).

:" "`! #v_

Andernfalls wird ein ähnlicher Vorgang wiederholt, um festzustellen, ob die Eingabe kleiner oder gleich einem Leerzeichen ist. Wenn es sich um ein Leerzeichen handelt, geht die Kontrolle zurück, ansonsten geht die Kontrolle nach rechts.

^      ># $ .# @#<

Wenn es sich um ein Leerzeichen handelt, wird es umgeleitet left ( <); Das Programm stop ( @), output ( .) und right redirection ( >) werden mit übersprungen #. Das Verwerfen wird jedoch ausgeführt, um den Speicherplatz vom Stapel zu entfernen. Schließlich wird es weitergeleitet, um mit der nächsten Ausführung zu beginnen ( ^).

:","`#^_

Wenn es sich nicht um ein Leerzeichen handelt, wird derselbe Prozess verwendet, um es zu teilen, wenn es richtig ist [+, *]oder wenn es [-, \]richtig ist und aufwärts geht.

 >~                         "*"`#v_&*>
 ^                               >&+

Denn [+, *]es wird erneut aufgeteilt, um festzustellen, ob es sich um eine +oder eine handelt *. Wenn +es nach unten gerichtet ist, wird die nächste Zahl eingegeben ( &) und sie werden hinzugefügt ( +), das Steuerelement wird dann umgebrochen und zum Hauptpfad für das nächste Zeichen weitergeleitet. Wenn es *dann eingibt ( &) und multipliziert ( *), wird es direkt umbrochen.

/& _ #`&# "-"$# -#<

Denn [-, \]es beginnt auf der rechten Seite links. Die #'s überspringen das Zeichen nach ihnen, so dass der Anfangspfad "-"`_einfach festlegt, ob es -oder ist /. Wenn dies der Fall ist /, wird die Eingabe ( &) und Division ( /) fortgesetzt . Wenn dies der Fall ist -, werden die Zeichen erneut übersprungen und ausgeführt, &"-"$-was zur Eingabe der Zahl führt ( &). Das -auf den Stapel geschobene Zeichen wird verworfen ( "-"$) und anschließend die Subtraktion berechnet ( -). Das Steuerelement wird dann zurück zum Hauptpfad umgeleitet.

Nemo157
quelle
6

Python 3, 105 Bytes

Verwaltet die vier Grundoperationen, aber das Hinzufügen von ^oder kostet jeweils nur 5 Zeichen %.

f=float
x,*l=input().split()
while l:o,y,*l=l;x,y=f(x),f(y);x=[x+y,x-y,x*y,x/y]['+-*/'.find(o)]
print(x)

Die Rangfolge der Operationen ist von links nach rechts.

daniero
quelle
5

Python (156)

from operator import*
while 1:
 l=raw_input().split();f=float
 while len(l)>2:l[:3]=({'*':mul,'/':div,'+':add,'-':sub}[l[1]](f(l[0]),f(l[2])),)
 print l[0]
Hoa Long Tam
quelle
1
Es ist wahrscheinlich einfacher, Python 3
jamylak
5

C - 168 126 Zeichen

main(c){float a,b;scanf("%f",&a);while(scanf("%s%f",&c,&b)!=-1)c=='+'?a+=b:c=='-'?(a-=b):c=='*'?(a*=b):(a/=b);printf("%f",a);}
Arnaud Le Blanc
quelle
5

Tcl 8,6, 57 48 Zeichen.

  • Eingabe von Argumenten:

    lm o\ b [las $argv a] {set a [exp $a$o$b]};pu $a
    
  • Von Stdin ( 64 53 )

    lm o\ b [las [ge stdin] a] {set a [exp $a$o$b]};pu $a
    

Sie müssen die interaktive Shell für beide Lösungen verwenden.

Ich behandle die Eingabe als Liste (Tcl verwendet Leerzeichen als Trennzeichen), nehme das erste Element und ordne es zu a, dann gehe ich über den Rest und nehme jeweils 2 Elemente, den Operator und eine zweite Zahl, wende den Operator auf $aund an $bund ordne das zu Ergebnis zu a. Am Ende steht das Ergebnis in a.

Johannes Kuhn
quelle
Ideone unterstützt mindestens stdin.
Johannes Kuhn
Endlich habe ich Ruby besiegt. Leider unterstützt Idone Tcl 8.6 nicht, aber ich brauche das Ergebnis nicht, lmapso foreachist ein guter Ersatz.
Johannes Kuhn
4

Haskell: 124 114 Zeichen

j[o]=o
j(u:m:b:o)=j$show((case m of{"+"->(+);"-"->(-);"*"->(*);"/"->(/)})(read u)(read b)):o
main=interact$j.words

Eine ziemlich direkte Antwort, die einen Mustervergleich und eine einfache Fallbeschreibung für das schwere Heben verwendet. Verwendung:

> ./calc <<< "123 - 12 + -12 / 12.124 * 9.99 - 1"
80.57456285054437
Fors
quelle
1
Anstelle von ((case m of{..})(read u)(read b))Ihnen können Sie auch ((case m of{..}$read u)$read b)2 Zeichen weniger schreiben .
Swish
4

C: 111 108 Zeichen

main(c){float a,b;for(scanf("%f ",&a);~scanf("%c%f ",&c,&b);a=c^43?c%5?c%2?a/b:a*b:a-b:a+b);printf("%f",a);}

Es erfüllt alle Anforderungen, Nutzung:

> ./calc <<< "-43 - 56 + 14.123 / -13.22"
6.420348
Fors
quelle
1
~scanfersetzen können +1. Auch c^45-> c%5und c^42-> c%2sollten funktionieren.
Ugoren
@MDXF nicht auf meinem Rechner, hier besteht es jeden Testfall. Ich kompiliere mit Clang auf einem ziemlich modernen Intel Macbook und es funktioniert hervorragend (ich habe es gerade noch einmal getestet, den Code von hier kopiert und es einfach ohne Flags kompiliert). Welche Compiler-, Prozessorarchitektur und welches Betriebssystem verwenden Sie?
Fors
@Für ich glaube, ich hatte einige seltsame Flags, die seltsames Verhalten hervorriefen; Mein Fehler, es funktioniert jetzt für mich. Entschuldige, dass ich dich belästige.
MD XF
3

C ++ 0x 205 203 198 194 Zeichen

#include<iostream>
#define P [](F l,F r){return l
int main(){typedef float F;F r,v,(*a[])(F,F)={P*r;},P+r;},0,P-r;},0,P/r;}};std::cin>>r;for(char o;std::cin>>o>>v;)r=a[o-42](r,v);std::cout<<r;}

Schön formatiert:

#include<iostream>

int main()
{
    float r,v;
    float (*a[])(float,float)   ={  [](float l,float r){return l*r;},
                                    [](float l,float r){return l+r;},
                                    0,
                                    [](float l,float r){return l-r;},
                                    0,
                                    [](float l,float r){return l/r;}
                                 };

    std::cin>>r;
    for(char o;std::cin>>o>>v;)
        r=a[o-42](r,v);

    std::cout<<r;
}
Martin York
quelle
3

Perl (97)

$b=shift;eval"\$b$r=$s"while($r=shift,$s=shift);print$b

Lesen Sie aus Argumenten

$b=shift;$b=($r eq'+'?$b+$s:$r eq'-'?$b-$s:$r eq'*'?$b*$s:$b/$s)while($r=shift,$s=shift);print$b;

von der Eingabe lesen

@_=split/ /,<>;$b=shift@_;$b=($r eq'+'?$b+$s:$r eq'-'?$b-$s:$r eq'*'?$b*$s:$b/$s)while($r=shift@_,$s=shift@_);print$b
Ming-Tang
quelle
3

PostScript (145)

Ein weiterer PostScript-Eintrag (danke an luser droog für das Graben der für PostScript interessanten Golfplätze!):

[/+{add}/-{sub}/*{mul}/{div}>>begin(%stdin)(r)file
999 string readline
pop{token not{exit}if
count 4 eq{3 1 roll
4 1 roll
cvx exec}if
exch}loop
=

Nicht golfen:

[/+{add}/-{sub}/*{mul}/ {div}>>begin
% Read the input
(%stdin)(r)file 999 string readline pop
{                        % .. string
  token not{exit}if      % .. string token
  % If we have 4 objects on the stack, we have two operands, one operator
  % and the input string. This means, we can calculate now.
  count 4 eq{            % a op string b
    % perform operation a op b = c (where op can be +,-,*,/)
    3 1 roll             % a b op string
    4 1 roll             % string a b op 
    cvx exec             % string c
  }if                    % string token (or c)
  exch                   % token string
}loop
=
Thomas W.
quelle
Du schlägst mich weiter! +1 Das ist sehr aufregend.
Luser Droog
Wenn Sie mein Kreuzworträtsel schlagen können , gebe ich Ihnen eine Prämie! NB Sie können nur 10-mal editieren, bevor der Beitrag in CW geändert wird. Stimmen bringen Ihnen keine Wiederholungspunkte.
Luser Droog
Ich halte Sie schlagen , weil ich nur die , die gewählt haben , wo ich kann dich schlagen ;-). Ich bin mir nicht sicher, ob ich mit dem Kreuzworträtsel zurecht komme. Ich werde es vielleicht versuchen, aber erst in ein paar Wochen.
Thomas W.
1
Community Wiki. Dies bedeutet, dass der Beitrag so oft bearbeitet wurde, dass er jetzt der Community gehört. Jeder Benutzer kann es bearbeiten ( unter Umgehung der Zustimmung des Moderators für die üblichen erforderlichen vorgeschlagenen Änderungen), und nicht mehr Punkte. Also, was auch immer Sie tun, hören Sie bei Rev 9 auf. Ich habe es fast auf dem ersten Gitarrentab geblasen.
Luser Droog
1
Ignoriere all das Greifen im Uhrzeigersinn. Sie haben es behoben!
Luser Droog
3

Python - 308

import sys;i=sys.argv[1].split();o=[];s=[];a=o.append;b=s.pop;c=s.append
for t in i:
 if t in"+-*/":
  if s!=[]:a(b())
  c(t)
 else:a(t)
if s!=[]:a(b())
for t in o:
 if t=="+":c(b()+b())
 elif t=="-":m=b();c(b()-m)
 elif t=="*":c(b()*b())
 elif t=="/":m=b();c(b()/m)
 else:c(float(t))
print(b())

Lesbare Version:

# Infix expression calc

import sys

# Shunting-yard algorithm
input = sys.argv[1].split()
output = []
stack = []

for tkn in input:
    if tkn in "+-*/":
        while stack != []:
            output.append(stack.pop())
        stack.append(tkn)
    else:
        output.append(tkn)

while stack != []:
    output.append(stack.pop())

# Eval postfix notation
for tkn in output:
    if tkn == "+":
        stack.append(stack.pop() + stack.pop())
    elif tkn == "-":
        tmp = stack.pop()
        stack.append(stack.pop() - tmp)
    elif tkn == "*":
        stack.append(stack.pop() * stack.pop())
    elif tkn == "/":
        tmp = stack.pop()
        stack.append(stack.pop()/tmp)
    else:
        stack.append(float(tkn))

print(stack.pop())

Nimmt Ausdruck als Befehlszeilenargument und gibt ihn in der Standardausgabe aus.

golfer9338
quelle
2

Nachschrift (340)

/D<</+{add}/-{sub}/*{mul}/ {div}>>def/eval{/P null def{token not{exit}if exch/rem exch def
dup D exch known{/P load null ne{D/P load get exch/P exch def exec}{/P exch def}ifelse}if
rem}loop/P load null ne{D/P load get exec}if}def {(> )print flush{(%lineedit)(r)file
dup bytesavailable string readline pop eval == flush}stopped{quit}if}loop

Und ein bisschen lesbarer:

%!
/oper<</+{add}/-{sub}/*{mul}/ {div}>>def

/eval{
    /op null def
    {
        token not {exit} if
        exch /rem exch def
        dup oper exch known {
            /op load null ne {
                oper /op load get
                exch /op exch def
                exec
            }{
                /op exch def
            } ifelse
        } if
        rem
    } loop
    /op load null ne { oper /op load get exec } if
} def

{
    (> )print flush
    {
    (%lineedit)(r)file
    dup bytesavailable string readline pop
    eval == flush
    } stopped { quit } if
} loop
Luser Droog
quelle
2

JavaScript (208 Zeichen komprimiert)

Aus Gründen der Übersichtlichkeit ist dies der Code, bevor ich ihn komprimiert habe ( JS-Fiddle davon ):

function math(match, leftDigit, operator, rightDigit, offset, string) {
    var L = parseFloat(leftDigit)
    var R = parseFloat(rightDigit)
    switch (operator)
    {
        case '*': return L*R;
        case '/': return L/R;
        case '+': return L+R;
        case '-': return L-R;
    }
};

str = prompt("Enter some math:", "-2 + 6 / 2 * 8 - 1 / 2.5 - 18").replace(/ /g, "");
var mathRegex = /(\-?\d+\.?\d*)([\*\/\+\-])(\-?\d+\.?\d*)/;
while(mathRegex.test(str)) {
    str = str.replace(mathRegex, math);
}
alert(str)

Hier ist es auf 208 Zeichen komprimiert ( JS-Fiddle davon ):

function m(x,l,o,r){
    L=(f=parseFloat)(l);
    R=f(r);
    return o=='*'?L*R:o=='/'?L/R:o=='+'?L+R:L-R;
};

M=/(\-?\d+\.?\d*)([\*\/\+\-])(\-?\d+\.?\d*)/;
for(s=prompt().replace(/ /g, "");M.test(s);s=s.replace(M,m)){};
alert(s)

Da ich Zeilen mit Semikolons beende, wurden alle entfernbaren Leerzeichen beim Zählen der Zeichen ignoriert, aber der Übersichtlichkeit halber belassen.

IQAndreas
quelle
2

Haskell - 124

let p=let f[x]=Just$read x;f(x:o:r)=lookup o[("-",(-)),("+",(+)),("*",(*)),("/",(/))]<*>f r<*>Just(read x)in f.reverse.words

Das Ergebnis wird in MaybeMonade verpackt

λ: p"-2 + 6 / 2 * 8 - 1 / 2.5 - 18"
Just (-12.0)

Es erfordert auch den Import <*>von Control.Applicative, aber der Import kann außerhalb des Codes erfolgen, also hoffe ich, dass es erlaubt ist.

Swish
quelle
2

C # (234) (231) (229) (223) (214)

class A{void Main(string[]s){var n=1;var o="";var r=0F;foreach(var t in s){if(n>0){var v=float.Parse(t);if(o=="")r=v;if(o=="+")r+=v;if(o=="-")r-=v;if(o=="*")r*=v;if(o=="/")r/=v;}o=t;n=-n;}System.Console.Write(r);}}

class A{
    void Main(string[] s)
    {
      var n = 1;
      var o = "";
      var r = 0F;

      foreach (var t in s)
      {
        if (n > 0)
        {
          var v = float.Parse(t);
          if (o == "") r = v;
          if (o == "+") r += v;
          if (o == "-") r -= v;
          if (o == "*") r *= v;
          if (o == "/") r /= v;
        }
        o = t;
        n = -n;
      }
      System.Console.Write(r);
    }
}
Sklivvz
quelle
Ich erhalte '0' für '1 + 1'. IDEONE
Rob
@Mike Eingabe als Argumente, nicht als Standard.
Johannes Kuhn
1

JavaScript (87 Zeichen)

alert(prompt().split(/ +/).reduce((a,b,i)=>i%2?(o=b,a):o+1-0?a-b*-(o+1):o<'/'?a*b:a/b))
Yair Rand
quelle
1

Java 11, 151 (als Lambda-Funktion)

s->{float r=0,t;int o=43,q;for(var x:s.split(" ")){if(x.length()>1|(q=x.charAt(0))>47){t=new Float(x);r=o<43?r*t:o<44?r+t:o<46?r-t:r/t;}o=q;}return r;}

Lambda-Funktion, bei der ein String eingegeben und ein Float ausgegeben wird.

Probieren Sie es online aus.

Java 11, 241 Bytes (als volles Programm mit abgefragten I / O)

interface M{static void main(String[]a){float r=0,t;int o=43,q;for(var x:new java.util.Scanner(System.in).nextLine().split(" ")){if(x.length()>1|(q=x.charAt(0))>47){t=new Float(x);r=o<43?r*t:o<44?r+t:o<46?r-t:r/t;}o=q;}System.out.print(r);}}

Volles Programm, das eine String-Zeile durch STDIN zieht und an STDOUT ausgibt.

Probieren Sie es online aus.

Erläuterung:

interface M{                  // Class
  static void main(String[]a){//  Mandatory main-method
    float r=0,                //   Result float, starting at 0
          t;                  //   Temp float
    int o=43,                 //   Operator flag, starting at '+'
        q;                    //   Temp operator flag
    for(var x:new java.util.Scanner(System.in)
                              //   Create an STDIN-reader
               .nextLine()    //   Get the user input
               .split(" ")){  //   Split it on spaces, and loop over it:
      if(x.length()>1         //    If the current String length is larger than 1
                              //    (work-around for negative values)
         |(q=x.charAt(0))>47){//    Or the first character is an operator
                              //    (and set `q` to this first character at the same time)
        t=new Float(x);       //     Convert the String to a float, and set it to `t`
        r=                    //     Change `r` to:
          o<43?               //      If `o` is a '*':
            r*t               //       Multiply `r` by `t`
          :o<44?              //      Else-if `o` is a '+':
            r+t               //       Add `r` and `t` together
          :o<46?              //      Else-if `o` is a '-':
            r-t               //       Subtract `t` from `r`
          :                   //      Else (`o` is a '/'):
            r/t;}             //       Divide `r` by `t`
      o=q;}                   //    And at the end of every iteration: set `o` to `q`
    System.out.print(r);}}    //    Print the result `r` to STDOUT
Kevin Cruijssen
quelle
1

05AB1E , 30 Bytes

#ćs2ôívy`…+-*sk©i-ë®>i+ë®<i*ë/

Probieren Sie es online aus oder überprüfen Sie alle Testfälle .

Erläuterung:

#           # Split the (implicit) input-string by spaces
 ć          # Pop the list, and push the remainder and first item separated to the stack
  s         # Swap so the remainder is at the top of the stack
   2ô       # Split it into parts of size 2 (operator + number pairs)
     í      # Reverse each pair so the numbers are before the operators
v           # Loop over each of the pairs:
 y`         #  Push the number and operator separated to the stack
   …+-*     #  Push a string "+-*"
       sk   #  Get the index of the operator in this string
         ©  #  Store this index in the register (without popping)
   i        #  If the index is 1 (the "-"):
    -       #   Subtract the numbers from each other
   ë®>i     #  Else-if the index is 0 (the "+"):
       +    #   Add the numbers together
   ë®<i     #  Else-if the index is 2 (the "*"):
       *    #   Multiply the numbers with each other
   ë        #  Else (the index is -1, so "/"):
    /       #   Divide the numbers from each other
            # (and output the result implicitly)

Wenn ein evaleingebauter Code zulässig wäre, könnte dies ein alternativer Ansatz sein ( 16 Byte ):

#ćs2ôJv…(ÿ)y«}.E

Probieren Sie es online aus oder überprüfen Sie alle Testfälle .

Erläuterung:

#ćs2ô    # Same as above
     J   # Join each operator+number pair together to a single string
v        # Loop over the operator+number strings:
 …(ÿ)    #  Surround the top of the stack in parenthesis
     y«  #  And append the operator+number string
}.E      # After the loop: evaluate the string using a Python-eval

Dies würde sich ändern , "-2 + 6 / 2 * 8 - 1 / 2.5 - 18"um "((((((-2)+6)/2)*8)-1)/2.5)-18"vor der Verwendung evalbuiltin (unter Verwendung .Ewürde direkt Operator Vorrang geben */über +-, damit die Konvertierung mit Klammern zuerst).

Kevin Cruijssen
quelle