Calculadora básica

20

Debe escribir un programa para evaluar una cadena que se ingresaría en una calculadora.

El programa debe aceptar la entrada y salida de la respuesta correcta. Para los idiomas que no tienen funciones estándar de entrada / salida, puede asumir las funciones readLiney print.

Requisitos

  • No utiliza ningún tipo de funciones "eval"
  • Puede manejar coma flotante y números negativos
  • Admite al menos los operadores +, -, * y /
  • Puede manejar la entrada que contiene uno o más espacios entre los operadores y los números
  • Evalúa la expresión de izquierda a derecha.

El programa que es el más corto gana. En caso de empate, el programa que se presentó primero gana.

Puede suponer que la entrada es válida y sigue el formato correcto

Casos de prueba

Entrada

-4 + 5

Salida

1


Entrada

-7.5 / 2.5

Salida

-3


Entrada

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

Salida

-12
Kevin Brown
fuente
Mi calculadora usa postfix . Consulte también Evaluación de expresiones matemáticas en el desbordamiento de pila para la competencia (aunque no he verificado si las reglas son idénticas).
dmckee
3
El tercer caso de prueba es incorrecto, ya sea que siga el orden estándar de operaciones o realice todas las operaciones de izquierda a derecha. Mirando el segundo caso de prueba, ¿su calculadora redondea el resultado de cada operación?
favor
Se corrigió el segundo y tercer caso de prueba, el resultado no es redondeado.
Kevin Brown
El tercer caso de prueba no sigue el orden estándar de operaciones. ¿Se supone que nuestras respuestas deben?
John
1
¿Qué pasa con el uso de argumentos de línea de comando ARGV? porque el shell se divide automáticamente y enumera los argumentos.
Ming-Tang

Respuestas:

7

Ruby - 74 69 67 65 caracteres

a=0
("+ "+$<.read).split.each_slice 2{|b,c|a=a.send b,c.to_f}
p a
Arnaud Le Blanc
fuente
1
En lugar de utilizar b[0],b[1].to_fse puede reemplazar |b|con |b,c|y el usob,c.to_f
Nemo157
\o gracias ! :-)
Arnaud Le Blanc
1
En lugar de a.send(b,c.to_f)usar a.send b,c.to_f. Se ahorra un char
Anonymous Coward
1
Puede usar en $<lugar deARGF
Dogbert
9

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

Esto está limitado a números enteros ya que Befunge no tiene soporte de coma flotante.

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

Explicación

La mayor característica distintiva de Befunge es que, en lugar de ser un conjunto lineal de instrucciones como la mayoría de los idiomas; Es una cuadrícula 2D de instrucciones de un solo carácter, donde el control puede fluir en cualquier dirección.

El primero &simplemente ingresa el primer número. El vy >luego redirige el control a la ruta principal en la segunda fila.

