修复Calculator.conversion方法计算包含%连接一元运算符的计算表达式的结果时逻辑缺陷(pr#4191@Github)

This commit is contained in:
Looly
2025-12-27 13:21:30 +08:00
parent c5c2f203f1
commit 497eb125d8
2 changed files with 48 additions and 7 deletions

View File

@@ -116,7 +116,8 @@ public class Calculator {
count++;
}
}
if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
//新增防止数组越界
if (count > 1 || (count == 1 && currentIndex < arr.length && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
postfixStack.push(new String(arr, currentIndex, count));
}
@@ -165,12 +166,20 @@ public class Calculator {
* @return 结果
*/
private BigDecimal calculate(final String firstValue, final String secondValue, final char currentOp) {
final BigDecimal first = NumberUtil.toBigDecimal(firstValue);
final BigDecimal second = NumberUtil.toBigDecimal(secondValue);
//添加除零检查并提供明确错误信息
if ((currentOp == '/' || currentOp == '%') && second.compareTo(BigDecimal.ZERO) == 0) {
throw new ArithmeticException("Division by zero: cannot divide " + firstValue + " by zero");
}
return switch (currentOp) {
case '+' -> NumberUtil.add(firstValue, secondValue);
case '-' -> NumberUtil.sub(firstValue, secondValue);
case '*' -> NumberUtil.mul(firstValue, secondValue);
case '/' -> NumberUtil.div(firstValue, secondValue);
case '%' -> NumberUtil.toBigDecimal(firstValue).remainder(NumberUtil.toBigDecimal(secondValue));
case '+' -> NumberUtil.add(first, second);
case '-' -> NumberUtil.sub(first, second);
case '*' -> NumberUtil.mul(first, second);
case '/' -> NumberUtil.div(first, second);
case '%' -> first.remainder(second);
default -> throw new IllegalStateException("Unexpected value: " + currentOp);
};
}
@@ -260,6 +269,6 @@ public class Calculator {
* 判断给定位置前一个非空字符是否为运算符或左括号(用于判定是否为一元上下文)
*/
private static boolean isPrevCharOperatorOrLeftParen(final char c) {
return c == '+' || c == '-' || c == '*' || c == '/' || c == '(';
return c == '%' || c == '+' || c == '-' || c == '*' || c == '/' || c == '(';
}
}

View File

@@ -113,4 +113,36 @@ public class CalculatorTest {
final double conversion4 = Calculator.conversion("-3");
assertEquals(-3.0, conversion4, 0.001);
}
@Test
public void percentOperatorTest() {
//基础 % 运算
assertEquals(1.0, Calculator.conversion("10 % 3"), 0.001);
// % 运算符后跟连续的一元运算符的情况
assertEquals(1.0, Calculator.conversion("10 % +-3"), 0.001);
assertEquals(1.0, Calculator.conversion("10 % -3"), 0.001);
// 带括号的 % 后一元负号
assertEquals(1.0, Calculator.conversion("10 % (-3)"), 0.001);
// % 与 * / 的优先级测试
assertEquals(2.0, Calculator.conversion("10 * 5 % 3"), 0.001);
assertEquals(1.0, Calculator.conversion("20 / 5 % 3"), 0.001);
//连续 % 运算
assertEquals(2.0, Calculator.conversion("100 % 7 % 3"), 0.001);
// % 与 + - 混合运算
assertEquals(13.0, Calculator.conversion("10 + 15 % 4"), 0.001);
//负数操作数的 % 运算
assertEquals(-1.0, Calculator.conversion("-10 % 3"), 0.001);
// 两个负数的 % 运算
assertEquals(-1.0, Calculator.conversion("-10 % -3"), 0.001);
// 小数的 % 运算
assertEquals(0.9, Calculator.conversion("10.5 % 3.2"), 0.001);
}
}