Podstawowy kalkulator


20

Musisz napisać program oceniający ciąg znaków, który zostałby wprowadzony do kalkulatora.

Program musi zaakceptować wejście i wyjście prawidłową odpowiedź. W przypadku języków, które nie mają standardowych funkcji wejścia / wyjścia, możesz przejąć funkcje readLinei print.

Wymagania

  • Nie używa żadnych funkcji „eval”
  • Obsługuje liczby zmiennoprzecinkowe i liczby ujemne
  • Obsługuje co najmniej operatorów +, -, * i /
  • Obsługuje dane wejściowe zawierające jedną lub więcej spacji między operatorami a liczbami
  • Ocenia wyrażenie od lewej do prawej

Najkrótszy program wygrywa. W przypadku remisu program, który został zgłoszony jako pierwszy, wygrywa.

Możesz założyć, że dane wejściowe są prawidłowe i mają poprawny format

Przypadki testowe

Wejście

-4 + 5

Wynik

1


Wejście

-7.5 / 2.5

Wynik

-3


Wejście

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

Wynik

-12

Mój kalkulator korzysta z Postfiksa . Zobacz także Ocena wyrażeń matematycznych dotyczących przepełnienia stosu w konkurencji (chociaż nie sprawdziłem, czy reguły są identyczne).
dmckee,

3
Trzeci przypadek testowy jest nieprawidłowy - niezależnie od tego, czy wykonujesz standardową kolejność operacji, czy wykonujesz wszystkie operacje od lewej do prawej. Patrząc na drugi przypadek testowy, czy Twój kalkulator zaokrągla wynik każdej operacji?
wstać

Naprawiono drugi i trzeci przypadek testowy, wynik nie jest zaokrąglany.
Kevin Brown

Trzeci przypadek testowy nie jest zgodny ze standardową kolejnością operacji. Czy nasze odpowiedzi powinny?
Jana

1
Co z użyciem argumentów wiersza polecenia ARGV? ponieważ powłoka automatycznie dzieli się i wyświetla argumenty.
Ming-Tang,

Odpowiedzi:


7

Ruby - 74 69 67 65 znaków

a=0
("+ "+$<.read).split.each_slice 2{|b,c|a=a.send b,c.to_f}
p a

1
Zamiast korzystać b[0],b[1].to_fmożna zastąpić |b|z |b,c|i wykorzystanieb,c.to_f
Nemo157

\o dzięki ! :-)
Arnaud Le Blanc

1
Zamiast tego a.send(b,c.to_f)użyj a.send b,c.to_f. To oszczędza char
anonimowy tchórz

1
Możesz użyć $<zamiastARGF
Dogbert

9

Befunge - 37 x 5 = 185 38 x 3 = 114 znaków

Jest to ograniczone do liczb całkowitych, ponieważ Befunge nie obsługuje zmiennoprzecinkowych.

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

Wyjaśnienie

Największą cechą wyróżniającą Befunge jest to, że zamiast być liniowym zestawem instrukcji, jak większość języków; jest siatką 2d instrukcji jednoznakowych, w których kontrola może płynąć w dowolnym kierunku.

Pierwsza &po prostu wprowadza pierwszą liczbę. vA >następnie przekierowanie sterowania do głównej ścieżki w drugim rzędzie.

