6
\$\begingroup\$

What's great about golfing is not having to deal with errors. Except this time you won't get off so lightly! I need to do some arithmetic with certain limitations, and I wan't to know what goes wrong if anything.

Challenge

Given a list of signed integer values [n1..n11], give the following result or the first error that occurred.

(((((((((n1+n2)-n3)^n4)/n5)*n6)+n7)-n8)^n9)/n10)*n11

The same in reverse polish notation:

n1 n2 + n3 - n4 ^ n5 / n6 * n7 + n8 - n9 ^ n10 / n11 *

The operators have the following limitations:

  • 0^0 → error 0^0 is undefined
  • 0^a when a<0 → error Negative exponent
  • a/0 → error Division by zero
  • a/b when mod a b != 0 → error Uneven division
  • for any operator: result < 0 → error Integer underflow
  • for any operator: result > 99 → error Integer overflow
  • for any operator: either input value or result == 13 → error 13 is bad luck!

Errors occur left to right, so 13/0 = error 13 is bad luck!.

Scoring

The shortest code in bytes wins. To encourage readability string literals used for errors won't count towards the score.

The output format isn't strict but all seven errors plus a correct value must be distinguishable. Your program/function must retain control flow until the end, so e.g. any exceptions must be caught.

Standard loopholes are disallowed.

Examples

[6,7,14,2,0,1,2,3,4,0,6]   → error `13 is bad luck!`
[6,6,14,2,0,1,2,3,4,0,6]   → error `Integer underflow`
[6,6,12,0,0,1,2,3,4,0,6]   → error `0^0 is undefined`
[6,6,12,2,0,1,2,3,4,0,6]   → error `Division by zero`
[6,6,10,6,12,1,2,3,4,0,6]  → error `Uneven division`
[6,6,10,6,8,17,2,13,4,0,6] → error `Integer overflow`
[6,6,10,6,8,7,99,13,4,0,6] → error `Integer overflow`
[6,6,10,6,8,7,9,99,4,0,6]  → error `Integer underflow`
[6,6,10,6,8,7,9,55,-2,0,0] → error `Negative exponent`
[6,6,10,6,8,7,9,56,2,0,8]  → error `Division by zero`
[6,6,10,6,8,7,9,56,2,9,12] → error `Integer overflow`
[6,6,10,6,8,7,9,56,2,9,11] → 99
\$\endgroup\$
0

1 Answer 1

4
\$\begingroup\$

Haskell, 190 186 185 bytes

311 bytes total, 185 bytes without the string literals.

e=Left
0#0=e"0^0 is undefined"
b#_|b<0=e"Negative exponent"
b#a=t$a^b
0!a=e"Division by zero"
b!a|mod a b>0=e"Uneven division"
b!a=t$div a b
t 13=e"13 is bad luck!"
t x|x<0=e"Integer underflow"|x>99=e"Integer overflow"|1<2=Right x
f(x:y)=foldl(>>=)(t x)$zipWith id(cycle[q(+),q(-),(#),(!),q(*)])y
q=((t.).).flip

This wraps the error handling in the Either e monad, i.e. the result is either Left <ErrorMsg> or Right <Number>, for example:

*Main> f [6,6,10,6,8,7,9,56,2,9,11]
Right 99
*Main> f [6,6,10,6,8,7,9,56,2,0,8] 
Left "Division by zero"

How it works: define custom versions for operators with individual error handling, i.e. # for ^ and ! for / (resp. div as it is called in Haskell) and lift the others (+, -, *) via q into the monad. The main function f creates a list of unary function form the numbers (without the first one) and the list of the operators in order, e.g. [+6, -10, #6, !8, ...] and reduces this list by feeding the first number into a chain of >>=.

Edit: @Angs found a bug. Fixing it saved 4 bytes.

\$\endgroup\$
4
  • \$\begingroup\$ Since yours is the only only answer yet, how would you feel about retroactively adding a clause that any exceptions must be caught at some point – I think it would better demonstrate error handling capabilities \$\endgroup\$
    – Angs
    Nov 22, 2016 at 4:55
  • \$\begingroup\$ Allright, done. \$\endgroup\$
    – Angs
    Nov 22, 2016 at 6:59
  • \$\begingroup\$ One problem I think, inputs aren't checked to be 13, only outputs. \$\endgroup\$
    – Angs
    Nov 22, 2016 at 10:22
  • \$\begingroup\$ @Angs: Yes, but luckily it's easy to fix. It even saved 4 bytes. Thanks! \$\endgroup\$
    – nimi
    Nov 22, 2016 at 10:26

Your Answer

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

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