A calculator as a list of numbers and operators

Your task is to take a list of arguments that are either integers or operators, and parse them like so:

1. There is a current operator, which starts as +.

2. Each time an operator is found, the current operator will change to it.

3. The possible operators are: "+", "-", "*", "/", and "%", which correspond to their meanings in C and most languages.

4. There is a running solution kept, which starts at 0.

5. Each time an integer is found, the solution is modified by the number depending on the operator; e.g. if the operator is "/" then the solution is divided by the number.

6. If an operation would result in a mixed number (i.e. with a decimal) then it must be floored back to an integer (i.e. the decimal must be chopped off).

7. Output the final solution.

For example:

The arguments 5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14 would result in:

  5 8  25 * 9   6    2    - 104  / 4    7      + 6 % 14
0 5 13 38   342 2052 4104   4000   1000 142   148    8  -> 8


The inputs will be as command-line or function arguments, or an equivalent for your language.

Shortest code wins!

• when you say meanings in C do you mean exactly as they do in C, or is it okay if % rounds towards -inf instead of 0? Sep 1, 2015 at 3:35
• @Maltysen: Whatever your language does. Sep 1, 2015 at 3:43
• Can the integers from input be negative? Sep 1, 2015 at 5:03
• Points 3 and 6 contradict each other: in C and most languages, integer division rounds towards zero rather than flooring. Sep 1, 2015 at 6:24
• It would be interesting to see another challenge similar to this, but including parenthesis precedence... Sep 2, 2015 at 7:54

JavaScript (ES6) 53

A function taking an array as input.

Run the snippet in Firefox to test.

f=a=>a.map(t=>t<'0'?o=t:v=eval(v+o+t)|0,v=0,o='+')&&v

// TEST
out=x=>O.innerHTML=x;

input = [5,8,25,"*",9,6,2,"-",104,"/",4,7,"+",6,"%",14];
out(input.join(' ')+' -> '+f(input));

function go() {
i=I.value.split(/ +/),out(I.value+' -> '+f(i))
}  
<pre id=O></pre>
Your test:<input id=I><button onclick='go()'>GO</button>

Pyth - 242322 20 bytes

2 bytes saved thanks to @issacg and 1 thanks to @orlp!

Uses reduce with base case of 0 and checks for ' being in repr to detect string vs. int.

u.xsv++GbH&=bHG+\+QZ


Does not work online because I use full eval which is disabled online for security reasons. Takes input from stdin in a list as such: 5, 8, 25, "*", 9, 6, 2, "-", 104, "/", 4, 7, "+", 6.

• You can save 2 bytes by switching from ? to .x, because only the else block can throw an exception, and it will do so every time. You can't use K, anymore, though. u.xsv++GbH&=bHG+\+QZ, specifically. Sep 1, 2015 at 7:04

Julia, 85 83 bytes

s->(o=0;p="+";for i=split(s) isdigit(i)?o=eval(parse("ifloor($o$p$i)")):(p=i)end;o)  This creates an unnamed function that accepts a string as input and returns an integer. Ungolfed: function f(s::String) # Assign the starting output value o and operator p o = 0 p = "+" # Split the input string into an array on spaces for i = split(s) if isdigit(i) # Assign o using string interpolation o = eval(parse("ifloor($o $p$i)"))
else
# Assign p to the new operator
p = i
end
end
end


Fixed issue and saved 2 bytes thanks to Glen O.