~:0`!#v_

Esto ingresa un carácter ( ~), lo duplica ( :), empuja cero a la pila ( 0), muestra los dos elementos superiores y determina si el segundo es mayor que el primero ( ` me sorprende que no pueda usar `` para obtener código backticks. ), invierte la veracidad del elemento superior ( !), luego va a la derecha si es cero, de lo contrario hacia abajo ( #v_).

Básicamente es verificar si la entrada -1no representa más entradas.

># $ .# @

Si la entrada fue -1entonces, el valor de entrada duplicado se descarta ( $), la parte superior de la pila se emite como un entero ( .) y el programa se detiene ( @).

:" "`! #v_

De lo contrario, se repite un proceso similar para determinar si la entrada es menor o igual que un espacio. Si es un espacio, entonces el control se cae, de lo contrario, los cabezales de control están a la derecha.

^      ># $ .# @#<

Si es un espacio, se redirige a la izquierda ( <); el programa halt ( @), output ( .) y right redirection ( >) se omiten usando #; pero el descarte se ejecuta para eliminar el espacio de la pila. Finalmente se redirige para comenzar la próxima ejecución ( ^).

:","`#^_

Si no era un espacio, el mismo proceso se usa para dividir si está dentro [+, *]o dentro[-, \] entrando yendo hacia la derecha y hacia arriba respectivamente.

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

Porque [+, *]nuevamente se divide para determinar si es a +o a *. Si +se dirige hacia abajo, el siguiente número es input ( &) y se agregan ( +), el control se envuelve y se redirige a la ruta principal para el siguiente carácter. Si *luego ingresa ( &) y multiplica ( *), entonces se envuelve directamente.

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

Porque [-, \]comienza por la derecha en dirección a la izquierda. Se #omiten los caracteres después de ellos, por lo que la ruta inicial es la "-"`_que simplemente determina si es -o /. Si es /así, continúa a la izquierda para ingresar ( &) y dividir ( /). Si es -así, se dirige hacia la derecha, nuevamente omitiendo caracteres para que se ejecute, lo que da como &"-"$-resultado que se ingrese el número ( &), el -carácter se empuje a la pila y luego se descarte ( "-"$) y luego se calcule la resta ( -). El control se redirige a la ruta principal.

Nemo157
fuente
6

Python 3, 105 bytes

Administra las cuatro operaciones básicas, pero solo cuesta 5 caracteres cada una para agregar ^o agregar %.

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 precedencia de las operaciones es de izquierda a derecha.

daniero
fuente
5

Pitón (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
fuente
1
Es probablemente más fácil usar Python 3
jamylak
5

C - 168126 caracteres

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
fuente
5

Tcl 8.6, 57 48 caracteres.

  • Entrada de argumentos:

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

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

Debe usar el shell interactivo para ambas soluciones.

Trato a la entrada como lista (Tcl utiliza espacios como delimitador) tomar el primer elemento y asignarlo a a, entonces camino sobre el resto, teniendo 2 elementos cada vez, el operador y un segundo número, aplicar el operador de $ay $by asignar el resultado a a. Al final el resultado está adentro a.

Johannes Kuhn
fuente
Ideone admite al menos stdin.
Johannes Kuhn el
Finalmente, vencí a Ruby. Lamentablemente, Idone no es compatible con Tcl 8.6, pero no necesito el resultado, por lmaplo que foreaches un buen reemplazo.
Johannes Kuhn el
4

Haskell: 124 114 caracteres

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

Una respuesta bastante directa, que utiliza la coincidencia de patrones y una declaración de caso simple para el trabajo pesado. Uso:

> ./calc <<< "123 - 12 + -12 / 12.124 * 9.99 - 1"
80.57456285054437
Fors
fuente
1
En lugar de ((case m of{..})(read u)(read b))que puedas escribir ((case m of{..}$read u)$read b), 2 caracteres menos.
swish
4

C: 111108 caracteres

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

Cumple todos los requisitos, uso:

> ./calc <<< "-43 - 56 + 14.123 / -13.22"
6.420348
Fors
fuente
1
~scanfpuede reemplazar +1. Además, c^45-> c%5y c^42-> c%2deberían funcionar.
ugoren
@MDXF no está en mi máquina, pasa todos los casos de prueba aquí. Estoy compilando con Clang en un Macbook Intel bastante moderno, y funciona increíblemente bien (lo probé nuevamente ahora mismo, copié el código desde aquí y lo compilé sin ningún indicador). ¿Qué compilador, arquitectura de procesador y sistema operativo está utilizando?
Fors
@ For Creo que tenía algunas banderas extrañas que inducían un comportamiento extraño; Mi error, está funcionando para mí ahora. Perdón por molestarte.
MD XF
3

C ++ 0x 205 203 198 194 caracteres

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

Bien formateado:

#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
fuente
3

Perl (97)

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

leer de argumentos

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

leer de entrada

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

PostScript (145)

Otra entrada de PostScript (¡gracias a luser droog por excavar los campos de golf interesantes para 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
=

Sin 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
=
Thomas W.
fuente
¡Sigues golpeándome! +1 Esto es muy emocionante.
luser droog
Si puedes superar mi crucigrama , ¡te daré una recompensa! Nota: solo puedes editar 10 veces antes de que la publicación se convierta en CW y los votos no te den puntos de reputación.
luser droog
Te sigo golpeando porque solo elegí aquellos en los que puedo vencerte ;-). No estoy seguro de poder hacerlo con la cuadrícula de crucigramas. Quizás lo intente, pero solo en unas pocas semanas.
Thomas W.
1
Wiki de la comunidad. Significa que la publicación ha sido editada tantas veces que ahora pertenece a la comunidad. Cualquier usuario puede editarlo (sin pasar por la aprobación del moderador requerida para las ediciones sugeridas habituales ), y no más puntos. Así que hagas lo que hagas, detente en la Rev 9. Casi lo soplé en la tabla de guitarra.
luser droog
1
Ignora todo ese agarre de CW. Lo arreglaron!
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())

Versión legible:

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

Toma la expresión como argumento de línea de comando, salida en salida estándar.

golfista9338
fuente
2

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

Y un poco más legible:

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

JavaScript (208 caracteres compactados)

Para mayor claridad, este es el código antes de compactarlo ( JS-Fiddle ):

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)

Aquí se compacta hasta 208 caracteres ( JS-Fiddle ):

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)

Como estoy terminando líneas con punto y coma, se ignoraron todos los espacios en blanco extraíbles para el recuento de caracteres, pero se dejaron en claro.

IQAndreas
fuente
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

El resultado será envuelto en Maybemónada

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

También requiere importar <*>desde Control.Applicative, pero las importaciones se pueden hacer fuera del código, así que espero que esté permitido.

silbido
fuente
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
fuente
Estoy obteniendo '0' por '1 + 1'. IDEONE
Rob
@Mike Input como argumentos, no stdin.
Johannes Kuhn el
1

JavaScript (87 caracteres)

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
fuente
1

Java 11, 151 (como función 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;}

La función Lambda toma una entrada de cadena y emite un flotante.

Pruébalo en línea.

Java 11, 241 bytes (como programa completo con E / S solicitadas)

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

Programa completo que toma una línea de cadena a través de STDIN y la envía a STDOUT.

Pruébalo en línea.

Explicación:

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
fuente
1

05AB1E , 30 bytes

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

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

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

Si evalse permitiera un incorporado, este podría ser un enfoque alternativo ( 16 bytes ):

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

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

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

Esto cambiaría "-2 + 6 / 2 * 8 - 1 / 2.5 - 18"a "((((((-2)+6)/2)*8)-1)/2.5)-18"antes de usar el evalincorporado (usar .Edirectamente daría al operador la precedencia de */over +-, de ahí la conversión con paréntesis primero).

Kevin Cruijssen
fuente