Calculatrice de base

20

Vous devez écrire un programme pour évaluer une chaîne qui serait entrée dans une calculatrice.

Le programme doit accepter l'entrée et la sortie de la bonne réponse. Pour les langues qui n'ont pas de fonctions d'entrée / sortie standard, vous pouvez assumer les fonctions readLineet print.

Exigences

  • N'utilise aucun type de fonctions "eval"
  • Peut gérer les nombres à virgule flottante et négatifs
  • Prend en charge au moins les opérateurs +, -, * et /
  • Peut gérer une entrée contenant un ou plusieurs espaces entre les opérateurs et les nombres
  • Évalue l'expression de gauche à droite

Le programme le plus court gagne. En cas d'égalité, le programme soumis en premier l'emporte.

Vous pouvez supposer que l'entrée est valide et suit le format correct

Cas de test

Contribution

-4 + 5

Production

1


Contribution

-7.5 / 2.5

Production

-3


Contribution

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

Production

-12
Kevin Brown
la source
Ma calculatrice utilise le suffixe . Voir aussi Évaluation des expressions mathématiques sur le débordement de pile pour la compétition (bien que je n'ai pas vérifié si les règles sont identiques).
dmckee
3
Le troisième scénario de test est incorrect - que vous suiviez l'ordre des opérations standard ou effectuiez toutes les opérations de gauche à droite. En regardant le deuxième cas de test, votre calculatrice arrondit-elle le résultat de chaque opération?
PleaseStand
Correction des deuxième et troisième cas de test, le résultat n'est pas arrondi.
Kevin Brown
Le troisième cas de test ne suit pas l'ordre standard des opérations. Nos réponses sont-elles censées le faire?
John
1
Qu'en est-il de l'utilisation des arguments de ligne de commande ARGV? car le shell se divise automatiquement et répertorie les arguments.
Ming-Tang

Réponses:

7

Ruby - 74 69 67 65 caractères

a=0
("+ "+$<.read).split.each_slice 2{|b,c|a=a.send b,c.to_f}
p a
Arnaud Le Blanc
la source
1
Au lieu d'utiliser , b[0],b[1].to_fvous pouvez remplacer |b|avec |b,c|et l' utilisationb,c.to_f
Nemo157
\Oh merci ! :-)
Arnaud Le Blanc
1
Au lieu de a.send(b,c.to_f), utilisez a.send b,c.to_f. Il sauve un char
lâche anonyme
1
Vous pouvez utiliser à la $<place deARGF
Dogbert
9

Befunge - 37 x 5 = 185 38 x 3 = 114 caractères

Ceci est limité aux nombres entiers car Befunge n'a pas de support en virgule flottante.

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

Explication

La plus grande caractéristique distinctive de Befunge est qu'au lieu d'être un ensemble linéaire d'instructions comme la plupart des langues; c'est une grille 2D d'instructions à caractère unique, où le contrôle peut circuler dans n'importe quelle direction.

Le premier &saisit simplement le premier nombre. Le v, >puis rediriger le contrôle vers le chemin principal sur la deuxième ligne.

~:0`!#v_

Cela entre un caractère ( ~), le duplique ( :), pousse zéro sur la pile ( 0), fait apparaître les deux premiers éléments et détermine si le second est supérieur au premier ( ` je suis surpris que vous ne puissiez pas utiliser `` `pour obtenir code backticks. ), inverse la véracité de l'élément supérieur ( !), puis va à droite s'il est nul, vers le bas sinon ( #v_).

Fondamentalement, il vérifie si l'entrée ne -1représente plus d'entrée.

># $ .# @

Si l'entrée était -1alors la valeur d'entrée dupliquée est supprimée ( $), le haut de la pile est sorti sous forme d'entier ( .) et le programme est arrêté ( @).

:" "`! #v_

Sinon, un processus similaire est répété pour déterminer si l'entrée est inférieure ou égale à un espace. S'il s'agit d'un espace, le contrôle descend, sinon le contrôle se dirige vers la droite.

^      ># $ .# @#<

S'il s'agit d'un espace, il est redirigé vers la gauche ( <); le programme halt ( @), output ( .) et redirection droite ( >) sont tous ignorés en utilisant #; mais le rejet est exécuté pour supprimer l'espace de la pile. Enfin, il est redirigé vers le haut pour commencer la prochaine exécution ( ^).

:","`#^_

Si ce n'était pas un espace, le même processus est utilisé pour se diviser s'il est dans [+, *]ou en [-, \]allant à droite et en haut respectivement.

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

Car [+, *]il est de nouveau divisé pour déterminer s'il s'agit d'un +ou d'un *. S'il +est dirigé vers le bas, le nombre suivant est input ( &) et ils sont ajoutés ( +), le contrôle se retourne et est redirigé vers le chemin principal pour le caractère suivant. Si *alors il entre ( &) et multiplie ( *), il s'enroule directement.

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

Car [-, \]cela commence à droite en direction de gauche. Les #sautent le caractère après eux pour que le chemin initial soit "-"`_qui détermine simplement si c'est -ou /. Si c'est le cas, il /continue à gauche pour entrer ( &) et diviser ( /). Si c'est le cas, il se -dirige vers la droite, en ignorant à nouveau les caractères afin qu'il s'exécute, &"-"$-ce qui entraîne l'entrée du nombre ( &), le -caractère étant poussé sur la pile, puis rejeté ( "-"$) et la soustraction calculée ( -). Le contrôle est ensuite redirigé vers le chemin principal.

Nemo157
la source
6

Python 3, 105 octets

Gère les quatre opérations de base, mais il ne coûte que 5 caractères chacun pour ajouter ^ou %.

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 priorité des opérations est de gauche à droite.

