3
\$\begingroup\$

String is given in form of a variable. Let's call that variable s. It is known that the string looks like a calculation expression using +, -, *, /. There's no parentheses.

Calculate the expression inside the string and store the result in variable r (you can assume it's already declared). All the divisions can be performed without remainders (4-6*3/8 is invalid because 8 is not divisible by 3). Length of string is not limited. String can't contain 0.

Challenge is not supposed to give advantage for some languages, so I decided to change some math rules:

Operators precedence is a little bit different than it is in math and programming language expressions: multiplication/division is still higher than addition/substraction. However, if there're some multiplications/divisions in a row, it is performed right-to-left. Addition/substraction is preformed left-to-right.

Sample s and r:

2+5-6/9*8+7 -> 2

1/3*6-6 -> 12

The shortest code (in bytes) wins.

\$\endgroup\$
8
  • \$\begingroup\$ You know, you can also just say don't use any eval equivalents. \$\endgroup\$
    – marinus
    Commented Jan 6, 2014 at 0:02
  • 3
    \$\begingroup\$ Nice point. But new math rules sound like more fun ;) \$\endgroup\$
    – gthacoder
    Commented Jan 6, 2014 at 0:03
  • 2
    \$\begingroup\$ You're also not really supposed to change the question after you post it, because you could invalidate previously posted answers. In this case it doesn't matter, but to iron out any mistakes/gotchas, you can post your question in the sandbox (on meta) first to discuss it. \$\endgroup\$
    – marinus
    Commented Jan 6, 2014 at 0:08
  • \$\begingroup\$ Yeah, I know. I was thinking not much people viewed the question text at that point, so I could change it a little bit. "In runtime." Sorry. \$\endgroup\$
    – gthacoder
    Commented Jan 6, 2014 at 0:12
  • \$\begingroup\$ @gthacoder Only me and marinus :) I've added on a solution that meets all the new requirements. \$\endgroup\$
    – Timtech
    Commented Jan 6, 2014 at 0:13

6 Answers 6

6
\$\begingroup\$

Mathematica (41)

s = "2+5-6/9*8+7";
ToExpression@StringReplace[s,"/"->"^-1 "]

2

Correct me if I'm wrong

\$\endgroup\$
3
\$\begingroup\$

Ruby, 24

 r=eval s.gsub ?/,'**-1*'

Thank you to @ybeltukov for the Mathematica technique. I thought there might be a substitution that could be used to leverage eval and yours was much simpler than the crazy regexes I was trying!

This shortcut effectively changes the operator precedence in s to what the question requires. It has the side effect of sometimes resulting in a Rational object type (e.g. 2/1 == 2). The results are correct for the cases I've tried.

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

Perl 5, 27 20

s/(.)\//1\/$1*/g;print eval

Edit:

s/\//**-1*/g;$r=eval

Assuming the input of:

$_ = "2+5-6/9*8+7";
> $r = 2

and

$_ = "1/3*6-6";
> $r = 12

This regex is based in the mathematical theory of @ybeltukov, I'm new to regex so it probably could be much better.

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

JavaScript (213 characters compacted, 133 if I'm willing to sacrifice my soul)

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 = parseInt(leftDigit)
    var R = parseInt(rightDigit)
    switch (operator)
    {
        case '*': return R*L;
        case '\/': return R/L;
        case '+': return L+R;
        case '-': return L-R;
    }
};

multAndDivRegex = /(\-?\d+)([\*\/])(\-?\d+)(?=[^\*\/]*$)/; //Right to left
addAndSubRegex = /(\-?\d+)([\+\-])(\-?\d+)/; // Left to right

while(multAndDivRegex.test(str)) {
    str = str.replace(multAndDivRegex, math);
}

while(addAndSubRegex.test(str)) {
    str = str.replace(addAndSubRegex, math);
}

Here it is compacted down to 213 characters (containing some extra help from Toni Almeida) (JS-Fiddle of it):

function m(x,l,o,r){
    L=~~l;R=~~r;
    return o=='*'?R*L:o=='/'?R/L:o=='+'?L+R:L-R
}

for(M=/(\-?\d+)([\*\/])(\-?\d+)(?=[^\*\/]*$)/;M.test(s);s=s.replace(M,m));
for(A=/(\-?\d+)([\+\-])(\-?\d+)/;A.test(r=s);s=s.replace(A,m));

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

I can get it down to 133 characters if I use eval(), but that's not how I roll... (JS-Fiddle)

function m(x,l,o,r){return o=='*'?~~r*~~l:~~r/~~l}for(M=/(\-?\d+)([\*\/])(\-?\d+)(?=[^\*\/]*$)/;M.test(s);s=s.replace(M,m));r=eval(s)

This solution would mean that people can enter ANY JavaScript code they want! The 303 character version does not execute any JavaScript; it only does math.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ May I say, I loved this challenge! :D \$\endgroup\$
    – IQAndreas
    Commented Jan 6, 2014 at 11:46
  • \$\begingroup\$ Well done! Here is a compacted version of your huge switch statment: o=='*'?R*L:o=='\/'?R/L:o=='+'?L+R:o=='-'?L-R:0 \$\endgroup\$ Commented Jan 7, 2014 at 9:12
  • \$\begingroup\$ By the way, you can save 4 characters by removing { and } from you while's, as they have only 1 instruction, they are useless. \$\endgroup\$ Commented Jan 7, 2014 at 9:15
  • \$\begingroup\$ Here is, 257 char version: jsfiddle.net/promatik/5W3nQ/2 \$\endgroup\$ Commented Jan 7, 2014 at 9:27
  • \$\begingroup\$ @ToniAlmeida Magnificent! Thanks. I trimmed off a few more characters in addition to that after re-reading the rules about allowing the use of s and r instead of input/output functions: jsfiddle.net/IQAndreas/5W3nQ/3 \$\endgroup\$
    – IQAndreas
    Commented Jan 9, 2014 at 18:53
1
\$\begingroup\$

Python 3, 35

r=int(eval(s.replace("/","**-1*")))

Python 3, 30

If you are not scared of floating point value, try this one.

r=eval(s.replace("/","**-1*"))

Both of them evaluate the string s and store the result in variable r

\$\endgroup\$
1
  • \$\begingroup\$ This doesn't work. It gives 0 for "4/2" \$\endgroup\$
    – recursive
    Commented Jan 9, 2014 at 21:42
0
\$\begingroup\$

GTB, 6

x?_)→R

6 chars and 6 bytes

EDIT - now that the original question has changed, here's some bloated code:

@iS_,"*")\\iS_,"/$_4;I,1,l?A;)-1:s;A;,2I,1)+A;&s;A;,1I→_&x?_)→R

I think I did a pretty good job; I made it only 63 characters ;) more than 1,000% bloat

\$\endgroup\$
2
  • \$\begingroup\$ I changed question a little bit. Now it is as supposed. \$\endgroup\$
    – gthacoder
    Commented Jan 5, 2014 at 23:55
  • \$\begingroup\$ I changed answer a little bit. Now it is as required. \$\endgroup\$
    – Timtech
    Commented Jan 6, 2014 at 0:13

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.