diff --git a/.classpath b/.classpath
index 168af0d..debb9c3 100644
--- a/.classpath
+++ b/.classpath
@@ -13,9 +13,8 @@
-
+
-
diff --git a/mdbook/src/Chapters/CalculatorCommands.md b/mdbook/src/Chapters/CalculatorCommands.md
index bfd6992..56cae67 100644
--- a/mdbook/src/Chapters/CalculatorCommands.md
+++ b/mdbook/src/Chapters/CalculatorCommands.md
@@ -21,7 +21,7 @@ These commands, like the others you'll read about later, are executed by typing
|fact
factorial| **FACTORIAL**
Takes the factorial of `line1`. The factorial target number must be an integer, so if there is a decimal component, it will be dropped (not rounded) as with the `int` command|
|f
flip | **FLIP SIGN**
Flip the sign on the top stack item (`line1`). This is effectively multiplying `line1` by `-1`|
|int| **INTEGER**
Converts the top stack item (`line1`) to it's integer value. This will discard the decimal portion regardless of it's value. For example: `4.34` will result in `4` and `4.999` will also result in `4`. If rounding is desired, execute the `round` command prior to `int` (or create a user defined function)|
-|lr| **SIMPLE LINEAR REGRESSION**
[Linear regression](https://www.graphpad.com/guides/the-ultimate-guide-to-linear-regression) is used to model the relationship between two variables and create a line that can be used to estimate other values using a line-of-best-fit method. This implementation is for simple linear regression and will show you the formula, slope, y-intercept as well as add the next expected value to the top of the stack.
The values will be plotted from the bottom of the stack to the top (`line1`)(which is probably want you want). If you need it the other way around, simply reverse the stack with the `reverse` or `rev` command prior to executing `lr`|
+|lr [add]
lr [x]| **SIMPLE LINEAR REGRESSION**
[Linear regression](https://www.graphpad.com/guides/the-ultimate-guide-to-linear-regression) is used to model the relationship between two variables and create a line that can be used to estimate other values using a line-of-best-fit method. This implementation is for simple linear regression, and will display the formula, slope, y-intercept as well as add the next expected value to the top of the stack.
If `add` (or just `a`) is entered, the next predicted value will be added to the top of the stack (`line1`). If a number is provided (`x`), the predicted `y` value will be displayed. The `y` value is the result of the linear extrapolation at the `x` value. If both are added, the y value at the x location will be both calculated and added to the top of the stack (`line1`)
The values will be plotted from the bottom of the stack to the top (`line1`)(which is probably want you want). If you need it the other way around, simply reverse the stack with the `reverse` or `rev` command prior to executing `lr`|
|log|**LOGARITHM BASE e**
Calculates the [natural logarithm (base e)](https://en.wikipedia.org/wiki/Natural_logarithm). Please note that these are calculated as a `double` and therefore do not have unlimited precision|
|log10|**LOGARITHM BASE 10**
Calculates the [base10 logarithm](https://en.wikipedia.org/wiki/Common_logarithm). Please note that these are calculated as a `double` and therefore do not have unlimited precision|
|max|**MAXIMUM VALUE**
Copies the largest value in the top of the stack (`line1`)|
diff --git a/pom.xml b/pom.xml
index 16d75f5..328c2d1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
org.fross
rpncalc
- 5.1.7
+ 5.1.8
jar
rpncalc
@@ -64,7 +64,7 @@
org.apache.maven.plugins
maven-compiler-plugin
- 3.11.0
+ 3.12.1
${maven.compiler.release}
@@ -77,7 +77,7 @@
org.apache.maven.plugins
maven-surefire-plugin
- 3.1.0
+ 3.2.5
@@ -87,7 +87,7 @@
org.apache.maven.plugins
maven-shade-plugin
- 3.4.1
+ 3.5.1
package
@@ -182,7 +182,7 @@
org.codehaus.mojo
exec-maven-plugin
- 3.1.0
+ 3.1.1
chmod
@@ -240,7 +240,7 @@
org.fross
library
- 2023.12.03
+ 2024.01.22
@@ -255,7 +255,7 @@
org.jline
jline-reader
- 3.25.0
+ 3.25.1
@@ -263,7 +263,7 @@
org.jline
jline-terminal-jansi
- 3.25.0
+ 3.25.1
diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml
index 186664b..262ba18 100644
--- a/snap/snapcraft.yaml
+++ b/snap/snapcraft.yaml
@@ -1,5 +1,5 @@
name: rpncalc
-version: '5.1.7'
+version: '5.1.8'
summary: The command line Reverse Polish Notation (RPN) calculator
description: |
RPNCalc is an easy to use command line based Reverse Polish
@@ -50,7 +50,7 @@ parts:
plugin: maven
source: https://github.com/frossm/library.git
source-type: git
- source-tag: 'v2023.12.03'
+ source-tag: 'v2024.01.22'
maven-parameters:
- install
diff --git a/src/main/java/org/fross/rpncalc/CommandParser.java b/src/main/java/org/fross/rpncalc/CommandParser.java
index 251a4a7..599ab3f 100644
--- a/src/main/java/org/fross/rpncalc/CommandParser.java
+++ b/src/main/java/org/fross/rpncalc/CommandParser.java
@@ -163,7 +163,7 @@ public static void Parse(StackObj calcStack, StackObj calcStack2, String cmdInpu
// Linear Regression
case "lr":
- StackCommands.cmdLinearRegression(calcStack);
+ StackCommands.cmdLinearRegression(calcStack, cmdInputParam);
break;
// Absolute Value
diff --git a/src/main/java/org/fross/rpncalc/Help.java b/src/main/java/org/fross/rpncalc/Help.java
index 37cae9d..0cf1056 100644
--- a/src/main/java/org/fross/rpncalc/Help.java
+++ b/src/main/java/org/fross/rpncalc/Help.java
@@ -81,7 +81,7 @@ public static void Display() {
Output.printColorln(Ansi.Color.WHITE, " fact Take a factorial of line1. Decimals will be dropped");
Output.printColorln(Ansi.Color.WHITE, " f Flip the sign of the element at line1");
Output.printColorln(Ansi.Color.WHITE, " int Convert line1 to an integer. No rounding is performed");
- Output.printColorln(Ansi.Color.WHITE, " lr Simple Linear regression. Calculate the next predicted value");
+ Output.printColorln(Ansi.Color.WHITE, " lr [add] [x] Linear Regress. 'add' will add next value. x adds the y value at that x");
Output.printColorln(Ansi.Color.WHITE, " log | log10 Calculate the natural (base e) or base10 logarithm");
Output.printColorln(Ansi.Color.WHITE, " min | max Add the minimum or maximum stack value to the stack");
Output.printColorln(Ansi.Color.WHITE, " median [keep] Replace stack with median value. 'keep' will retain stack");
diff --git a/src/main/java/org/fross/rpncalc/StackCommands.java b/src/main/java/org/fross/rpncalc/StackCommands.java
index 85ed5af..674f266 100644
--- a/src/main/java/org/fross/rpncalc/StackCommands.java
+++ b/src/main/java/org/fross/rpncalc/StackCommands.java
@@ -406,13 +406,40 @@ public static void cmdInteger(StackObj calcStack) {
*
* @param calcStack
*/
- public static void cmdLinearRegression(StackObj calcStack) {
+ public static void cmdLinearRegression(StackObj calcStack, String args) {
+ boolean argAdd = false;
+ BigDecimal argX = new BigDecimal(calcStack.size());
+
// Ensure we have at least 2 values on the stack
if (calcStack.size() < 2) {
Output.printColorln(Ansi.Color.RED, "Error: There must be at least two items on the stack to calculate a linear regression");
return;
}
+ // Process the arguments
+ try {
+ // If any arguments were supplied
+ if (!args.isEmpty()) {
+ // Loop through each option and process it
+ for (String a : args.split("\\s")) {
+ // Look for a string that starts with 'a'
+ if (a.toLowerCase().startsWith("a")) {
+ argAdd = true;
+ Output.debugPrintln("Setting LR ADD flag");
+ continue;
+ } else {
+ argX = new BigDecimal(a).subtract(BigDecimal.ONE);
+ Output.debugPrintln("Setting LR 'x' value to : " + argX.toString());
+ continue;
+ }
+ }
+ }
+
+ } catch (Exception ex) {
+ Output.printColorln(Ansi.Color.RED, "ERROR: Acceptable linear regression options are 'add' or a number");
+ return;
+ }
+
// X is the number of stack items
BigDecimal n = new BigDecimal(String.valueOf(calcStack.size()));
BigDecimal sumX = BigDecimal.ZERO; // X values are the stack numbers
@@ -464,17 +491,18 @@ public static void cmdLinearRegression(StackObj calcStack) {
BigDecimal b = b_top.divide(b_bottom, MathContext.DECIMAL128);
// Output details if debug is enabled
- Output.debugPrintln("n: " + n.toPlainString());
- Output.debugPrintln("sumX: " + sumX.toPlainString());
- Output.debugPrintln("sumY: " + sumY.toPlainString());
- Output.debugPrintln("sumXY: " + sumXY.toPlainString());
- Output.debugPrintln("sumX2: " + sumX2.toPlainString());
- Output.debugPrintln("sumY2: " + sumY2.toPlainString());
- Output.debugPrintln("a: " + a.toPlainString());
- Output.debugPrintln("b: " + b.toPlainString());
+ Output.debugPrintln("n: " + n.toPlainString());
+ Output.debugPrintln("sumX: " + sumX.toPlainString());
+ Output.debugPrintln("sumY: " + sumY.toPlainString());
+ Output.debugPrintln("sumXY: " + sumXY.toPlainString());
+ Output.debugPrintln("sumX2: " + sumX2.toPlainString());
+ Output.debugPrintln("sumY2: " + sumY2.toPlainString());
+ Output.debugPrintln("a: " + a.toPlainString());
+ Output.debugPrintln("b: " + b.toPlainString());
+ Output.debugPrintln("NextValue: " + argX.toPlainString() + " (one less than displayed)");
// Rounded values are just for the display
- BigDecimal nextValue = a.add(b.multiply(n.add(BigDecimal.ONE)));
+ BigDecimal nextValue = a.add(b.multiply(argX.add(BigDecimal.ONE)));
BigDecimal aRounded = a.setScale(4, RoundingMode.HALF_UP);
BigDecimal bRounded = b.setScale(4, RoundingMode.HALF_UP);
BigDecimal nextValueRounded = nextValue.setScale(4, RoundingMode.HALF_UP);
@@ -482,13 +510,15 @@ public static void cmdLinearRegression(StackObj calcStack) {
// Display the LR formula
Output.printColorln(Ansi.Color.CYAN, "Slope Equation: y = " + bRounded + "x + " + aRounded);
Output.printColorln(Ansi.Color.CYAN, "Slope: " + bRounded + " Y-Intercept: " + aRounded);
- Output.printColorln(Ansi.Color.CYAN, "Predicted next value (" + nextValueRounded + ") added to the top of the stack");
-
- // Save current calcStack to the undoStack
- calcStack.saveUndo();
+ Output.printColorln(Ansi.Color.CYAN, "Predicted value at x = " + argX.add(BigDecimal.ONE) + ": " + nextValueRounded);
- // Add the next predicted value to the stack
- calcStack.push(nextValue);
+ // Add the next predicted value to the stack if 'add' was selected
+ if (argAdd) {
+ // Save current calcStack to the undoStack
+ calcStack.saveUndo();
+
+ calcStack.push(nextValue);
+ }
}
diff --git a/src/test/java/org/fross/rpncalc/StackCommandsTest.java b/src/test/java/org/fross/rpncalc/StackCommandsTest.java
index d459e1e..8c8f50b 100644
--- a/src/test/java/org/fross/rpncalc/StackCommandsTest.java
+++ b/src/test/java/org/fross/rpncalc/StackCommandsTest.java
@@ -570,7 +570,7 @@ void testCmdInteger() {
/**
* Testing the linear regression results
- *
+ * Reference for testing: https://www.socscistatistics.com/tests/regression/default.aspx
*/
@Test
void testCmdLinearRegression() {
@@ -584,7 +584,7 @@ void testCmdLinearRegression() {
stk.push(20.00);
stk.push(10.00);
stk.push(35.00);
- StackCommands.cmdLinearRegression(stk);
+ StackCommands.cmdLinearRegression(stk, "a");
StackCommands.cmdRound(stk, "4");
assertEquals(8, stk.size());
assertEquals(27.7143, stk.pop().doubleValue());
@@ -601,7 +601,7 @@ void testCmdLinearRegression() {
stk.push(11.11);
stk.push(22.22);
stk.push(3.0);
- StackCommands.cmdLinearRegression(stk);
+ StackCommands.cmdLinearRegression(stk, "a");
StackCommands.cmdRound(stk, "6");
assertEquals(11, stk.size());
assertEquals(16.671333, stk.pop().doubleValue());
@@ -618,7 +618,7 @@ void testCmdLinearRegression() {
stk.push(-34.88);
stk.push(40.99);
stk.push(3.00);
- StackCommands.cmdLinearRegression(stk);
+ StackCommands.cmdLinearRegression(stk, "a");
StackCommands.cmdRound(stk, "6");
assertEquals(11, stk.size());
assertEquals(4.271333, stk.pop().doubleValue());
@@ -629,7 +629,7 @@ void testCmdLinearRegression() {
for (int i = 0; i < testValues.length; i++) {
stk.push(testValues[i]);
}
- StackCommands.cmdLinearRegression(stk);
+ StackCommands.cmdLinearRegression(stk, "a");
StackCommands.cmdRound(stk, "7");
assertEquals(48.9842105, stk.pop().doubleValue());
@@ -639,7 +639,7 @@ void testCmdLinearRegression() {
for (int i = 0; i < testValues1.length; i++) {
stk.push(testValues1[i]);
}
- StackCommands.cmdLinearRegression(stk);
+ StackCommands.cmdLinearRegression(stk, "a");
StackCommands.cmdRound(stk, "9");
assertEquals(17, stk.size());
assertEquals(-9.101980055, stk.pop().doubleValue());
@@ -652,10 +652,45 @@ void testCmdLinearRegression() {
stk.push(testValues2[i]);
}
assertEquals(12, stk.size());
- StackCommands.cmdLinearRegression(stk);
+ StackCommands.cmdLinearRegression(stk, "a");
StackCommands.cmdRound(stk, "9");
assertEquals("47498562223075895424.242424242", stk.peek().toEngineeringString());
assertEquals(13, stk.size());
+
+ // Test #7 - Custom X values
+ stk.clear();
+ Double[] testValues3 = { 29.0, 41.0, 8.0, 18.0, 22.0, 99.0, 32.0, 15.0, 31.0, 3.0, 72.0, 12.0, 60.0, 32.0, 54.0, 45.0, 34.0, 76.0, 5.0, 67.0 };
+ for (int i = 0; i < testValues3.length; i++) {
+ stk.push(testValues3[i]);
+ }
+ StackCommands.cmdLinearRegression(stk, "30 a");
+ StackCommands.cmdRound(stk, "4");
+ assertEquals(58.6135, stk.pop().doubleValue());
+ assertEquals(20, stk.size());
+
+ // Test #8 - Custom X values
+ stk.clear();
+ Double[] testValues4 = { 19.0, 41.0, 8.0, 18.0, 12.0, -99.0, 32.0, 15.0, 31.0, 3.0, 72.0, 12.0, 60.0, 32.0, 54.0, 45.0, 34.0, 76.0, 5.0, 67.0 };
+ for (int i = 0; i < testValues4.length; i++) {
+ stk.push(testValues4[i]);
+ }
+ StackCommands.cmdLinearRegression(stk, "22 a");
+ StackCommands.cmdRound(stk, "4");
+ assertEquals(57.1564, stk.pop().doubleValue());
+ assertEquals(20, stk.size());
+
+ // Test #9 - Custom X values
+ stk.clear();
+ Double[] testValues5 = { 29.0, 41.0, 8.0, 18.0, 22.0, -99.0, 32.0, 15.0, 31.0, 3.0, 72.0, 12.0, -60.0, 32.0, 54.0, 45.0, 14.0, 76.0, 5.0, 44.0 };
+ for (int i = 0; i < testValues5.length; i++) {
+ stk.push(testValues5[i]);
+ }
+ StackCommands.cmdLinearRegression(stk, "45 a");
+ StackCommands.cmdRound(stk, "4");
+ assertEquals(69.1932, stk.pop().doubleValue());
+ assertEquals(20, stk.size());
+
+
}
/**