daniero
la source
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
la source
1
Il est probablement plus facile d'utiliser Python 3
jamylak
5

C - 168 126 caractères

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
la source
5

Tcl 8.6, 57 48 caractères.

  • Entrée d'arguments:

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

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

Vous devez utiliser le shell interactif pour les deux solutions.

Je traite l'entrée sous forme de liste (Tcl utilise des espaces comme délimiteur) prennent le premier élément et l' affecter à a, puis je marche sur le reste, en 2 éléments à chaque fois, l'opérateur et un second nombre, appliquer l'opérateur $aet $bet attribuer la résultat à a. À la fin, le résultat est là a.

Johannes Kuhn
la source
Ideone prend en charge au moins stdin.
Johannes Kuhn
Enfin, j'ai battu Ruby. Malheureusement, Idone ne prend pas en charge Tcl 8.6, mais je n'ai pas besoin du résultat lmap, foreachc'est donc un bon remplacement.
Johannes Kuhn
4

Haskell: 124114 caractères

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

Une réponse assez simple, utilisant la correspondance de motifs et une simple déclaration de cas pour le levage de charges lourdes. Usage:

> ./calc <<< "123 - 12 + -12 / 12.124 * 9.99 - 1"
80.57456285054437
Fors
la source
1
Au lieu de ((case m of{..})(read u)(read b))vous pouvez écrire ((case m of{..}$read u)$read b), 2 caractères de moins.
swish
4

C: 111 108 caractères

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

Il remplit toutes les exigences, utilisation:

> ./calc <<< "-43 - 56 + 14.123 / -13.22"
6.420348
Fors
la source
1
~scanfpeut remplacer +1. De plus, c^45-> c%5et c^42-> c%2devraient fonctionner.
ugoren
@MDXF n'est pas sur ma machine, il passe tous les tests ici. Je compile avec Clang sur un Macbook Intel assez moderne, et cela fonctionne très bien (je l'ai testé à nouveau tout à l'heure, j'ai copypéé le code d'ici et je l'ai compilé sans aucun indicateur). Quel compilateur, quelle architecture de processeur et quel système d'exploitation utilisez-vous?
Fors
@Pour je crois que j'avais quelques drapeaux étranges qui induisaient un comportement étrange; mon erreur, ça marche pour moi maintenant. Désolé de vous déranger.
MD XF
3

C ++ 0x 205 203 198 194 caractères

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

Joliment formaté:

#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
la source
3

Perl (97)

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

lire des arguments

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

lire depuis l'entrée

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

PostScript (145)

Une autre entrée PostScript (merci à luser droog pour avoir creusé les golfs intéressants pour 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
=

Non-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.
la source
Tu continues de me battre! +1 C'est très excitant.
luser droog
Si vous pouvez battre mes mots croisés , je vous donnerai une prime! NB Vous ne pouvez éditer que 10 fois avant que le post ne devienne CW et les votes ne vous rapportent pas de points rep.
luser droog
Je continue de te battre parce que je n'ai choisi que ceux où je peux te battre ;-). Je ne sais pas si je peux avec la grille de mots croisés. J'essaierai peut-être, mais seulement dans quelques semaines.
Thomas W.19
1
Wiki de la communauté. Cela signifie que le message a été modifié tant de fois qu'il appartient désormais à la communauté. Tout utilisateur peut le modifier (en contournant l'approbation du modérateur requise pour les modifications suggérées habituelles ), et pas plus de points. Donc, quoi que vous fassiez, arrêtez-vous sur Rev 9. Je l'ai presque fait exploser sur la guitare.
luser droog
1
Ignorez tout ce grip CW. Ils l'ont réparé!
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())

Version lisible:

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

Prend l'expression comme argument de ligne de commande, sortie sur la sortie standard.

golfeur9338
la source
2

Post-scriptum (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

Et un peu plus lisible:

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

JavaScript (208 caractères compactés)

Pour plus de clarté, voici le code avant de le compacter ( 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)

Ici, il est compacté à 208 caractères ( JS-Fiddle de celui-ci ):

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)

Comme je termine les lignes par des points-virgules, tous les espaces amovibles ont été ignorés pour le comptage des caractères, mais laissés pour plus de clarté.

IQAndreas
la source
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

Le résultat sera enveloppé dans la Maybemonade

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

Il faut également importer <*>depuis Control.Applicative, mais les importations peuvent être effectuées en dehors du code, donc j'espère que c'est autorisé.

bruissement
la source
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
la source
Je reçois «0» pour «1 + 1». IDEONE
Rob
@Mike Input comme arguments, pas stdin.
Johannes Kuhn
1

JavaScript (87 caractères)

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
la source
1

Java 11, 151 (en tant que fonction 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;}

Fonction lambda prenant une entrée String et sortant un flottant.

Essayez-le en ligne.

Java 11, 241 octets (en tant que programme complet avec E / S demandées)

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

Programme complet prenant une ligne de chaîne via STDIN et sortie vers STDOUT.

Essayez-le en ligne.

Explication:

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
la source
1

05AB1E , 30 octets

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

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

#           # 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 une fonction evalintégrée était autorisée, cela pourrait être une approche alternative ( 16 octets ):

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

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

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

Cela changerait "-2 + 6 / 2 * 8 - 1 / 2.5 - 18"à "((((((-2)+6)/2)*8)-1)/2.5)-18"avant d' utiliser la evalcommande intégrée ( en utilisant .Edirectement l' opérateur donnerait priorité de */plus +-, d' où la conversion avec parenthèses en premier).

Kevin Cruijssen
la source