/RPNLibrary

Java Reverse Polish Notation Library

Primary LanguageJava

RPNLibrary

Simple RPN (Reverse Polish Notation) Library for Java.
It is based on Dijkstra Algorithm. (https://en.wikipedia.org/wiki/Reverse_Polish_notation)

Reliability Rating

Maven Central

javadoc

Story

Couple years ago I read Joshua Bloch's "Java. Effective Programming". I wanted to practice what I've learned. I didn't want to create another CRUD like application, so I found that Dijkstra's algorithm would be good to learn design patterns, and effective programming. First version's were available on Sourceforge. Couple years later I manage to publish my library on maven cetral repo. Over the years I built a small ecosystem around this library. Feel free to check my other projects that use this one.

Available functions:

+,-,*,/ with (), power(^) Sin, cos, tg, ctg, min, max, fib

example:

        Calculator calc = Calculator.createCalulator();
        BigDecimal result = calc.calculate("2^3*(12/6)+18/3+5.0/2");
        BigDecimal result2 = calc.calculate("3.678^2");
        BigDecimal resultSin = calc.calculate("sin(2)");
        BigDecimal resultSin2 = calc.calculate("sin(1+1)")
        BigDecimal resultCtg = calc.calculate("ctg(-1.65091)");
        BigDecimal min = calc.calculate("min(10, 8) + 10");

Maven:

        <dependency>
            <groupId>com.github.bartlomiej-gora</groupId>
            <artifactId>RPNLibrary</artifactId>
            <version>5.0.0</version>
        </dependency>

Changelog:

Version 5.0.0:

  • Moved to java 8
  • Refactoring, split Calculator class into smaller pieces, using java 8 functional interfaces
  • Added tests written in Kotest:

example:

class RPNFactoryTest : FreeSpec({

    val tested = RPNFactory(RPNChecker(DefaultStrategyProvider()))
            "should Return RPN" - {
                val text = "( 2 + 3 ) * 5"
                val result = tested.apply(text)
                result shouldBe "2 3 + 5 *"
            }
            "should Return RPN for Function call" - {
                val text = "sin ( 1 )"
                val result = tested.apply(text)
                result shouldBe "1 sin"
            }
            "should Return RPN for Function and equation" - {
                val text = "sin ( 1 ) + 27 * 8"
                val result = tested.apply(text)
                result shouldBe "1 sin 27 8 * +"
            }
            "should Return RPN for  two Functions call" - {
                val text = "sin ( 1 ) + ctg ( 0 )"
                val result = tested.apply(text)
                result shouldBe "1 sin 0 ctg +"
            }
})

Version 4.0.0:

Version 3.2.2:

  • Changed internal calculation from BigDecimal to Double in DefaultCalculator implementation

Version 3.2.1:

  • Fixed bug in divide operator, that caused: ex: "10/4 = 2, and not 2.5", "5/2 = 2, and not 2.5"
  • Changed RoundinMode from HALF_UP, to HALF_EVEN
  • Changed internal calculation type from BigDecimal to Double

Version 3.2.1-SNAPSHOT:

  • Fixed bug in divide operator, that caused: ex: "10/4 = 2, and not 2.5", "5/2 = 2, and not 2.5"
  • Changed RoundinMode from HALF_UP, to HALF_EVEN
  • Changed internal calculation type from BigDecimal to Double

Version 3.2.0:

IMPORTANT:
Changed package names from

    pl.bgora.rpn

to

com.github.bgora.rpnlibrary

Fixed bug, that prevented from exucuting functions with multiple parameters.

New functions:
max() - takes two parameters, returns greater one
min() - take two parameters, returns less one
fib() - Fibonacci number

Refactor:

Changed createCalulator, and getDefaultEngine to use CalculationEngine interface

    /**
     * Creates AdvanceCalculator with given CalculatorEngine
     *
     * @param engine CalculationEngine implementation
     * @return AdvanceCalculator
     */
    public CalculatorInterface createCalulator(CalculationEngine engine) {
        return new AdvancedCalculator(RoundingMode.HALF_UP, engine);
    }


    /**
     * Return default CalculationEngine implementation
     *
     * @return CalculatorEngine
     */
    public CalculationEngine getDefaultEngine() {
        return new CalculatorEngine(StrategiesUtil.DEFAULT_OPERATORS, StrategiesUtil.DEFAULT_FUNCTIONS);
    }

Version 3.1.0:

  • Added package pl.bgora.rpn.advanced
  • Added AdvancedCalculatorFactory

The advanced Calculator works with CalculationEngine, which uses strategy pattern to run. please see:
pl.bgora.rpn.AbstractOperatorStrategy
pl.bgora.rpn.AbstractFunctionStrategy

Example 1:

        AdvancedCalculatorFactory advancedCalculatorFactory = new AdvancedCalculatorFactory();
        calc = advancedCalculatorFactory.createCalulator();

Example 2:

Assume that you want to add a function sqrt(number), which will return The square root , You will have to extend AbstractFunctionStrategy like this:

public class SqrtFunctionStrategy extends AbstractFunctionStrategy {
    public SqrtFunctionStrategy() {
        super("sqrt", 1, RoundingMode.HALF_EVEN);
    }

    @Override
    public BigDecimal execute(String... params) {
        return java.math.BigDecimal.valueOf(Math.sqrt(x));
    }
}

And then you can add your function like that:

        CalculatorInterface calc;
        AdvancedCalculatorFactory advancedCalculatorFactory = new AdvancedCalculatorFactory();
        CalculatorEngine engine = advancedCalculatorFactory.getDefaultEngine();
        engine.addFunctionStartegy(new SqrtFunctionStrategy());
        calc = advancedCalculatorFactory.createCalulator(engine);

Example 3:

Assume that you want to add a function max(number, number), which will return greater value, You will have to extend AbstractFunctionStrategy like this:

public class MaxFunctionStrategy extends AbstractFunctionStrategy {
    public MaxFunctionStrategy() {
        super("max", 2, RoundingMode.HALF_EVEN);
    }

    @Override
    public BigDecimal execute(String... params) {
        String first = params[0];
        String second = params[1];
        BigDecimal result = //do you calculation here
        return result; //result;
    }
}

And then you can add your function like that:

        CalculatorInterface calc;
        AdvancedCalculatorFactory advancedCalculatorFactory = new AdvancedCalculatorFactory();
        CalculatorEngine engine = advancedCalculatorFactory.getDefaultEngine();
        engine.addFunctionStartegy(new MaxFunctionStrategy());
        calc = advancedCalculatorFactory.createCalulator(engine);