21
\$\begingroup\$

You must write a program to evaluate a string that would be entered into a calculator.

The program must accept input and output the correct answer. For languages that do not have standard input/output functions, you may assume the functions readLine and print.

Requirements

  • Does not use any kind of "eval" functions
  • Can handle floating point and negative numbers
  • Supports at least the +, -, *, and / operators
  • Can handle input containing one or more spaces between the operators and numbers
  • Evaluates the expression from left to right

The program that is the shortest wins. In the event of a tie, the program that was submitted first wins.

You can assume that the input is valid and follows the correct format

Test Cases

Input

-4 + 5

Output

1


Input

-7.5 / 2.5

Output

-3


Input

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

Output

-12
\$\endgroup\$
13
  • \$\begingroup\$ My calculator uses postfix. See also Evaluating Mathematical Expressions on Stack Overflow for competition (though I haven't checked if the rules are identical). \$\endgroup\$ Commented Feb 5, 2011 at 19:04
  • 3
    \$\begingroup\$ Third test case is wrong - whether you follow standard order of operations or perform all operations left to right. Looking at the second test case, does your calculator round the result of each operation? \$\endgroup\$ Commented Feb 5, 2011 at 19:04
  • \$\begingroup\$ Fixed the second and third test case, the result is not rounded. \$\endgroup\$ Commented Feb 5, 2011 at 19:21
  • \$\begingroup\$ The third test case does not follow the standard order of operations. Are our answers supposed to? \$\endgroup\$
    – John
    Commented Feb 5, 2011 at 21:35
  • 1
    \$\begingroup\$ What about using command line arguments ARGV? because the shell auto-splits and lists the arguments. \$\endgroup\$
    – Ming-Tang
    Commented Feb 6, 2011 at 3:01

20 Answers 20

9
\$\begingroup\$

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

This is limited to integer numbers as Befunge has no floating point support.

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

Explanation

The biggest distinguishing feature of Befunge is that instead of being a linear set of instructions like most languages; it is a 2d grid of single character instructions, where control can flow in any direction.

The first & simply inputs the first number. The v and > then redirect control to the main path on the second row.

~:0`!#v_

This inputs a character (~), duplicates it (:), pushes zero onto the stack (0), pops the top two elements and determines if the second is greater than the first (` I'm surprised you can't use ``` to get code backticks.), inverts the truthiness of the top element (!), then goes right if it is zero, down otherwise (#v_).

Basically it's checking whether the input is -1 representing no more input.

># $ .# @

If the input was -1 then the duplicated input value is discarded ($), the top of the stack is output as an integer (.) and the program is halted (@).

:" "`! #v_

Otherwise a similar process is repeated to determine if the input is less than or equal to a space. If it is a space then control goes down, otherwise control heads right.

^      ># $ .# @#<

If it is a space then it's redirected left (<); the program halt (@), output (.) and right redirection (>) are all skipped using #; but the discard is executed to remove the space from the stack. Finally it's redirected up to begin the next execution (^).

:","`#^_

If it wasn't a space the same process is used to split on if it is in [+, *] or in [-, \] going right and up respectively.

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

For [+, *] it is again split to determine whether it is a + or a *. If + it is directed down then the next number is input (&) and they are added (+), the control then wraps around and is redirected up to the main path for the next character. If * then it inputs (&) and multiplies (*) then directly wraps around.

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

For [-, \] it starts on the right heading left. The #'s skip the character after them so the initial path is "-"`_ which simply determines if it is - or /. If it is / then it continues left to input (&) and divide (/). If it is - then it heads right, again skipping characters so that it executes &"-"$- resulting in the number being input (&) the - character being pushed onto the stack then discarded ("-"$) and then the subtraction being calculated (-). The control is then redirected back to the main path.

\$\endgroup\$
8
\$\begingroup\$

Ruby - 74 69 67 65 characters

a=0
("+ "+$<.read).split.each_slice 2{|b,c|a=a.send b,c.to_f}
p a
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Instead of using b[0],b[1].to_f you can replace |b| with |b,c| and use b,c.to_f \$\endgroup\$
    – Nemo157
    Commented Feb 5, 2011 at 23:30
  • 1
    \$\begingroup\$ Instead of a.send(b,c.to_f), use a.send b,c.to_f. It saves a char \$\endgroup\$ Commented Feb 6, 2011 at 5:22
  • 1
    \$\begingroup\$ You can use $< instead of ARGF \$\endgroup\$
    – Dogbert
    Commented Feb 7, 2011 at 20:15
6
\$\begingroup\$

Python 3, 105 bytes

Manages the four basic operations, but it only costs 5 characters each to add ^ or %.

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)

