9
\$\begingroup\$

Create a program that solves a mathematical expression using the elements from alternating sides of the expression. The way it’s done is, instead of reading from left to right, you read the first character, then the last, then the second, then the second to last etc. This will give you a new expression that you must evaluate and output.

a*b/c+d-e
135798642  <-- Order you read the expression in
ae*-bd/+c  <-- Order of operation. 

Example:

1*3/2+4-5
15*-34/+2 = -255

If the expression doesn’t «work», a 1 must be inserted in the necessary positions to make it work.

A few examples will probably illustrate it better:

Input: 1+1+1+1+1
Result: 23     // Because 1+1+1+1+1 -> 11++11++1 -> 23

Input: 1+2-3+12-5
Result: -19    // Because 1+2-3+12-5 -> 15+-22-13+ -> 15+-22-13+1 -> -19
               //                                 |
               //                                 Not valid expression

Input: 2*2*2*2*2
Result: 968    // Because 2*2*2*2*2 -> 22**22**2 -> 22*1*22*1*2 -> 968
               //                        ||  ||
               //                        Not valid, 1 must be inserted

Input: 17/2
Output: 127    // Because 17/2 = 127/ -> 127/1 -> 127

The operators that must be supported are + - * /. There won't be parentheses. Normal math rules and "syntax" is used, so for instance ** does not mean exponentiation. a++++1 is equivalent to a+1 (i.e. MATLAB style, not C++).

In case there's any doubt, some valid operations are:

-a
+a
a++b
a+-b
a*-b
a*+b
a*++b
a/b
a/-b
a/+b
-a/--b

While all of the following are not valid. It's shown what they should be substituted with:

a+      | a+1
a-      | a-1
a++++   | a++++1   (This is equivalent to a+1)
a*+++   | a*+++1   (This is equivalent to a*1)
a**b    | a*1*b
a*/b    | a*1/b
a/*b    | a/1*b
a*      | a*1
*a      | 1*a
***a    | 1*1*1*a

Rules:

  • The code can be a function or a full program
  • The input can be STDIN or function argument
  • The input must be a valid mathematical expression, without quotation marks, '' or "".
  • The output should be the answer to the new expression, as an integer, decimal or a simplified fraction.
  • At least three digits after the decimal point must be supported. So 1/3 = 0.333, not 0.33. 0.333333333 is accepted.
  • ans = ... is accepted.
  • Leading and trailing newlines and spaces are accepted.
  • The input will only be integers
  • Division by zero can result in an error, NaN, Inf etc. Outputting a number is not accepted.

As always, the shortest code in bytes win. A winner will be selected one week from the day the challenge was posted. Answers posted later may still win if it's shorter than the current leader.

\$\endgroup\$
  • \$\begingroup\$ is there a max length on input string or count of operators/integers input? also, do I have to support math up to 2^64, and should it error or wrap if you go over? \$\endgroup\$ – cat Dec 14 '15 at 13:09
  • \$\begingroup\$ "the output should be the answer [ . . . ] simplified fraction ..." so can I just return 0/0 if the expression evals to integer division or modulo by zero? \$\endgroup\$ – cat Dec 14 '15 at 13:12
  • 2
    \$\begingroup\$ If the answer gives division by zero, then x/0 is a valid output. As long as it doesn't output an incorrect answer it's OK. Error and "Not a number" is by definition correct, and infinity is "correct enough", \$\endgroup\$ – Stewie Griffin Dec 14 '15 at 13:16
  • \$\begingroup\$ Just to be sure - eval can be used, right? \$\endgroup\$ – orlp Dec 14 '15 at 15:02
  • \$\begingroup\$ Yes, eval is ok. \$\endgroup\$ – Stewie Griffin Dec 14 '15 at 15:11
3
\$\begingroup\$

Perl, 108 100 bytes

$_="";while(@F){$_.=shift@F;$_.=pop@F}s@(\*|/)\1+@\1@g;s@^[*/]@1$&@;s@\D$@$&1@;s@\D@$&@g;$_=eval

