Skip to content

Commit

Permalink
Added Scientific Notation Capability
Browse files Browse the repository at this point in the history
- Accept SN from the command line
- Updated code to display it correctly
- Lot of tests, although I need to do more tests for all of the commands
  using scientific notation.  I'm sure many commands will break.
- Added additional tests as for currently tests commands
  • Loading branch information
frossm committed May 26, 2023
1 parent 74e994a commit b3727a7
Show file tree
Hide file tree
Showing 12 changed files with 325 additions and 118 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

<groupId>org.fross</groupId>
<artifactId>rpncalc</artifactId>
<version>5.0.0</version>
<version>5.0.1</version>
<packaging>jar</packaging>

<name>rpncalc</name>
Expand Down
2 changes: 1 addition & 1 deletion snap/snapcraft.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: rpncalc
version: '5.0.0'
version: '5.0.1'
summary: The command line Reverse Polish Notation (RPN) calculator
description: |
RPNCalc is an easy to use command line based Reverse Polish
Expand Down
31 changes: 30 additions & 1 deletion src/main/java/org/fross/rpncalc/CommandParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ public static void Parse(StackObj calcStack, StackObj calcStack2, String cmdInpu

// Divide the fraction and get a decimal equivalent
fracDecimalEquiv = fracTop.divide(fracBottom, MathContext.DECIMAL128);

// Overall decimal equivalent (integer + decimal)
BigDecimal endResult = fracInteger.add(fracDecimalEquiv);

Expand All @@ -460,6 +460,35 @@ public static void Parse(StackObj calcStack, StackObj calcStack2, String cmdInpu
break;
}

// Scientific notation number entered
} else if (cmdInputCmd.toLowerCase().contains("e")) {
// Make sure the digits before and after the 'e' are numbers
try {
String[] numberSplit = cmdInputCmd.toLowerCase().trim().replace(" ", "").split("e");
if (Math.isNumeric(numberSplit[0]) && Math.isNumeric(numberSplit[1])) {
// Ensure there is no decimal in the exponent portion
if (numberSplit[1].contains(".")) {
throw new IllegalArgumentException();
}

// Save current calcStack to the undoStack
calcStack.saveUndo();

Output.debugPrint("Adding the scientific notation number '" + cmdInputCmd + "' onto the stack");
calcStack.push(new BigDecimal(cmdInputCmd.toLowerCase()));

} else {
throw new IllegalArgumentException();
}

} catch (ArrayIndexOutOfBoundsException ex) {
Output.printColorln(Ansi.Color.RED, "Illegal Scientific Notation Number Entered: '" + cmdInputCmd + "'");
break;
} catch (IllegalArgumentException ex) {
Output.printColorln(Ansi.Color.RED, "Illegal Scientific Notation Number Entered: '" + cmdInputCmd + "'");
break;
}

// Number entered, add to stack.
} else if (cmdInputCmd.matches("^-?\\d*\\.?\\d*")) {
// Save current calcStack to the undoStack
Expand Down
27 changes: 22 additions & 5 deletions src/main/java/org/fross/rpncalc/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,21 +204,38 @@ public static void main(String[] args) {

// Configure the alignment
if (configAlignment.compareTo("d") == 0) {
int decimalLocation = 0;

// Put in spaces to align the decimals
int decimalLocation = Format.Comma(calcStack.get(i).toPlainString()).indexOf(".");
if (calcStack.get(i).toEngineeringString().toLowerCase().contains("e")) {
stkLineNumber = calcStack.get(i).toEngineeringString();
decimalLocation = stkLineNumber.indexOf(".");

} else {
stkLineNumber = Format.Comma(calcStack.get(i).toEngineeringString());
decimalLocation = stkLineNumber.indexOf(".");
}

// Insert the right number of spaces
for (int k = 0; k < maxDigitsBeforeDecimal - decimalLocation; k++) {
Output.print(" ");
}
stkLineNumber = Format.Comma(calcStack.get(i).toPlainString());

} else if (configAlignment.compareTo("r") == 0) {
stkLineNumber = String.format("%" + maxLenOfNumbers + "s", Format.Comma(calcStack.get(i).toPlainString()));
if (calcStack.get(i).toEngineeringString().toLowerCase().contains("e"))
stkLineNumber = String.format("%" + maxLenOfNumbers + "s", calcStack.get(i).toEngineeringString());
else
stkLineNumber = String.format("%" + maxLenOfNumbers + "s", Format.Comma(calcStack.get(i).toEngineeringString()));

} else {
stkLineNumber = Format.Comma(calcStack.get(i).toPlainString());
if (calcStack.get(i).toEngineeringString().toLowerCase().contains("e"))
stkLineNumber = calcStack.get(i).toEngineeringString();
else
stkLineNumber = Format.Comma(calcStack.get(i).toEngineeringString());
}

// Finally display the current stack item
// Finally display the current stack item after removing any spaces at the end
stkLineNumber = stkLineNumber.replaceAll("\\s+$", "");
Output.printColorln(Ansi.Color.WHITE, stkLineNumber);
}

Expand Down
18 changes: 7 additions & 11 deletions src/main/java/org/fross/rpncalc/Math.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@
*
*/
public class Math {
// Default global match context with unlimited precision
public static final MathContext mc = MathContext.UNLIMITED;

/**
* Parse Take an operand and a stack and call the right math function.
*
Expand Down Expand Up @@ -91,7 +88,7 @@ public static StackObj Parse(String op, StackObj stk) {
public static StackObj Add(StackObj stk) {
BigDecimal b = stk.pop();
BigDecimal a = stk.pop();
BigDecimal result = a.add(b, Math.mc);
BigDecimal result = a.add(b, stk.mc);

Output.debugPrint("Adding: " + a.toString() + " + " + b.toString() + " = " + result.toString());
stk.push(result);
Expand All @@ -107,7 +104,7 @@ public static StackObj Add(StackObj stk) {
public static StackObj Subtract(StackObj stk) {
BigDecimal b = stk.pop();
BigDecimal a = stk.pop();
BigDecimal result = a.subtract(b, Math.mc);
BigDecimal result = a.subtract(b, stk.mc);

Output.debugPrint("Subtracting: " + a.toString() + " - " + b.toString() + " = " + result.toString());
stk.push(result);
Expand All @@ -123,7 +120,7 @@ public static StackObj Subtract(StackObj stk) {
public static StackObj Multiply(StackObj stk) {
BigDecimal b = stk.pop();
BigDecimal a = stk.pop();
BigDecimal result = a.multiply(b, Math.mc);
BigDecimal result = a.multiply(b, stk.mc);

Output.debugPrint("Multiplying: " + a.toString() + " * " + b.toString() + " = " + result.toString());
stk.push(result);
Expand Down Expand Up @@ -169,7 +166,7 @@ public static StackObj Divide(StackObj stk) {
public static StackObj Power(StackObj stk) {
BigDecimal power = stk.pop();
BigDecimal base = stk.pop();
BigDecimal result = base.pow(power.intValue(), Math.mc);
BigDecimal result = base.pow(power.intValue(), stk.mc);

Output.debugPrint(base.toString() + " ^ " + power.toString() + " = " + result.toString());
stk.push(result);
Expand Down Expand Up @@ -221,7 +218,7 @@ public static BigDecimal mean(StackObj stk) {

// Add up the numbers in the stack
for (int i = 0; i < size; i++) {
totalCounter = totalCounter.add(stk.get(i), Math.mc);
totalCounter = totalCounter.add(stk.get(i), stk.mc);
}

// Return the average
Expand Down Expand Up @@ -284,7 +281,7 @@ public static BigDecimal median(StackObj stk) {
int upperIndex = Integer.valueOf(stk.size() / 2 + 1);

Output.debugPrint("Median: UpperIndex=" + upperIndex + " | LowerIndex=" + lowerIndex);
result = (stk.get(lowerIndex - 1).add(stk.get(upperIndex - 1), Math.mc)).divide(new BigDecimal("2"), MathContext.DECIMAL128);
result = (stk.get(lowerIndex - 1).add(stk.get(upperIndex - 1), stk.mc)).divide(new BigDecimal("2"), MathContext.DECIMAL128);

} else {
// Odd number of items
Expand All @@ -311,8 +308,7 @@ public static BigDecimal factorial(int num) {
BigDecimal result = BigDecimal.ONE;

for (int factor = 2; factor <= num; factor++) {
result = result.multiply(new BigDecimal(factor), Math.mc);
}
result = result.multiply(new BigDecimal(factor), MathContext.UNLIMITED); }

return result;
}
Expand Down
34 changes: 8 additions & 26 deletions src/main/java/org/fross/rpncalc/StackCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,6 @@ public static void cmdAbsoluteValue(StackObj calcStack) {
// Pop the stack item and push back the absolute value
calcStack.push(calcStack.pop().abs());

// TODO delete
// Double value = calcStack.pop();
// if (value < 0) {
// calcStack.push(value * -1);
// } else {
// calcStack.push(value);
// }
}

/**
Expand Down Expand Up @@ -366,11 +359,6 @@ public static void cmdInteger(StackObj calcStack) {

calcStack.push(new BigDecimal(calcStack.pop().toBigInteger().toString()));

// TODO: Delete
// String stackItemString = calcStack.pop().toPlainString();
// int stackItemInt = Integer.parseInt(stackItemString.substring(0, stackItemString.indexOf(".")));
// calcStack.push(stackItemInt * 1.0);

} else {
Output.printColorln(Ansi.Color.RED, "ERROR: Must be at least one item on the stack");
}
Expand Down Expand Up @@ -408,13 +396,12 @@ public static void cmdLinearRegression(StackObj calcStack) {
int x = i + 1;
BigDecimal y = calcStack.get(i);

// Calculate the sums
// TODO delete
// sumX += x;
// sumY += y;
// sumXY += x * y;
// sumX2 += x * x;
// sumY2 += y * y;
// Calculate the sums:
// sumX += x;
// sumY += y;
// sumXY += x * y;
// sumX2 += x * x;
// sumY2 += y * y;

// sumX & sumY
sumX = sumX.add(new BigDecimal(String.valueOf(x)));
Expand All @@ -430,8 +417,6 @@ public static void cmdLinearRegression(StackObj calcStack) {
sumY2 = sumY2.add(new BigDecimal(String.valueOf(y)).pow(2));

// Line by line debug output
// TODO delete
// Output.debugPrint("#" + i + ":\tx:" + x + "\ty:" + y + "\tXY:" + (x * y) + "\tX2:" + (x * x) + "\tY2:" + (y * y));
Output.debugPrint(
"#" + i + ":\tx:" + x + "\ty:" + y + "\tXY:" + y.multiply(new BigDecimal(String.valueOf(x))) + "\tX2:" + (x * x) + "\tY2:" + y.pow(2));
}
Expand Down Expand Up @@ -742,7 +727,6 @@ public static void cmdRound(StackObj calcStack, String arg) {
// Round the top of stack item and return that result to the stack
result = calcStack.pop();
result = result.setScale(decimalPlaces, RoundingMode.HALF_UP);
//result = result.round(Math.mc);

// Save current calcStack to the undoStack
calcStack.saveUndo();
Expand Down Expand Up @@ -881,14 +865,12 @@ public static void cmdStdDeviation(StackObj calcStack, String arg) {

// Step2: For each number: subtract the mean from the number and square the result
BigDecimal[] stdArray = new BigDecimal[calcStack.size()];

// Zero out the array
for (int i = 0; i < calcStack.size(); i++)
stdArray[i] = BigDecimal.ZERO;

for (int i = 0; i < calcStack.size(); i++) {
// TODO remove
// stdArray[i] = java.lang.Math.pow((calcStack.get(i) - mean1), 2);
stdArray[i] = calcStack.get(i).subtract(mean1);
stdArray[i] = stdArray[i].pow(2);
}
Expand Down
25 changes: 3 additions & 22 deletions src/main/java/org/fross/rpncalc/StackConversions.java
Original file line number Diff line number Diff line change
Expand Up @@ -112,30 +112,22 @@ public static String[] cmdFraction(StackObj calcStack, String param) {
}

// Determine the integer portion of the number
// TODO delete
// int integerPart = (int) java.lang.Math.floor(startingNumber);
BigInteger integerPart = startingNumber.toBigInteger();

// Determine the fractional portion as an double
BigDecimal decimalPart = startingNumber.subtract(new BigDecimal(integerPart));

// Convert to a fraction with provided base
// This will round to the nearest integer by adding 1/2 to the number and getting it's integer value
// TODO delete
// long numerator = java.lang.Math.round(decimalPart * denominator);
BigDecimal numeratorNotRounded = decimalPart.multiply(new BigDecimal(String.valueOf(denominator)));
BigInteger numerator = numeratorNotRounded.add(new BigDecimal(".5")).toBigInteger();

// Get the Greatest Common Divisor so we can simply the fraction
long gcd = Math.GreatestCommonDivisor(numerator.longValue(), denominator);

Output.debugPrint("Greatest Common Divisor for " + numerator.toString() + " and " + denominator + " is " + gcd);

// Simply the fraction
// TODO delete
// numerator /= gcd;
// denominator /= gcd;

numerator = numerator.divide(new BigInteger(String.valueOf(gcd)));
denominator /= gcd;

Expand All @@ -149,7 +141,8 @@ public static String[] cmdFraction(StackObj calcStack, String param) {
String stackHeader = "-Fraction (Granularity: 1/" + (denominator * gcd) + ")";
outputString[0] = "\n" + stackHeader + "-".repeat(Main.configProgramWidth - stackHeader.length());
if (numerator.compareTo(BigInteger.ZERO) != 0) {
outputString[1] = " " + calcStack.peek().setScale(8, RoundingMode.HALF_UP) + " is approximately '" + integerPart + " " + numerator + "/" + denominator + "'";
outputString[1] = " " + calcStack.peek().setScale(8, RoundingMode.HALF_UP) + " is approximately '" + integerPart + " " + numerator + "/"
+ denominator + "'";
} else {
outputString[1] = " " + calcStack.peek() + " does not have a fractional component with a base of " + (denominator * gcd);
}
Expand All @@ -175,8 +168,6 @@ public static void cmdRad2Deg(StackObj calcStack) {
calcStack.saveUndo();

// Pull the value, convert and push back
// TODO delete
// calcStack.push(calcStack.pop() * (180 / java.lang.Math.PI));
Double conversionFactor = 180 / java.lang.Math.PI;
calcStack.push(calcStack.pop().multiply(new BigDecimal(String.valueOf(conversionFactor))));
}
Expand All @@ -197,8 +188,6 @@ public static void cmdDeg2Rad(StackObj calcStack) {
calcStack.saveUndo();

// Pull the value, convert and push back
// TODO delete
// calcStack.push(calcStack.pop() * (java.lang.Math.PI / 180));
Double conversionFactor = java.lang.Math.PI / 180;
calcStack.push(calcStack.pop().multiply(new BigDecimal(String.valueOf(conversionFactor))));
}
Expand All @@ -221,8 +210,6 @@ public static void cmdGram2Oz(StackObj calcStack) {
calcStack.saveUndo();

// Make the conversion
// TODO delete
// calcStack.push(calcStack.pop() * 0.035274);
calcStack.push(calcStack.pop().multiply(new BigDecimal("0.035274")));
}

Expand All @@ -244,8 +231,6 @@ public static void cmdOz2Gram(StackObj calcStack) {
calcStack.saveUndo();

// Make the conversion
// TODO delete
// calcStack.push(calcStack.pop() * 28.349523125);
calcStack.push(calcStack.pop().multiply(new BigDecimal("28.349523125")));
}

Expand All @@ -267,8 +252,6 @@ public static void cmdKg2Lbs(StackObj calcStack) {
calcStack.saveUndo();

// Make the conversion
// TODO delete
// calcStack.push(calcStack.pop() * 2.2046226218);
calcStack.push(calcStack.pop().multiply(new BigDecimal("2.2046226218")));
}

Expand All @@ -290,8 +273,6 @@ public static void cmdLbs2Kg(StackObj calcStack) {
calcStack.saveUndo();

// Make the conversion
// TODO delete
// calcStack.push(calcStack.pop() * 0.45359237);
calcStack.push(calcStack.pop().multiply(new BigDecimal("0.45359237")));
}
}
Loading

0 comments on commit b3727a7

Please sign in to comment.