Precedence of operations is left to right.

\$\endgroup\$
5
\$\begingroup\$

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]
\$\endgroup\$
1
  • 1
    \$\begingroup\$ It's prob just easier to use Python 3 \$\endgroup\$
    – jamylak
    Commented Apr 20, 2013 at 3:29
5
\$\begingroup\$

C - 168 126 characters

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);}
\$\endgroup\$
5
\$\begingroup\$

Tcl 8.6, 57 48 chars.

  • Input from arguments:

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

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

You have to use the interactive shell for both solutions.

I treat the input as list (Tcl uses spaces as delimiter) take the first element and assign it to a, then I walk over the rest, taking 2 elements each time, the operator and a second number, apply the operator on $a and $b and assign the result to a. At the end the result is in a.

\$\endgroup\$
2
  • \$\begingroup\$ Ideone supports at least stdin. \$\endgroup\$ Commented Apr 19, 2013 at 20:39
  • \$\begingroup\$ Finally, I beat Ruby. Unfortunately Idone does not support Tcl 8.6, but I don't need the result of lmap so foreach is a good replacement. \$\endgroup\$ Commented Apr 23, 2013 at 11:56
4
\$\begingroup\$

C++0x 205 203 198 194 chars

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

Nicely formatted:

#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;
}
\$\endgroup\$
4
\$\begingroup\$

Haskell: 124 114 characters

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

A rather straight-forward answer, using pattern matching and a simple case statement for the heavy lifting. Usage:

> ./calc <<< "123 - 12 + -12 / 12.124 * 9.99 - 1"
80.57456285054437
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Instead of ((case m of{..})(read u)(read b)) you can write ((case m of{..}$read u)$read b), 2 characters less. \$\endgroup\$
    – swish
    Commented Jan 6, 2014 at 15:28
4
\$\begingroup\$

C: 111 108 characters

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

It fulfills all the requirements, usage:

> ./calc <<< "-43 - 56 + 14.123 / -13.22"
6.420348
\$\endgroup\$
3
  • 1
    \$\begingroup\$ ~scanf can replace +1. Also, c^45->c%5 and c^42->c%2 should work. \$\endgroup\$
    – ugoren
    Commented Apr 21, 2013 at 7:31
  • \$\begingroup\$ @MDXF not on my machine, it passes every test case here. I'm compiling with Clang on a fairly modern Intel Macbook, and it works smashingly well (I tested it again just now, I copypasted the code from here and just compiled it without any flags). What compiler, processor architecture and OS are you using? \$\endgroup\$
    – Fors
    Commented Oct 8, 2017 at 1:21
  • \$\begingroup\$ @Fors I believe I had some odd flags that were inducing strange behavior; my mistake, it's working for me now. Sorry to bother you. \$\endgroup\$
    – MD XF
    Commented Oct 8, 2017 at 1:24
3
\$\begingroup\$

Perl (97)

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

read from 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;

read from 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
\$\endgroup\$
0
3
\$\begingroup\$

PostScript (145)

