Calcolatrice di base


20

È necessario scrivere un programma per valutare una stringa che verrebbe inserita in una calcolatrice.

Il programma deve accettare input e output la risposta corretta. Per le lingue che non dispongono di funzioni standard di input / output, è possibile assumere le funzioni readLinee print.

Requisiti

  • Non utilizza alcun tipo di funzione "eval"
  • Può gestire numeri in virgola mobile e negativi
  • Supporta almeno gli operatori +, -, * e /
  • Può gestire input contenenti uno o più spazi tra operatori e numeri
  • Valuta l'espressione da sinistra a destra

Il programma più corto vince. In caso di pareggio, il programma presentato per primo vince.

Si può presumere che l'input sia valido e segua il formato corretto

Casi test

Ingresso

-4 + 5

Produzione

1


Ingresso

-7.5 / 2.5

Produzione

-3


Ingresso

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

Produzione

-12

La mia calcolatrice utilizza Postfix . Vedi anche Valutazione delle espressioni matematiche su Stack Overflow per la concorrenza (anche se non ho verificato se le regole sono identiche).
dmckee,

3
Il terzo caso di test è errato, indipendentemente dal fatto che segua l'ordine standard delle operazioni o esegua tutte le operazioni da sinistra a destra. Guardando il secondo caso di test, la tua calcolatrice arrotonda il risultato di ogni operazione?
favore

Risolto il secondo e il terzo caso di test, il risultato non è arrotondato.
Kevin Brown,

Il terzo caso di test non segue l'ordine standard delle operazioni. Le nostre risposte dovrebbero?
Giovanni,

1
Che dire dell'utilizzo degli argomenti della riga di comando ARGV? perché la shell si divide automaticamente ed elenca gli argomenti.
Ming-Tang,

Risposte:


7

Rubino - 74 69 67 65 caratteri

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

1
Invece di utilizzare b[0],b[1].to_fè possibile sostituire |b|con |b,c|e l'usob,c.to_f
Nemo157

\ o / grazie! :-)
Arnaud Le Blanc,

1
Invece di a.send(b,c.to_f), utilizzare a.send b,c.to_f. Salva un
codardo anonimo

1
È possibile utilizzare $<invece diARGF
Dogbert

9

Befunge - 37 x 5 = 185 38 x 3 = 114 caratteri

Questo è limitato ai numeri interi poiché Befunge non ha supporto in virgola mobile.

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

Spiegazione

La più grande caratteristica distintiva di Befunge è che invece di essere un insieme lineare di istruzioni come la maggior parte delle lingue; è una griglia 2d di istruzioni a carattere singolo, in cui il controllo può fluire in qualsiasi direzione.

Il primo &inserisce semplicemente il primo numero. Il controllo reindirizza ve >quindi al percorso principale sulla seconda riga.

~:0`!#v_

Questo inserisce un carattere ( ~), lo duplica ( :), spinge zero sulla pila ( 0), apre i primi due elementi e determina se il secondo è maggiore del primo ( ` sono sorpreso che non puoi usare `` '' per ottenere code backticks. ), inverte la veridicità dell'elemento top ( !), quindi va bene se è zero, in basso altrimenti ( #v_).

Fondamentalmente sta controllando se l'input -1non rappresenta più input.

># $ .# @

Se l'input era -1allora il valore di input duplicato viene scartato ( $), la parte superiore dello stack viene emessa come numero intero ( .) e il programma viene arrestato ( @).

:" "`! #v_

Altrimenti si ripete un processo simile per determinare se l'ingresso è inferiore o uguale a uno spazio. Se è uno spazio, il controllo scende, altrimenti controlla le teste a destra.

^      ># $ .# @#<

Se è uno spazio, viene reindirizzato a sinistra ( <); il programma halt ( @), output ( .) e il reindirizzamento destro ( >) vengono saltati usando #; ma lo scarto viene eseguito per rimuovere lo spazio dallo stack. Alla fine viene reindirizzato fino a iniziare la prossima esecuzione ( ^).

:","`#^_

Se non era uno spazio, lo stesso processo viene utilizzato per dividere se è in [+, *]o [-, \]andando rispettivamente verso destra e verso l'alto.

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

Perché [+, *]è di nuovo diviso per determinare se si tratta di a +o a *. Se +viene indirizzato verso il basso, viene immesso il numero successivo ( &) e vengono aggiunti ( +), quindi il controllo si avvolge e viene reindirizzato fino al percorso principale per il carattere successivo. Se *poi inserisce ( &) e moltiplica ( *), quindi si avvolge direttamente.

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

Perché [-, \]inizia sulla destra, andando a sinistra. La #'s saltare il carattere dopo di loro in modo che il percorso iniziale è "-"`_che determina semplicemente se è -o /. In tal caso, /continua a sinistra per input ( &) e divide ( /). Se lo è, -si dirige a destra, saltando di nuovo i caratteri in modo che si esegua &"-"$-risultando nel numero immesso ( &) il -personaggio che viene spinto nella pila e poi scartato ( "-"$) e quindi la sottrazione calcolata ( -). Il controllo viene quindi reindirizzato al percorso principale.


6

Python 3, 105 byte

