Tell me more ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

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
share|improve this question
My calculator uses postfix. See also Evaluating Mathematical Expressions on Stack Overflow for competition (though I haven't checked if the rules are identical). – dmckee Feb 5 '11 at 19:04
1  
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? – PleaseStand Feb 5 '11 at 19:04
Fixed the second and third test case, the result is not rounded. – Kevin Brown Feb 5 '11 at 19:21
The third test case does not follow the standard order of operations. Are our answers supposed to? – John Feb 5 '11 at 21:35
1  
What about using command line arguments ARGV? because the shell auto-splits and lists the arguments. – SHiNKiROU Feb 6 '11 at 3:01
show 3 more comments

13 Answers

up vote 5 down vote accepted

Ruby - 74 69 67 65 characters

a=0
("+ "+$<.read).split.each_slice 2{|b,c|a=a.send b,c.to_f}
p a
share|improve this answer
1  
Instead of using b[0],b[1].to_f you can replace |b| with |b,c| and use b,c.to_f – Nemo157 Feb 5 '11 at 23:30
\o/ thanks ! :-) – user300 Feb 5 '11 at 23:36
1  
Instead of a.send(b,c.to_f), use a.send b,c.to_f. It saves a char – Charlie Somerville Feb 6 '11 at 5:22
thanks, updated :-) – user300 Feb 6 '11 at 11:21
1  
You can use $< instead of ARGF – Dogbert Feb 7 '11 at 20:15
show 1 more comment

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.

share|improve this answer

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]
share|improve this answer
It's prob just easier to use Python 3 – jamylak Apr 20 at 3:29

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);}
share|improve this answer

Python 3 (105)

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)

Presedense of operations is left to right.

share|improve this answer

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;
}
share|improve this answer

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
share|improve this answer

C# (234) (231) (229) (223)

class A{static void Main (string[]s){var n=true;var o="";var r=0F;foreach(var t in s){if(n){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{
    static void Main (string[]s){
        var n=true;
        var o="";
        var r=0F;

        foreach(var t in s)
        {
            if(n){
                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);
    }
}
share|improve this answer
I'm getting '0' for '1 + 1'. IDEONE – Mike Dtrick Oct 6 '12 at 18:55
@Mike Input as arguments, not stdin. – Johannes Kuhn Apr 20 at 14:55

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
=
share|improve this answer
You keep beating me! +1 This is very exciting. – luser droog Oct 19 '12 at 7:20
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. – luser droog Oct 19 '12 at 7:42
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. – Thomas W. Oct 19 '12 at 9:54
BTW, what does CW mean? – Thomas W. Oct 19 '12 at 9:55
1  
Ignore all that CW griping. They fixed it! – luser droog Oct 22 '12 at 6:05
show 1 more comment

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
share|improve this answer
1  
~scanf can replace +1. Also, c^45->c%5 and c^42->c%2 should work. – ugoren Apr 21 at 7:31

Tcl 8.6, 57 chars.

  • Input from arguments:

    lmap o\ b [lassign $argv a] {set a [expr $a$o$b]};puts $a
    
  • From Stdin (64)

    lmap o\ b [lassign [gets stdin] a] {set a [expr $a$o$b]};puts $a
    
share|improve this answer
Ideone supports at least stdin. – Johannes Kuhn Apr 19 at 20:39
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. – Johannes Kuhn Apr 23 at 11:56

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
share|improve this answer

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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