十进制补码算术实现中的ArrayIndexOutOfBoundsException

我的代码试图实现一个算法

  • 从控制台获取两个整数和操作数+-用户输入
  • 将这些数字逐位存储在int[50] ,以十进制补码格式表示负数,
  • 实现(十进制)逐位加/减操作,
  • 以十进制格式打印结果而不带前导零。

但是,在我目前的实施中,存在两个问题

  • 添加99 + 9999时,打印结果为01098而不是预期的010098。
  • 当减去99 – 9999时,我得到一个ArrayIndexOutOfBoundsException: 50而不是预期的结果-09900。
 import java.util.*; public class Program9 { public static String getOperand() { Scanner scan = new Scanner(System.in); String stringOfInteger; System.out.print("Please enter an integer up to 50 numbers: "); stringOfInteger = scan.nextLine(); return stringOfInteger; } public static int[] convert(String operand) { int[] integer = new int[50]; char ch; int position = operand.length() - 1; for (int i = integer.length - 1; i >= 0; i--) { if (position >= 0) ch = operand.charAt(position--); else ch = 0; if (ch >= '0' && ch = 0; i--) { result[i] = operand1[i] + operand2[i] + carry; if (result[i] / 10 == 1) { result[i] = result[i] % 10; carry = 1; } else carry = 0; } return result; } public static int[] complement(int[] operand) { int[] result = new int[operand.length]; for (int i = operand.length - 1; i >= 0; i--) result[i] = 9 - operand[i]; return result; } public static int[] add1(int[] operand) { int[] result = new int[50]; result[49] = 1; for (int i = result.length - 2; i >= 0; i--) result[i] = 0; return result; } public static int[] negate(int[] operand) { return add(add1(operand), complement(operand)); } public static void print(int[] result, String operation) { if (operation.charAt(0) == '+') System.out.print("The subtotal of the two integer = "); else if (operation.charAt(0) == '-') System.out.print("The substraction of the two integers = "); if (result[0] == 9) { result = negate(result); System.out.print("-"); for (int i = 0; i < result.length; i++) { if (result[i] == 0 && result[i + 1] == 0) continue; else System.out.print(result[i]); } } else for (int i = 0; i < result.length; i++) { if (result[i] == 0 && result[i + 1] == 0) continue; else System.out.print(result[i]); } System.out.println(); } public static void main(String[] args) { Scanner scan = new Scanner(System.in); int[] result = new int[50]; String string1 = getOperand(); String string2 = getOperand(); int[] integer1 = convert(string1); int[] integer2 = convert(string2); String operation; System.out.print("Please enter which operation will be used (+ or -): "); operation = scan.nextLine(); if (operation.charAt(0) == '+') add(integer1, integer2); else if (operation.charAt(0) == '-') integer2 = negate(integer2); result = add(integer1, integer2); System.out.println(Arrays.toString(integer1)); System.out.println(Arrays.toString(integer2)); System.out.println(Arrays.toString(add(integer1, integer2))); print(result, operation); } } 

好的,经过如此多的讨论和你的代码有很多问题我完全修改了原始代码,因为你说你想了解更多。 在其他改进中,我做了以下更改:

  • Meaninfgul类名
  • 有意义的方法和参数名称
  • 将重复且经常使用的常量(如50和数字1的数组表示(否定所需)转换为静态最终成员,以获得干净的代码(文档,在一个地方轻松更改,有意义的名称),运行时优化)。
  • 扩展代码以允许负整数作为操作数
  • 添加了用户输入的validation模式。 例如,现在检查最大数量长度以避免arrays溢出。
  • 通过使数组大于用户输入允许的最大位数,避免数值溢出(参见源代码注释)
  • 添加具有操作数和操作员输入的error handling的重试循环,将控制台处理提取到一个参数化方法中。
  • 通过删除不必要的检查来简化代码,因为用户输入在将其转换为int[]之前已经过validation。
  • 使调试输出可选
 package de.scrum_master.stackoverflow; import java.util.Arrays; import java.util.Scanner; import java.util.regex.Pattern; public class TensComplementArithmetic { // Print debug messages? private static final boolean DEBUG = true; // Maximum length for numbers entered by a user // (number of digits excluding the optional +/- sign) private static final int MAX_NUMBER_LENGTH = 50; // Array must have one additional element for the sign and // one more to avoid overflows when adding big negative numbers private static final int ARRAY_LENGTH = MAX_NUMBER_LENGTH + 2; // Scanner for console input handling private static final Scanner INPUT_SCANNER = new Scanner(System.in); // Regex pattern for positive/negative integer number format verification incl. length check private static final Pattern INTEGER_PATTERN = Pattern.compile("[+-]?[0-9]{1," + MAX_NUMBER_LENGTH + "}"); // Regex pattern for operator verification (currently only "+"/"-" allowed) private static final Pattern OPERATOR_PATTERN = Pattern.compile("[+-]"); // The number 1 is always needed for converting a 9's into a 10's complement // during negation, so we define it as a reusable constant private static final int[] NUMBER_ONE; static { // Initialise constant carrying array representation for number 1 NUMBER_ONE = new int[ARRAY_LENGTH]; NUMBER_ONE[ARRAY_LENGTH - 1] = 1; } public static String readConsoleInput(String prompt, Pattern validationPattern, String errorMessage) { String input = null; while (input == null) { System.out.print(prompt + ": "); if (INPUT_SCANNER.hasNext(validationPattern)) input = INPUT_SCANNER.next(validationPattern); else { INPUT_SCANNER.nextLine(); System.out.println(errorMessage); } } return input; } public static String getOperand(String operandName) { return readConsoleInput( "Operand " + operandName, INTEGER_PATTERN, "Illegal number format, please enter a positive/negative integer of max. " + MAX_NUMBER_LENGTH + " digits." ); } private static String getOperator() { return readConsoleInput( "Arithmetical operator (+ or -)", OPERATOR_PATTERN, "Unknown operator, try again." ); } public static int[] parseInteger(String number) { char sign = number.charAt(0); boolean isNegative = sign == '-' ? true : false; if (isNegative || sign == '+') number = number.substring(1); int[] result = new int[ARRAY_LENGTH]; int parsePosition = number.length() - 1; for (int i = result.length - 1; i >= 0; i--) { if (parsePosition < 0) break; result[i] = number.charAt(parsePosition--) - '0'; } return isNegative ? negate(result) : result; } public static int[] add(int[] operand1, int[] operand2) { int[] result = new int[ARRAY_LENGTH]; int carry = 0; for (int i = ARRAY_LENGTH - 1; i >= 0; i--) { result[i] = operand1[i] + operand2[i] + carry; if (result[i] >= 10) { result[i] = result[i] % 10; carry = 1; } else carry = 0; } return result; } public static int[] complement(int[] operand) { int[] result = new int[ARRAY_LENGTH]; for (int i = operand.length - 1; i >= 0; i--) result[i] = 9 - operand[i]; return result; } public static int[] negate(int[] operand) { return add(complement(operand), NUMBER_ONE); } public static void print(int[] result, String operation) { System.out.print(operation.charAt(0) == '-' ? "Difference = " : "Sum = "); if (result[0] == 9) { result = negate(result); System.out.print("-"); } boolean leadingZero = true; for (int i = 0; i < result.length; i++) { if (leadingZero) { if (result[i] == 0) continue; leadingZero = false; } System.out.print(result[i]); } System.out.println(leadingZero ? "0" : ""); } public static void main(String[] args) { int[] operand1 = parseInteger(getOperand("#1")); int[] operand2 = parseInteger(getOperand("#2")); String operator = getOperator(); if (operator.equals("-")) operand2 = negate(operand2); int[] result = new int[ARRAY_LENGTH]; result = add(operand1, operand2); if (DEBUG) { System.out.println("Operand #1 = " + Arrays.toString(operand1)); System.out.println("Operand #2 = " + Arrays.toString(operand2)); System.out.println("Result = " + Arrays.toString(result)); } print(result, operator); } } 

免责声明:您的源代码存在多个问题,但为了保持简单,我现在将忽略其中的大多数问题,并且只解释当前问题的原因并仅为它们提出修复建议。

如果从main方法检查数组输出,您会看到加法/减法结果看起来很好,即问题不在计算例程中,而是在打印例程中。 你有

  • 重复代码:打印正/负数的for循环是相同的。
  • 美容问题:始终打印一个前导零。
  • 逻辑错误:检查两个连续的零,以确定前导零结束的位置和实际数字的开始位置。 但你忘记了
    • 在一个数字内,也可以有重复的零,例如在10098或-9900之内。 这解释了为什么10098打印为1098:您正在抑制打印的第一个零点。
    • 如果最后一个数组元素中存在零(例如9900),则无法检查(不存在的)后续元素而不会导致ArrayIndexOutOfBoundsException 。 这解释了为什么你得到-9900的例外。

现在你能做什么/应该做什么?

  • 消除冗余for循环。 您可以使用相同的循环来打印正数和负数。
  • 使用boolean标志,以便记住您是否仍然循环通过前导零。

您可以像这样更改打印方法:

 public static void print(int[] result, String operation) { System.out.print(operation.charAt(0) == '-' ? "Difference = " : "Sum = "); if (result[0] == 9) { result = negate(result); System.out.print("-"); } boolean leadingZero = true; for (int i = 0; i < result.length; i++) { if (leadingZero) { if (result[i] == 0) continue; leadingZero = false; } System.out.print(result[i]); } System.out.println(leadingZero ? "0" : ""); } 

修复问题后的代码。 谢谢@kriegaex!

 import java.util.*; public class Program9 { public static String getOperand() { Scanner scan = new Scanner(System.in); String stringOfInteger; System.out.print("Please enter an integer up to 50 numbers: "); stringOfInteger = scan.nextLine(); return stringOfInteger; } public static int[] convert(String operand) { int [] integer = new int[50]; char ch; int position = operand.length() - 1; for (int i = integer.length - 1; i >= 0; i--) { if (position >= 0) ch = operand.charAt(position--); else ch = 0; if (ch >= '0' && ch <= '9') { integer[i] = ch - '0'; } else { integer[i] = 0; } } return integer; } public static int[] add(int[] operand1, int[] operand2) { int [] result = new int[operand1.length]; int carry = 0; for (int i = operand1.length - 1; i >= 0; i--) { result[i] = operand1[i] + operand2[i] + carry; if (result[i] / 10 == 1) { result[i] = result[i] % 10; carry = 1; } else carry = 0; } return result; } public static int[] complement(int[] operand2){ int [] result = new int[operand2.length]; for (int i = operand2.length - 1; i >= 0; i--) result[i] = 9 - operand2[i]; return result; } public static int[] add1(int[] operand2){ int [] result = new int[operand2.length]; result[operand2.length - 1] = 1; for (int i = result.length - 2; i >= 0; i--) result[i] = 0; return result; } public static int[] negate(int[] operand2){ return add(add1(operand2), complement(operand2)); } public static void print(int[] result, String operation) { if (operation.charAt(0) == '+') System.out.print("The subtotal of the two integers = "); else if (operation.charAt(0) == '-') System.out.print("The subtraction of the two integers = "); if (result[0] == 9) { result = negate(result); System.out.print("-"); } boolean leadingZero = true; for (int i = 0; i < result.length; i++) { if (leadingZero) { if (result[i] == 0) continue; leadingZero = false; } System.out.print(result[i]); } if (leadingZero == true) System.out.println('0' - '0'); System.out.println(); } public static void main(String[] args) { Scanner scan = new Scanner(System.in); int [] result = new int[50]; String string1 = getOperand(); String string2 = getOperand(); int [] integer1 = convert(string1); int [] integer2 = convert(string2); String operation; System.out.print("Please enter which operation will be used (+ or -): "); operation = scan.nextLine(); if (operation.charAt(0) == '+') add(integer1, integer2); else if (operation.charAt(0) == '-') integer2 = negate(integer2); result = add(integer1, integer2); System.out.println(Arrays.toString(integer1)); System.out.println(Arrays.toString(integer2)); System.out.println(Arrays.toString(add(integer1, integer2))); print(result, operation); } }