Gestisce le quattro operazioni di base, ma costa solo 5 caratteri ciascuna da aggiungere ^o %.

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)

La precedenza delle operazioni è da sinistra a destra.


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
Probabilmente è più semplice usare Python 3
jamylak il

5

C - 168 126 caratteri

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 caratteri.

  • Input da argomenti:

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

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

Devi usare la shell interattiva per entrambe le soluzioni.

I trattare l'ingresso come elenco (Tcl utilizza spazi come delimitatori) prendere il primo elemento e assegnare a a, allora cammino sul resto, prendendo 2 elementi ogni volta, il pilota ed un secondo numero, applicare l'operatore $aed $be assegnare il risultato a a. Alla fine il risultato è in a.


Ideone supporta almeno lo stdin.
Johannes Kuhn,

Alla fine, ho battuto Ruby. Sfortunatamente Idone non supporta Tcl 8.6, ma non ho bisogno del risultato, lmapquindi foreachè un buon sostituto.
Johannes Kuhn,

4

Haskell: 124 114 caratteri

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

Una risposta piuttosto diretta, usando il pattern matching e una semplice dichiarazione del caso per il sollevamento pesante. Uso:

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

1
Invece di ((case m of{..})(read u)(read b))te puoi scrivere ((case m of{..}$read u)$read b), 2 caratteri in meno.
Swish,

4

C: 111 108 caratteri

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

Soddisfa tutti i requisiti, utilizzo:

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

1
~scanfpuò sostituire +1. Inoltre, c^45-> c%5e c^42-> c%2dovrebbero funzionare.
ugoren,

@MDXF non è sulla mia macchina, passa qui tutti i casi di test. Sto compilando con Clang su un Macbook Intel abbastanza moderno e funziona perfettamente (l'ho provato di nuovo proprio ora, ho copiato il codice da qui e l'ho appena compilato senza flag). Quale compilatore, architettura del processore e sistema operativo stai usando?
Fors

@Perché credo di avere delle strane bandiere che inducono comportamenti strani; errore mio, ora funziona per me. Mi dispiace disturbarla.
MD XF,

3

C ++ 0x 205 203 198 194 caratteri

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

Ben formattato:

#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

letto dagli argomenti

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

letto dall'input

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

Un'altra voce PostScript (grazie al droog utente per scavare i campi da golf interessanti per 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
=

Un-giocato a golf:

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

Continui a picchiarmi! +1 Questo è molto eccitante.
Luser droog,

Se riesci a battere il mio cruciverba , ti darò una taglia! NB Puoi modificare solo 10 volte prima che il post diventi CW e i voti non guadagnano punti rep.
Luser droog,

Continuo a picchiarti perché ho scelto solo quelli in cui posso batterti ;-). Non sono sicuro di poterlo fare con la griglia del cruciverba. Forse ci proverò, ma solo tra poche settimane.
Thomas W.

1
Wiki della comunità. Significa che il post è stato modificato così tante volte che ora appartiene alla community. Qualsiasi utente può modificarlo (ignorando l'approvazione del moderatore richiesta per le normali modifiche suggerite ) e non più punti. Quindi, qualunque cosa tu faccia, fermati al Rev 9. L'ho quasi fatto saltare sulla chitarra uno.
Luser droog

1
Ignora tutto quel grip CW. L'hanno risolto!
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())

Versione leggibile:

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

Prende espressione come argomento da riga di comando, output su output standard.


2

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

E un po 'più leggibile:

%!
/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 (208 caratteri compattati)

Per chiarezza, questo è il codice prima di comprimerlo ( JS-Fiddle di esso ):

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)

Qui è compattato fino a 208 caratteri ( JS-Fiddle di esso ):

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)

Dal momento che sto terminando le linee con punti e virgola, tutti gli spazi bianchi rimovibili sono stati ignorati per il conteggio dei personaggi, ma sono stati lasciati per chiarezza.


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

Il risultato sarà racchiuso nella Maybemonade

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

Inoltre richiede l'importazione <*>da Control.Applicative, ma le importazioni possono essere eseguite al di fuori del codice, quindi spero sia consentito.


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

Ricevo '0' per '1 + 1'. IDEONE
Rob,

@Mike Input come argomenti, non stdin.
Johannes Kuhn,

1

JavaScript (87 caratteri)

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 (come funzione 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;}

Funzione Lambda che accetta un input String e produce un float.

Provalo online.

Java 11, 241 byte (come programma completo con I / O richiesto)

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

Programma completo che prende una linea di stringa attraverso STDIN e viene inviato a STDOUT.

Provalo online.

Spiegazione:

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 byte

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

Provalo online o verifica tutti i casi di test .

Spiegazione:

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

Se evalfosse consentito un built-in, questo potrebbe essere un approccio alternativo ( 16 byte ):

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

Provalo online o verifica tutti i casi di test .

Spiegazione:

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

Questo cambierebbe "-2 + 6 / 2 * 8 - 1 / 2.5 - 18"in "((((((-2)+6)/2)*8)-1)/2.5)-18"prima di usare il evalbuiltin (usare .Edirettamente darebbe all'operatore la precedenza di */over +-, quindi la conversione con parentesi prima).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.