Another PostScript entry (thanks to luser droog for digging the golfs interesting for 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-golfed:

[/+{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
=
\$\endgroup\$
6
  • \$\begingroup\$ You keep beating me! +1 This is very exciting. \$\endgroup\$ Commented Oct 19, 2012 at 7:20
  • \$\begingroup\$ If you can beat my crossword, I'll give you a bounty! N.B. You can only edit 10 times before the post becomes CW and votes don't earn you rep points. \$\endgroup\$ Commented Oct 19, 2012 at 7:42
  • \$\begingroup\$ I keep beating you because I only chose the ones where I can beat you ;-). I'm not sure whether I can with the crossword grid. I'll maybe try, but only in a few weeks. \$\endgroup\$
    – Thomas W.
    Commented Oct 19, 2012 at 9:54
  • 1
    \$\begingroup\$ Community Wiki. It means the post has been edited so many times it now belongs to the community. Any user can edit it (bypassing the moderator approval required for the usual suggested edits), and no more points. So whatever you do, stop on Rev 9. I almost blew it on the guitar tab one. \$\endgroup\$ Commented Oct 20, 2012 at 6:45
  • 1
    \$\begingroup\$ Ignore all that CW griping. They fixed it! \$\endgroup\$ Commented Oct 22, 2012 at 6:05
3
\$\begingroup\$

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

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

Takes expression as command-line argument, output on standard output.

\$\endgroup\$
2
\$\begingroup\$

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

And a little more readable:

%!
/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
\$\endgroup\$
2
\$\begingroup\$

JavaScript (208 characters compacted)

For clarity, this is the code before I compacted it down (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)

Here it is compacted down to 208 characters (JS-Fiddle of it):

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)

Since I'm ending lines with semi-colons, all removable whitespace was ignored for character counting, but left in for clarity.

\$\endgroup\$
2
\$\begingroup\$

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

The result will be wrapped in Maybe monad

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

Also it requires importing <*> from Control.Applicative, but imports can be done outside the code, so I hope it's allowed.

\$\endgroup\$
2
\$\begingroup\$

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);
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ I'm getting '0' for '1 + 1'. IDEONE \$\endgroup\$
    – anon
    Commented Oct 6, 2012 at 18:55
  • \$\begingroup\$ @Mike Input as arguments, not stdin. \$\endgroup\$ Commented Apr 20, 2013 at 14:55
1
\$\begingroup\$

JavaScript (87 characters)

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

05AB1E, 30 bytes

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

Try it online or verify all test cases.

Explanation:

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

If an eval builtin was allowed, this could be an alternative approach (16 bytes):

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

Try it online or verify all test cases.

Explanation:

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

This would change "-2 + 6 / 2 * 8 - 1 / 2.5 - 18" to "((((((-2)+6)/2)*8)-1)/2.5)-18" before using the eval builtin (using .E directly would give operator precedence of */ over +-, hence the conversion with parenthesis first).

\$\endgroup\$
1
\$\begingroup\$

Java 10, 151 145 (as lambda function)

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

-6 bytes thanks to @ceilingcat.

Lambda function taking a String input and outputting a float.

Try it online.

Java 10, 241 235 bytes (as full program with asked 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);}}

Full program taking a String-line through STDIN and outputting to STDOUT.

Try it online.

Explanation:

interface M{                  // Class
  static void main(String[]a){//  Mandatory main-method
    float r=0,                //   Result float, starting at 0
          t,                  //   Temp float
          o=0,                //   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)-43)>4){
                              //    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<0?                //      If `o` is a '*':
            r*t               //       Multiply `r` by `t`
          :o<1?               //      Else-if `o` is a '+':
            r+t               //       Add `r` and `t` together
          :o<3?               //      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
\$\endgroup\$
0
1
\$\begingroup\$

ZX81 BASIC (might be cheating, so just for fun/non-competing), ~14 Tokenised BASIC bytes, 6 key entries without new line (ZX81 speak for enter)

1 INPUT A
2 PRINT A

Whilst this does not explicitly use any kind of "eval" functions, ZX81 BASIC evaluates any mathematical expressions in its ROM if you are inputing to a floating point variable of which A would be (like most 8-bit BASIC variants, string variables will have a $ at the end of the variable name). So when you enter the program and RUN it, you can type like 12+10*6 and this will output 72 (note the ZX81 keyboard has some odd key placements for +, /, - and * etc).

The byte count is as follows: as I recall, each line number is stored as 4 bytes, and INPUT is a single token, as is PRINT (you cannot free type in ZX81 BASIC to enter BASIC commands, so to enter the INPUT command, press I, and to enter the PRINT command, press P). I don't recall how many bytes are stored at the end of each BASIC line entered, but let's assume that it is a single byte, hence my estimate of 14 tokenised BASIC bytes. I'll find out the exact number at a later time (if this is not cheating).

You may try this online with the JtyOne Online ZX81 Emulator which helpfully has an interactive keyboard below the running emulator.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.