~:0`!#v_

To wprowadza znak ( ~), powiela go ( :), wypycha zero na stos ( 0), wyskakuje z górnych dwóch elementów i określa, czy drugi jest większy od pierwszego ( ` jestem zaskoczony, że nie można użyć `` '', aby uzyskać kod backticks. ), odwraca prawdziwość górnego elementu ( !), a następnie idzie w prawo, jeśli wynosi zero, w przeciwnym razie ( #v_).

Zasadniczo sprawdza, czy dane wejściowe -1nie reprezentują już danych wejściowych.

># $ .# @

Jeśli dane wejściowe były -1następnie zduplikowane wartości wejściowe są odrzucane ( $), górna część stosu jest wyprowadzana jako liczba całkowita ( .), a program jest zatrzymywany ( @).

:" "`! #v_

W przeciwnym razie podobny proces powtarza się w celu ustalenia, czy dane wejściowe są mniejsze lub równe spacji. Jeśli jest to spacja, kontrola spada, w przeciwnym razie kieruj w prawo.

^      ># $ .# @#<

Jeśli jest to spacja, to przekierowuje left ( <); program halt ( @), output ( .) i prawe przekierowanie ( >) są pomijane za pomocą #; ale odrzucenie jest wykonywane w celu usunięcia przestrzeni ze stosu. Wreszcie jest przekierowywany w celu rozpoczęcia następnego wykonania ( ^).

:","`#^_

Jeśli nie była to spacja, ten sam proces jest używany do podziału, jeśli jest odpowiednio w [+, *]lub w [-, \]prawo i w górę.

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

Na [+, *]to jest podzielona w celu określenia, czy jest to +albo *. Jeśli +jest skierowany w dół, to wprowadzana jest następna liczba ( &) i są one dodawane ( +), a następnie formant zawija się i zostaje przekierowany do głównej ścieżki dla następnego znaku. Jeśli *następnie wpisze ( &) i mnoży ( *), wówczas bezpośrednio się zawija.

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

Ponieważ [-, \]zaczyna się po prawej stronie po lewej stronie. #„S pominąć znak po nich tak początkowa jest ścieżka "-"`_, która określa, czy po prostu jest -albo /. Jeśli tak, /to kontynuuje wprowadzanie ( &) i dzielenie ( /). Jeśli tak, -to kieruje się w prawo, ponownie pomijając znaki, aby wykonać, &"-"$-powodując wprowadzenie liczby ( &), -znak jest wypychany na stos, a następnie odrzucany ( "-"$), a następnie obliczane jest odejmowanie ( -). Sterowanie jest następnie przekierowywane z powrotem do głównej ścieżki.


6

Python 3, 105 bajtów

Zarządza czterema podstawowymi operacjami, ale dodawanie ^lub kosztuje tylko 5 znaków %.

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)

Pierwszeństwo operacji jest od lewej do prawej.


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]

1
Prawdopodobnie łatwiej jest używać Pythona 3
jamylak 20.04.2013

5

C - 168 126 znaków

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

5

Tcl 8.6, 57 48 znaków.

  • Dane wejściowe z argumentów:

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

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

Musisz użyć interaktywnej powłoki dla obu rozwiązań.

Traktuję wejście w formie listy (Tcl używa spacji jako separatora) podejmuje pierwszy element i przypisać go a, a potem chodzić na resztę, biorąc 2 elementy każdym razem, operator i drugi numer, należy zastosować operator na $ai $bi przypisać wynik do a. Na koniec wynik jest w a.


Ideone obsługuje co najmniej standardowe wejście .
Johannes Kuhn

W końcu pokonałem Ruby. Niestety, Idone nie obsługuje Tcl 8.6, ale nie potrzebuję wyniku, lmapwięc foreachjest to dobry zamiennik.
Johannes Kuhn

4

Haskell: 124 114 znaków

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

Raczej prosta odpowiedź, wykorzystująca dopasowanie wzoru i proste stwierdzenie przypadku ciężkiego podnoszenia. Stosowanie:

> ./calc <<< "123 - 12 + -12 / 12.124 * 9.99 - 1"
80.57456285054437

1
Zamiast tego ((case m of{..})(read u)(read b))możesz pisać ((case m of{..}$read u)$read b), 2 znaki mniej.
świst

4

C: 111 108 znaków

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

Spełnia wszystkie wymagania, zastosowanie:

> ./calc <<< "-43 - 56 + 14.123 / -13.22"
6.420348

1
~scanfmoże zastąpić +1. Ponadto, c^45-> c%5i c^42-> c%2powinny działać.
ugoren 21.04.2013