The code is 96 bytes, plus 4 for the command-line argument -pF//, where

  • -p inserts while (<>) { .. } continue { print } and
  • -F// splits the input and puts it in @F.

Note that the input should not have a trailing newline, so use /bin/echo -n 'formula' | perl ...

Less golfed:

$_='';              # reset $_
while(@F) {         # reorder input
   $_.=shift @F;    # take first element off of @_
   $_.=pop @F       # idem for last; if @F is empty, undef is appended
}

s@(\*|/)\1+@\1@g;   # replace 2 or more '*' or '/' with just one: *1 and /1 = nop
s@^[*/]@1$&@;       # if expression starts with * or / prepend a 1
s@\D$@$&1@;         # if expression doesn't end with a number, append 1
s@\D@$& @g;         # eval doesn't like '++1': add spaces after operators
$_ = eval           # set $_ to 3v1l, so the `-p` will print the new value

Testing

Put the above in a file called 114.pl, and the below test script in a file next to it:

%test = (
    '1+1+1+1+1' =>   23,
    '1*3/2+4-5' => -255,
    '1+2-3+12-5'=>  -19,
    '2*2*2*2*2' =>  968,
    '17/2'      =>  127,
    '--/-1-2-'  =>   -2,
    '**2*'      =>    2,
    '++1++'     =>    1,
    '/2/'       =>  0.5,
    '10/'       =>   '',
);

printf "%-20s -> %5s: %5s\n", $_, $test{$_}, `/bin/echo -n '$_' | perl -pF// 114.pl`
for keys %test;

Running it outputs:

++1++                ->     1:     1
**2*                 ->     2:     2
17/2                 ->   127:   127
10/                  ->      :
1+1+1+1+1            ->    23:    23
1*3/2+4-5            ->  -255:  -255
2*2*2*2*2            ->   968:   968
1+2-3+12-5           ->   -19:   -19
--/-1-2-             ->    -2:    -2
/2/                  ->   0.5:   0.5

Note that 1/0 causes a division by zero error: the eval outputs undef, which is represented by the empty string.

\$\endgroup\$
  • \$\begingroup\$ A few more test cases! I'm going to use them \$\endgroup\$ – edc65 Dec 14 '15 at 20:22
3
\$\begingroup\$

JavaScript ES6, 105 106

Edit Saved 1 byte thx @Kenney

t=>eval("for(t=[...t],p=o='';c=t.reverse().pop();p=c)o+=p<'0'?(c=='/'|c<'+'||' ')+c:c;eval(p<'0'?o+1:o)")

// Less golfed
t=>{
  for(t = [...t], p = o = '';
      c = t.reverse().pop();
      p = c)
    o += p<'0' 
     ? (c=='/' | c=='*' || ' ')+c  // '1' or ' '
     : c;
  return eval(p<'0' ? o+1 : o)
}

Test snippet

f=t=>eval("for(t=[...t],p=o='';c=t.reverse().pop();p=c)o+=p<'0'?(c=='/'|c<'+'||' ')+c:c;eval(p<'0'?o+1:o)")

console.log=x=>O.innerHTML+=x+'\n'

function test() { console.log(I.value + ' -> '+f(I.value)) }

;['1+1+1+1+1', '1*3/2+4-5', '1+2-3+12-5', '2*2*2*2*2',
  '17/2', '--/-1-2-', '**2*', '++1++', '/2/', '10/' ]
.forEach(t=>console.log(t+' -> '+f(t)))
Your test <input id=I><button onclick="test()">-></button>
<pre id=O></pre>

\$\endgroup\$
  • \$\begingroup\$ Saved you a byte: p < '0' ? ( c=='/' | c<'+' || ' ' )+c : c ;. \$\endgroup\$ – Kenney Dec 14 '15 at 21:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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