ArrayIndexOutOfBoundsException in ten's complement arithmetic implementation

后端 未结 3 1013
被撕碎了的回忆
被撕碎了的回忆 2020-12-20 11:28

My code tries to implement an algorithm to

  • take user input for two integer numbers and an operand + or - from the console,
  • s
相关标签:
3条回答
  • 2020-12-20 12:22

    The code after fixing the problems. all thanks to @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);
        
      }
    }

    0 讨论(0)
  • 2020-12-20 12:27

    Disclaimer: Your source code has multiple problems, but in order to keep it simple I am going to ignore most of them now and will just explain the reasons for your current problems and suggest fixes for them only.

    If you check the array outputs from your main method, you see that the addition/subtraction results look good, i.e. the problem is not located in the calculation routines but in the print routine. There you have

    • duplicate code: The for loops printing the positive/negative numbers are identical.
    • a cosmetic problem: One leading zero is always printed.
    • a logical error: You check for two consecutive zeroes in order to determine where leading zeroes end and the actual number begins. But you forget that
      • within a number there can also be duplicate zeroes, e.g. within 10098 or -9900. This explains why 10098 is printed as 1098: You are suppressing the first zero from being printed.
      • if there is a zero in the last array element (e.g. 9900) you cannot check the (non-existent) subsequent element without causing an ArrayIndexOutOfBoundsException. This explains why you get the exception for -9900.

    Now what can/should you do?

    • Eliminate the redundant for loop. You can use the same loop to print both positive and negative numbers.
    • Use a boolean flag in order to remember if you are still looping through leading zeroes or not.

    You can change your print method like so:

    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" : "");
    }
    
    0 讨论(0)
  • 2020-12-20 12:28

    Okay, after so much discussion and so many issues with your code I have totally revised your original code because you said you wanted to learn more. Among other improvements I have done the following changes:

    • Meaninfgul class name
    • Meaningful method and parameter names
    • Convert repeated and often used constants like 50 and the array representation of the number 1 (needed for negation) into static final members for clean code reasons (documentation, easy change in one place, meaningful names), runtime optimisation).
    • Extend the code to permit negative integers as operands
    • Added validation patterns for user input. E.g. now the maximum number length is checked in order to avoid an array overflow.
    • Avoid numeric overflows during calculation by making the array bigger than the maximum number of digits permitted for user input (see source code comments)
    • Add retry loops with error handling for operand and operator input, extract console handling into one parametrised method.
    • Simplify code by removing unnecessary checks because user input is already validated before converting it into an int[].
    • Make debug output optional
    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题