@MDXF nie ma na moim komputerze, przechodzi tutaj każdy przypadek testowy. Kompiluję z Clangiem na dość nowoczesnym MacBooku z procesorem Intel i działa on miażdżąco dobrze (przetestowałem go teraz jeszcze raz, skopiowałem stąd kod i po prostu skompilowałem go bez żadnych flag). Z jakiego kompilatora, architektury procesora i systemu operacyjnego korzystasz?
Fors

@Fors Myślę, że miałem dziwne flagi, które wywoływały dziwne zachowanie; mój błąd, teraz działa dla mnie. Przepraszam, że przeszkadzam.
MD XF,

3

C ++ 0x 205 203 198 194 znaków

#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;}

Ładnie sformatowany:

#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;
}

3

Perl (97)

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

czytać z argumentów

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

odczytać z wejścia

@_=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

3

PostScript (145)

Kolejny wpis PostScript (dzięki luser droog do kopania golfów interesujących PostScript!):

[/+{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
=

Bez golfa:

[/+{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
=

Bicie mnie! +1 To jest bardzo ekscytujące.
luser droog

Jeśli zdołasz pokonać moją krzyżówkę , dam ci nagrodę! Uwaga: Możesz edytować tylko 10 razy, zanim post zmieni się w CW, a głosy nie będą zdobywać punktów rep.
luser droog

Ciągle bije cię, bo wybrałem tylko te, gdzie można pokonać ;-). Nie jestem pewien, czy mogę z siatką krzyżówki. Może spróbuję, ale tylko za kilka tygodni.
Thomas W.,

1
Wiki Wiki. Oznacza to, że post był edytowany tyle razy, że teraz należy do społeczności. Każdy użytkownik może go edytować (z pominięciem zatwierdzenia moderatora wymaganego dla zwykłych sugerowanych zmian) i nie więcej punktów. Cokolwiek więc zrobisz, zatrzymaj się w wersji 9. Prawie wysadziłem to na gitarze.
luser droog

1
Zignoruj ​​to chwytanie CW. Naprawili to!
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())

Wersja do odczytu:

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

Przyjmuje wyrażenie jako argument wiersza poleceń, wyprowadzane na standardowe wyjście.


2

Postscriptum (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

I trochę bardziej czytelny:

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

2

JavaScript (skompresowane 208 znaków)

Dla jasności jest to kod przed jego kompaktowaniem ( JS-Fiddle of it ):

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)

Tutaj jest spakowany do 208 znaków ( JS-Fiddle tego ):

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)

Ponieważ kończę linie średnikami, wszystkie usuwalne białe znaki zostały zignorowane do zliczania znaków, ale pozostawiono je dla przejrzystości.


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

Wynik zostanie zawinięty w Maybemonadę

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

Wymaga również importowania <*>z Control.Applicative, ale import można wykonać poza kodem, więc mam nadzieję, że jest to dozwolone.


2

DO# (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);
    }
}

Dostaję „0” za „1 + 1”. IDEONE
Rob

@ Mike Wprowadź jako argumenty, a nie standardowe.
Johannes Kuhn

1

JavaScript (87 znaków)

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

1

Java 11, 151 (jako funkcja lambda)

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

Funkcja lambda pobierająca dane wejściowe typu String i wysyłająca liczbę zmiennoprzecinkową.

Wypróbuj online.

Java 11, 241 bajtów (jako pełny program z pytaniem o operacje we / wy)

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

Pełny program przechodzący przez ciąg STDIN i wysyłający do STDOUT.

Wypróbuj online.

Wyjaśnienie:

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

1

05AB1E , 30 bajtów

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

Wypróbuj online lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie:

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

Jeśli evalwbudowane było dozwolone, może to być alternatywne podejście ( 16 bajtów ):

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

Wypróbuj online lub sprawdź wszystkie przypadki testowe .

Wyjaśnienie:

#ć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

To zmieniłoby się "-2 + 6 / 2 * 8 - 1 / 2.5 - 18"na "((((((-2)+6)/2)*8)-1)/2.5)-18"przed użyciem evalwbudowanego (użycie .Ebezpośrednio dałoby operatorowi pierwszeństwo */przed +-, stąd konwersja z nawiasami jako pierwsza).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.