• Julia complains that o is not defined when you try to run the function freshly. It tries to run the "o=ifloor..." function in Main, rather than inside the function (see here github.com/JuliaLang/julia/issues/2386 ). Might I suggest s->(o=0;p="+";for i=split(s) isdigit(i)?o=eval(parse("ifloor($o$p$i)")):p=i;end;o)? Sep 1, 2015 at 13:15 • @GlenO I don't know how I didn't catch that. :/ Thanks, fixed. Sep 1, 2015 at 16:00 elisp, 101 bytes With the arguments passed as a quoted list: e.g. (c '(5 5 * 10))  (defun c(a)(let((f 0)(o '+))(dolist(x a)(if(not(integerp x))(setf o x)(setq f (eval(list o f x)))))f))  Version with new lines:  (defun c (a) (let ((f 0) (o '+)) (dolist (x a) (if (not (integerp x)) (setf o x) (setq f (eval (list o f x))))) f))  CJam, 24 bytes 0'+ea+{_A,s&O{:O;}?S}%s~  This is a full program that reads the input as command-line arguments. To try the code online in the CJam interpreter (which doesn't support command-line arguments), replace ea with lS/ to read from simulated STDIN. How it works 0'+ Push a 0 and the character '+'. ea Push the array of command-line arguments. + Prepend the character to the array. { }% For each element: _ Push a copy. A,s Push "0123456789". & Intersect the copy with the string of digits. { }? If the intersection is non-empty: O The element is a number. Push O. :O; The element is an operator. Save it in O. S Push a space. s~ Flatten the array of strings and evaluate it.  JavaScript, 85 bytes r=0;o="+";prompt().split(" ").forEach(t=>+t+1?r=parseInt(eval(r+o+ +t)):o=t);alert(r)  • why o+ +t? you are building a string anyway, no need to convert to number. Moreover, .forEach has no place in Code Golf: use .map Sep 1, 2015 at 9:06 • ... and ~~ instead of parseInt (codegolf.stackexchange.com/a/2788/21348) Sep 1, 2015 at 9:06 • prompt(o="+",r=0).split(" ").forEach(t=>+t+1?r=+eval(r+o+ +t):o=t);alert(r) --> 75 bytes. Sep 1, 2015 at 16:57 Lua, 142 bytes function f(s)o="+"r=0 for c in s:gmatch"%S+" do if tonumber(c)~=nil then loadstring("r=r"..o..c)() else o=c end r=math.floor(r)end print(r)end  Ungolfed: function f(s) o="+" --original operator r=0 --return value for c in s:gmatch"%S+" do --split by spaces if tonumber(c)~=nil then --check if the current character is a number loadstring("r=r"..o..c)() --appends the current operator and current character ex "r=r+5" and then evaluates as another Lua script else o=c --if the character is not a number, it is the new operator end r=math.floor(r) --floor after each operation end print(r) --print the result end  Powershell, 57 bytes $o="+"
$args|%{$r=iex "$r$o$_" if(!$?){$o=$_}$r-=$r%1}
$r  ungolfed; $operator="+"
$args | ForEach-Object {$result = Invoke-Expression "$result$operator $_" if(!$?)
{
$operator=$_
}
$result -=$result % 1
}
$result  If the implicit variable in the for-each is an operator rather than number, Invoke-Expression (POSH's eval()) will fail and the execution status $? will be false.

Floor in POSH is unwieldy - $foo=[math]::floor($foo) and $foo-=$foo%1 was the golfiest alternative I could think of.

• Nice. I read it a little more literally by assuming a string input and parsing it on spaces, then ifing on digits, but essentially the same. 89 Bytes $o="+";$r=0;$args-split'\s+'|%{if($_-match'^\d+$'){$r=iex $r$o$_;$r-=$r%1}Else{$o=$_}};$r Sep 1, 2015 at 18:21

GNU Sed (with the eval extension, + dc), 102

(Score includes +1 for the -r option to sed.)

s/.*/0 + &p/
s/([-+/*%]) ([0-9]+)/\2 \1/g
:
s/([-+/*%] )([0-9]+ )([0-9]+)/\1\2\1\3/
t
s/.*/dc<<<'&'/e


Transforms the input expression to reverse polish notation, and then uses dc to evaluate it.

Test output:

$sed -rf calclist.sed <<< '5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14' 8$


CJam, 34 bytes

'+0lS/{"+-*/%"1$#){@;\}{i2$~}?}/\;


Try it online

I thought this was going to be fairly reasonable. But I wasn't fast enough posting it to be the shortest CJam answer at least for a moment. :(

Python 3 - 131 bytes129 bytes121 bytes 116 Bytes

Thanks to Maltysen for shaving off two bytes, Beta Decay for shaving off 8, and Steven Rumbalski for shaving off 5.

def f(x):
a,b="+",0
for i in x:
if i in"+-*/%":a=i
else:b=int(eval(str(b)+a+i))
return b


I'm trying to figure out a way to reduce the length of the if statement, but for now this seems about as golfed as I can get it. Takes input as a list.

• you can save some bytes on indentation and replacing int with //1 Sep 1, 2015 at 3:46
• also, why the parens in the if? Sep 1, 2015 at 3:47
• @ Maltysen whoops, I forgot I didn't need the parentheses in the if statement. Thanks. I don't think that using //1 will be allowed, though I didn't think to use it, as it seems to leave a trailing 0 (e.g. 10.0) which I don't think is allowed.
– cole
Sep 1, 2015 at 3:53
• i don't think you need that space between in and the quote. Sep 1, 2015 at 3:56
• You could save some bytes by assuming that list is passed in the function arguments and getting rid of .split(). Sep 1, 2015 at 7:59

Bash, 69

set -f
for t in $* do ((1${t}1>2))&&((r${o-+}=$t))||o=$t done echo$r


This only works with non-negative integers - its not clear in the question if this is ok or not.

Groovy, 79 bytes

def f(x,a=0,b='+'){x.each{z->a=z=~/\d/?Eval.me(a+b+z)as int:a;b=z=~/\d/?b:z};a}


Demo:

groovy> f([5,8,25,'*',9,6,2,'-',104,'/',4,7,'+',6,'%', 14])
Result: 8


Ungolfed:

def f(x, a=0, b='+') {
x.each {z->
a = z =~ /\d/ ? Eval.me(a+b+z) as int : a
b = z =~ /\d/ ? b : z
}
a
}


Perl 5.10+, 52 bytes

perl -E '$o="+";/\D/?$o=$_:eval"$x=int$x$o$_"for@ARGV;say$x'


Demo:

$perl -E '$o="+";/\D/?$o=$_:eval"\x=int$xo_"for@ARGV;sayx' 5 8 25 \* 9 6 2 - 104 / 4 7 + 6 % 14 8  (Note that * has to be escaped in my shell so it's not interpreted as a glob pattern.) Ungolfed: o="+"; # Start with addition /\D/ ? o=_ # If not a number, update the current operator : eval"$x=int\$x$o$_" # Otherwise, make a string like '$x=int$x+1' and eval it for@ARGV; # Repeat for each item in the argument list say$x                        # Print the result


C#, 132 165 168 bytes

This function assumes the input is valid. This is tough for C# given there's no eval equivalent.

Thanks edc65 for saving 33 bytes!

Indented for clarity.

int C(string[]a){
int o=1,r=0,n;
foreach(var b in a)
n=int.TryParse(b,out n)
?r=o<0?r%n
:o<1?r*n
:o<2?r+n
:o<4?r-n
:r/n
:o=b[0]-42;
return r;
}

• You can take out most of the newlines. Sep 1, 2015 at 23:47
• I haven't counted any newlines or insignificant whitespace. Sep 2, 2015 at 3:40
• 132 using ?: -->int C(string[]a){int o=1,r=0,n;foreach(var b in a)n=int.TryParse(b,out n)?r=o<0?r%n:o<1?r*n:o<3?r+n:o<5?r-n:r/n:o=b[0]-42;return r;} Sep 4, 2015 at 13:13

Ruby, 59 bytes

a=0
o=?+
gets.split.map{|s|s=~/\d/?a=eval([a,s]*o):o=s}
p a


Test run:

\$ ruby calc.rb <<< "5 8 25 * 9 6 2 - 104 / 4 7 + 6 % 14"
8


C 122

Thanks to @ceilingcat for finding a much better (and shorter) version

#define A atoi(*a):s
o,s;main(z,a)char**a;{for(;*++a;)**a<48?o=**a-43:(1?s=o+6?o-4?~o?o-2?o?:s+A-A*A/A%A);printf("%d",s);}


Try it online!

But if you are compiling it with mingw32 you need to turn off globbing (see https://www.cygwin.com/ml/cygwin/1999-11/msg00052.html) by compiling like this:

gcc x.c C:\Applications\mingw32\i686-w64-mingw32\lib\CRT_noglob.o
`