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

时间:2014-11-28 04:11:22

标签: java arrays int

我的代码尝试将算法实现为

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

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

  • 添加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 <= '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[] 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);
    }
}

3 个答案:

答案 0 :(得分:1)

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

如果从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" : "");
}

答案 1 :(得分:1)

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

  • Meaninfgul班级名称
  • 有意义的方法和参数名称
  • 将重复且经常使用的常量(如50)和数字1的数组表示(否定所需)转换为静态最终成员,以获得干净的代码原因(文档,在一个地方轻松更改,有意义名称),运行时优化)。
  • 扩展代码以允许负整数作为操作数
  • 为用户输入添加了验证模式。例如。现在检查最大数字长度以避免阵列溢出。
  • 通过使数组大于用户输入允许的最大位数来避免数值溢出(参见源代码注释)
  • 为操作数和操作员输入添加带错误处理的重试循环,将控制台处理提取到一个参数化方法中。
  • 通过删除不必要的检查来简化代码,因为用户输入在将其转换为int[]之前已经过验证。
  • 使调试输出可选
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);
    }
}

答案 2 :(得分:-1)

解决问题后的代码。谢谢@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);
    
  }
}