diff --git a/.~lock.rcalc-doc.odt# b/.~lock.rcalc-doc.odt# new file mode 100644 index 0000000..7f0f6da --- /dev/null +++ b/.~lock.rcalc-doc.odt# @@ -0,0 +1 @@ +,ondra,Penguin,29.09.2013 21:06,file:///home/ondra/.config/libreoffice/4; \ No newline at end of file diff --git a/rcalc-doc.odt b/rcalc-doc.odt index 55ee14a..a8bfb43 100644 Binary files a/rcalc-doc.odt and b/rcalc-doc.odt differ diff --git a/src/net/mightypork/semestralka/CalculatorBatch.java b/src/net/mightypork/calculator/CalculatorBatch.java similarity index 97% rename from src/net/mightypork/semestralka/CalculatorBatch.java rename to src/net/mightypork/calculator/CalculatorBatch.java index 9e32f9d..0b1f756 100644 --- a/src/net/mightypork/semestralka/CalculatorBatch.java +++ b/src/net/mightypork/calculator/CalculatorBatch.java @@ -1,4 +1,4 @@ -package net.mightypork.semestralka; +package net.mightypork.calculator; import java.io.File; @@ -19,7 +19,7 @@ import net.mightypork.rcalc.numbers.Fraction; */ public class CalculatorBatch implements Runnable { - /** Rcalc Session used by the calculator */ + /** RCalc Session used by the calculator */ private RCalcSession session = new RCalcSession(); /** File to load the expressions from */ diff --git a/src/net/mightypork/semestralka/CalculatorInteractive.java b/src/net/mightypork/calculator/CalculatorInteractive.java similarity index 93% rename from src/net/mightypork/semestralka/CalculatorInteractive.java rename to src/net/mightypork/calculator/CalculatorInteractive.java index 6bd82c8..4c74cf9 100644 --- a/src/net/mightypork/semestralka/CalculatorInteractive.java +++ b/src/net/mightypork/calculator/CalculatorInteractive.java @@ -1,4 +1,4 @@ -package net.mightypork.semestralka; +package net.mightypork.calculator; import java.io.File; @@ -17,7 +17,7 @@ import net.mightypork.rcalc.numbers.Fraction; */ public class CalculatorInteractive implements Runnable { - /** Rcalc Session used by the calculator */ + /** RCalc Session used by the calculator */ private RCalcSession session = new RCalcSession(); /** Show results as fractions */ @@ -42,17 +42,18 @@ public class CalculatorInteractive implements Runnable { + "Commands:\n" + "\thelp - show this help\n" + "\texit - quit the calculator\n" - + "\tdebug - toggle debug mode (default off)\n" + "\tdecimal - toggle decimal/fractional output\n" + "\tvars - print a list of variables\n" + + "\tdebug - toggle debug mode (default off)\n" + + "\tutest - perform RCalc unit tests\n" + "\tload filename - execute commands from a file\n" + "\t\t(Expressions from the file can use/change variables)\n" + "\n" + "Mathematical operations, syntax\n" + "\tSupported: + - * / % ^ ! ( )\n" + "\tMultiplication sign can be omitted where it makes sense.\n" - + "\tAlong with fractions, decimal-point format works too.\n" + "\tUse 'a/b' syntax to express a fraction.\n" + + "\tDecimal-point numbers are supported, too.\n" + "\n" + "Variables\n" + "\tAssign a variable:\n" @@ -91,7 +92,7 @@ public class CalculatorInteractive implements Runnable { while (!sc.hasNextLine()) {} String expr = sc.nextLine().toLowerCase().trim(); - + if (expr.equals("%")) { // repeat last expression if (history.size() > 0) { expr = history.get(history.size() - 1); @@ -101,7 +102,10 @@ public class CalculatorInteractive implements Runnable { continue; } } - + + + // can't use a switch on strings because of java 6 :( + if (expr.equals("exit")) { // quit System.out.println("Exit."); return; @@ -109,6 +113,10 @@ public class CalculatorInteractive implements Runnable { } else if (expr.equals("help")) { // show help System.out.println(helpMessage); + } else if (expr.equals("utest")) { // show help + Runnable r = new Tests(); + r.run(); + } else if (expr.equals("debug")) { // toggle debug mode if (session.isDebug()) { diff --git a/src/net/mightypork/semestralka/Main.java b/src/net/mightypork/calculator/Main.java similarity index 93% rename from src/net/mightypork/semestralka/Main.java rename to src/net/mightypork/calculator/Main.java index b5069be..7dd5967 100644 --- a/src/net/mightypork/semestralka/Main.java +++ b/src/net/mightypork/calculator/Main.java @@ -1,4 +1,4 @@ -package net.mightypork.semestralka; +package net.mightypork.calculator; import java.io.File; diff --git a/src/net/mightypork/semestralka/Tests.java b/src/net/mightypork/calculator/Tests.java similarity index 63% rename from src/net/mightypork/semestralka/Tests.java rename to src/net/mightypork/calculator/Tests.java index b852435..2080c36 100644 --- a/src/net/mightypork/semestralka/Tests.java +++ b/src/net/mightypork/calculator/Tests.java @@ -1,4 +1,4 @@ -package net.mightypork.semestralka; +package net.mightypork.calculator; import net.mightypork.rcalc.RCalc; @@ -9,13 +9,15 @@ import net.mightypork.rcalc.RCalc; * * @author Ondrej Hruska */ -public class Tests { +public class Tests implements Runnable { /** * Run the tests */ - public static void run() { + @Override + public void run() { + System.out.println("--- RCalc Unit Tests ---"); RCalc rc = new RCalc(); rc.setDebug(true); @@ -27,22 +29,18 @@ public class Tests { "(1-1)(1--1)(1---1)(1----1)(1--+-+-+++--+-+1)(1--+-+-+-+-----1)(5*-1)", // minus, plus "-(15/2)+(72*43-2)-(12+1)", // minus with parentheses "+34-(--8+2*+13)", // + at beginning of scope - // misc - "23%(6/5)", - "53/(5-4-1)", - "100!", - "24/4/3", - "(10+1)(15-3)", - "13(55-3/12)^2", - "(1/2)^-2", - "13^(1/2)", // should fail - "(1/2)*(3/4)", + "1000!", // big factorial + "24/4/3", // chained division must go LTR + "5-4-1", // subtraction must go LTR + "5(10+1)(4!3)", // implicit multiplication + "(1/2)^-2", // inverting a fraction "(1/2)/(3/4)", // compound fraction + "(1/2)*(3/4)", // fraction multiplication }; //@formatter:on for (String expr : testCases) { - System.out.println("\n\n###### test case begin ######"); + System.out.println("\n\n# Test Case #"); try { System.out.println("IN: " + expr); @@ -52,5 +50,7 @@ public class Tests { } } + System.out.println("--- Unit Tests End ---"); + } } diff --git a/src/net/mightypork/rcalc/Tokenizer.java b/src/net/mightypork/rcalc/Tokenizer.java index bc1d69d..17646ce 100644 --- a/src/net/mightypork/rcalc/Tokenizer.java +++ b/src/net/mightypork/rcalc/Tokenizer.java @@ -1,7 +1,6 @@ package net.mightypork.rcalc; -import java.math.BigInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -109,11 +108,11 @@ public class Tokenizer implements IDebugable { if (debug && deepDebug) System.out.println("\nNormalize sequences of '+' and '-'\n" + input); // turn '-' to '+-' between numbers - input = input.replaceAll("(?<=[0-9)!])-(?=[0-9])", "+-"); + input = input.replaceAll("(?<=[0-9)!])-(?=[0-9.])", "+-"); if (debug && deepDebug) System.out.println("\n'-' to '+-' between numbers\n" + input); // convert '-' to '+-1*' in front of non-numbers - input = input.replaceAll("-(?=[^0-9])", "+-1*"); + input = input.replaceAll("-(?=[^0-9.])", "+-1*"); if (debug && deepDebug) System.out.println("\n'-' to '+-1*' in front of non-numbers\n" + input); // discard useless + signs diff --git a/src/net/mightypork/rcalc/numbers/Fraction.java b/src/net/mightypork/rcalc/numbers/Fraction.java index 9c53326..68d10bb 100644 --- a/src/net/mightypork/rcalc/numbers/Fraction.java +++ b/src/net/mightypork/rcalc/numbers/Fraction.java @@ -94,16 +94,29 @@ public class Fraction implements IEvaluableToken { } + /** + * Create a fraction with numerator parsed from a string, and 1 as + * denominator. + * + * @param number numerator as string + */ public Fraction(String number) { - if(number.contains(".")) { + + if (number.matches("[.][0-9]+")) { + number = "0" + number; + } + + if (number.matches("-[.][0-9]+")) { + number = "-0" + number.substring(1); + } + + if (number.matches("-?[0-9]+[.][0-9]+")) { String[] parts = number.split("[.]"); - try{ - if(parts.length != 2) throw new ParseError(""); // for the catch - this.numerator = new BigInteger(parts[0]+parts[1]); + try { + this.numerator = new BigInteger(parts[0] + parts[1]); this.denominator = BigInteger.valueOf(10).pow(parts[1].length()); this.simplify_ip(); - }catch(Exception e) { - e.printStackTrace(); + } catch (Exception e) { throw new ParseError("Invalid number format."); } } else { @@ -270,13 +283,13 @@ public class Fraction implements IEvaluableToken { return new Fraction(numerator.divide(gcd), denominator.divide(gcd)); } - /** * Simplify the fraction (in place) */ private void simplify_ip() { + BigInteger gcd = numerator.gcd(denominator); numerator = numerator.divide(gcd);