From 735f1d584a566437bdb186eb78254274af512ad8 Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Sat, 13 Jan 2018 08:52:29 -0500 Subject: [PATCH] Add remainder function --- src/function/builtin/math/REMAINDER.java | 35 ++++++ src/table/FunctionTable.java | 2 + test/function/builtin/math/MODULOTest.java | 18 +-- test/function/builtin/math/REMAINDERTest.java | 105 ++++++++++++++++++ 4 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 src/function/builtin/math/REMAINDER.java create mode 100644 test/function/builtin/math/REMAINDERTest.java diff --git a/src/function/builtin/math/REMAINDER.java b/src/function/builtin/math/REMAINDER.java new file mode 100644 index 0000000..ede2d17 --- /dev/null +++ b/src/function/builtin/math/REMAINDER.java @@ -0,0 +1,35 @@ +package function.builtin.math; + +import function.ArgumentValidator; +import function.FunctionNames; +import function.LispFunction; +import function.builtin.math.DIVIDE.DivideByZeroException; +import sexpression.Cons; +import sexpression.LispNumber; +import sexpression.SExpression; + +@FunctionNames({ "REM", "REMAINDER" }) +public class REMAINDER extends LispFunction { + + private ArgumentValidator argumentValidator; + + public REMAINDER(String name) { + this.argumentValidator = new ArgumentValidator(name); + this.argumentValidator.setExactNumberOfArguments(2); + this.argumentValidator.setEveryArgumentExpectedType(LispNumber.class); + } + + @Override + public SExpression call(Cons argumentList) { + argumentValidator.validate(argumentList); + LispNumber dividend = (LispNumber) argumentList.getFirst(); + LispNumber divisor = (LispNumber) ((Cons) argumentList.getRest()).getFirst(); + + try { + return new LispNumber(dividend.getValue().remainder(divisor.getValue())); + } catch (ArithmeticException e) { + throw new DivideByZeroException(); + } + } + +} diff --git a/src/table/FunctionTable.java b/src/table/FunctionTable.java index 57932e1..383ce24 100644 --- a/src/table/FunctionTable.java +++ b/src/table/FunctionTable.java @@ -29,6 +29,7 @@ import function.builtin.math.MINUS; import function.builtin.math.MODULO; import function.builtin.math.MULTIPLY; import function.builtin.math.PLUS; +import function.builtin.math.REMAINDER; import function.builtin.predicate.ATOM; import function.builtin.predicate.EQ; import function.builtin.predicate.EQUAL; @@ -98,6 +99,7 @@ public class FunctionTable { allBuiltIns.add(PROGN.class); allBuiltIns.add(QUOTE.class); allBuiltIns.add(RECUR.class); + allBuiltIns.add(REMAINDER.class); allBuiltIns.add(REST.class); allBuiltIns.add(SET.class); allBuiltIns.add(SETQ.class); diff --git a/test/function/builtin/math/MODULOTest.java b/test/function/builtin/math/MODULOTest.java index efe838b..93f2403 100644 --- a/test/function/builtin/math/MODULOTest.java +++ b/test/function/builtin/math/MODULOTest.java @@ -1,5 +1,6 @@ package function.builtin.math; +import static testutil.TestUtilities.assertIsErrorWithMessage; import static testutil.TestUtilities.assertSExpressionsMatch; import static testutil.TestUtilities.evaluateString; @@ -85,17 +86,13 @@ public class MODULOTest extends SymbolAndFunctionCleaner { } @Test(expected = ModulusNotPositiveException.class) - public void divisorOfZero() { - String input = "(mod 5 0)"; - - assertSExpressionsMatch(new LispNumber("0"), evaluateString(input)); + public void negativeDivisor() { + evaluateString("(mod 5 -10)"); } @Test(expected = ModulusNotPositiveException.class) - public void negativeDivisor() { - String input = "(mod 5 -10)"; - - assertSExpressionsMatch(new LispNumber("0"), evaluateString(input)); + public void divisorOfZero() { + evaluateString("(mod 5 0)"); } @Test(expected = BadArgumentTypeException.class) @@ -112,4 +109,9 @@ public class MODULOTest extends SymbolAndFunctionCleaner { public void modWithTooManyArguments() { evaluateString("(mod 1 2 3)"); } + + @Test + public void moduloNotPositiveException_HasCorrectAttributes() { + assertIsErrorWithMessage(new ModulusNotPositiveException()); + } } diff --git a/test/function/builtin/math/REMAINDERTest.java b/test/function/builtin/math/REMAINDERTest.java new file mode 100644 index 0000000..d5096ab --- /dev/null +++ b/test/function/builtin/math/REMAINDERTest.java @@ -0,0 +1,105 @@ +package function.builtin.math; + +import static testutil.TestUtilities.assertSExpressionsMatch; +import static testutil.TestUtilities.evaluateString; + +import org.junit.Test; + +import function.ArgumentValidator.BadArgumentTypeException; +import function.ArgumentValidator.TooFewArgumentsException; +import function.ArgumentValidator.TooManyArgumentsException; +import function.builtin.math.DIVIDE.DivideByZeroException; +import sexpression.LispNumber; +import testutil.SymbolAndFunctionCleaner; + +public class REMAINDERTest extends SymbolAndFunctionCleaner { + + @Test + public void rem() { + String input = "(rem 5 3)"; + + assertSExpressionsMatch(new LispNumber("2"), evaluateString(input)); + } + + @Test + public void remainder() { + String input = "(remainder 11 7)"; + + assertSExpressionsMatch(new LispNumber("4"), evaluateString(input)); + } + + @Test + public void dividendGreaterThanDivisor() { + String input = "(rem 21 19)"; + + assertSExpressionsMatch(new LispNumber("2"), evaluateString(input)); + } + + @Test + public void dividendLessThanDivisor() { + String input = "(rem 5 239)"; + + assertSExpressionsMatch(new LispNumber("5"), evaluateString(input)); + } + + @Test + public void dividendEqualToDivisor() { + String input = "(rem 5 5)"; + + assertSExpressionsMatch(new LispNumber("0"), evaluateString(input)); + } + + @Test + public void dividendMultipleOfDivisor() { + String input = "(rem 20 5)"; + + assertSExpressionsMatch(new LispNumber("0"), evaluateString(input)); + } + + @Test + public void divisorOfOne() { + String input = "(rem 5 1)"; + + assertSExpressionsMatch(new LispNumber("0"), evaluateString(input)); + } + + @Test + public void dividendOfZero() { + String input = "(rem 0 2309)"; + + assertSExpressionsMatch(new LispNumber("0"), evaluateString(input)); + } + + @Test + public void negativeDividend() { + String input = "(rem -23 25)"; + + assertSExpressionsMatch(new LispNumber("-23"), evaluateString(input)); + } + + public void negativeDivisor() { + String input = "(rem 5 -11)"; + + assertSExpressionsMatch(new LispNumber("0"), evaluateString(input)); + } + + @Test(expected = DivideByZeroException.class) + public void divisorOfZero() { + evaluateString("(rem 5 0)"); + } + + @Test(expected = BadArgumentTypeException.class) + public void remWithNonNumber() { + evaluateString("(rem 'a 'b)"); + } + + @Test(expected = TooFewArgumentsException.class) + public void remWithTooFewArguments() { + evaluateString("(rem 1)"); + } + + @Test(expected = TooManyArgumentsException.class) + public void remWithTooManyArguments() { + evaluateString("(rem 1 2 3)"); + } +}