微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Java中大数的加减法

如何解决Java中大数的加减法

我有这个任务,我应该在其中添加或减去非常大的数字(很长很长)。我需要使用 String 和/或 StringBuilder 来使其工作。

我这里有一些代码,但大多数情况下都不起作用,而且减法真的有问题。

 /** This class contains the method meant to calculate the sum of two large numbers. 
    */
public class SummingLargeNumbers {

  private SummingLargeNumbers() {}

  private static final char ZERO = '0';

  /**
   * Implements addition of two large numbers.
   *
   * @param s1 First number as string.
   * @param s2 Second number as string.
   * @return The answer as a string.
   */
  static String findSum(String s1,String s2) {
    if (s1 == null || s2 == null || s1.equals("") || s2.equals("")) {
      return "";
    }
    if (s1.length() > s2.length()) {
      String temp = s1;
      s1 = s2;
      s2 = temp;
    }
    StringBuilder result = new StringBuilder();
    int n1 = s1.length();
    int n2 = s2.length();
    int diff = n2 - n1;
    int denom = 0;
    for (int i = n1 - 1; i >= 0; i--) {
      int sum = ((int) (s1.charat(i) - ZERO) + (int) (s2.charat(i + diff) - ZERO) + denom);
      result.append((char) (sum % 10 + ZERO));
      denom = sum / 10;
    }

    for (int i = n2 - n1 - 1; i >= 0; i--) {
      int sum = ((int) (s2.charat(i) - ZERO) + denom);
      result.append((char) (sum % 10 + ZERO));
      denom = sum / 10;
    }

    if (denom > 0) {
      result.append((char) (denom + ZERO));
    }

    return result.reverse().toString();
  }

  /**
   * Checks whether the first number is smaller than the second.
   *
   * @param s1 First number as a string.
   * @param s2 Second number as a string.
   * @return True if the first number is smaller than the second and false if otherwise.
   */
  static boolean isSmaller(String s1,String s2) {
    int firstLength = s1.length();
    int secondLength = s2.length();

    if (firstLength < secondLength) return true;
    if (secondLength < firstLength) return false;

    for (int i = 0; i < firstLength; i++) {
      if (s1.charat(i) < s2.charat(i)) return true;
      else if (s1.charat(i) > s2.charat(i)) return false;
    }
    return false;
  }

  /**
   * Implements subtraction of two large numbers.
   *
   * @param s1 First number as a string.
   * @param s2 Second number as a string.
   * @return The answer as a string.
   */
  static String findDiff(String s1,String s2) {
    if (s1 == null || s2 == null || s1.equals("") || s2.equals("")) {
      return "";
    }
    if (isSmaller(s1,s2)) {
      String temp = s1;
      s1 = s2;
      s2 = temp;
    }

    StringBuilder result = new StringBuilder();

    int n1 = s1.length();
    int n2 = s2.length();
    int diff = n1 - n2;

    int denom = 0;

    for (int i = n2 - 1; i >= 0; i--) {

      int sum =
          (((int) s1.charat(i + diff) - (int) '0') - ((int) s2.charat(i) - (int) '0') - denom);
      if (sum < 0) {
        sum = sum + 10;
        denom = 1;
      } else {
        denom = 0;
      }

      result.append(String.valueOf(sum));
    }

    for (int i = n1 - n2 - 1; i >= 0; i--) {
      if (s1.charat(i) == '0' && denom > 0) {
        result.append("9");
        continue;
      }
      int sub = (((int) s1.charat(i) - (int) '0') - denom);
      if (i > 0 || sub > 0) {
        result.append(String.valueOf(sub));
        denom = 0;
      }
    }
    if (result.reverse().indexOf("0") == 0) {
      result.deleteCharat(0);
    }
    return result.toString();
  }
}

我真的不明白我哪里出错了,现在我还必须将加法和减法实现为一种方法,这对我来说真的很困难。 如果我能对整件事有所了解,我会很高兴,这样我就可以尝试让它发挥作用。

例如一些不起作用的情况是:

-88131415555612 + 77020304444501 = 11111111111111

在这种情况下,它应该返回 -11111111111111

-1021315510 + 2183194 = 1019132316

这里也应该返回-1019132316

大多数与减法有关的情况都是错误的。

解决方法

这看起来是一个有趣的问题,所以我试了一下。这是我最新测试的结果。

123 + 8900 = 9023
123 + 89 = 212
-123 + 893 = 770
-123 + -893 = -1016
123 + -893 = -770
999 + -999 = 0
999 + -997 = 2
-999 + 997 = -2
-88131415555612 + 77020304444501 = -11111111111111
-1021315510 + 2183194 = -1019132316
1021315510 + -2183194 = 1019132316
-1021315510 + -2183194 = -1023498704

我无法理解您的代码。你有太多的静态方法。如果您想知道,过多的静态字段和方法是一件需要避免的坏事。

那么,这就是您解决此类问题的方法。

将问题分解成越来越小的步骤,直到您可以对每个步骤进行编码。

我的意思是:

Sum two String numbers
    Return empty string if either String number is null or empty.
    Determine if the first String has a negative sign.
    Determine if the second string has a negative sign.
    If the signs are the same
        Add numbers.
    Else
        Subtract numbers.

Add numbers
    Determine if the first String has a negative sign.
    Strip signs from both numbers.
    Add numbers,starting from the right and going left.
    Append the carry,if any.
    Append the negative sign,if needed.

Subtract numbers
    Order the numbers by absolute value,largest first,then smallest.
    Determine if the largest String has a negative sign.
    Strip signs from both numbers.
    Subtract the smaller from the larger,starting from the right and going left.
    Append the negative sign,if needed.
    Remove leading zeros.

当然,在您编写代码之后,这会容易得多。

从小处着手。我首先得到了相同的标志。然后我研究了相反的符号加法(减法)。

像撰写论文一样组织您的代码。先放最抽象的代码,再放更详细的代码。代码的读者永远不必回头查看顶部以了解某些东西是如何工作的。

这是完整的可运行代码。

public class SummingLargeNumbers {

    public static void main(String[] args) {
        SummingLargeNumbers sln = new SummingLargeNumbers();
        
        String s1 = "123";
        String s2 = "8900";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "123";
        s2 = "89";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "-123";
        s2 = "893";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "-123";
        s2 = "-893";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "123";
        s2 = "-893";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "999";
        s2 = "-999";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "999";
        s2 = "-997";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "-999";
        s2 = "997";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "-88131415555612";
        s2 = "77020304444501";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "-1021315510";
        s2 = "2183194";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "1021315510";
        s2 = "-2183194";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
        
        s1 = "-1021315510";
        s2 = "-2183194";
        System.out.println(s1 + " + " + s2 + " = " + sln.findSum(s1,s2));
    }
    
    public String findSum(String s1,String s2) {
        if (s1 == null || s2 == null || s1.isEmpty() || s2.isEmpty()) {
            return "";
        }
        
        boolean s1IsNegative = s1.charAt(0) == '-';
        boolean s2IsNegative = s2.charAt(0) == '-';
        
        if (s1IsNegative == s2IsNegative) {
            return addNumbers(s1,s2);
        } else {
            return subtractNumbers(s1,s2);
        }
    }
    
    private String addNumbers(String s1,String s2) {
        boolean s1IsNegative = s1.charAt(0) == '-';
        s1 = stripSign(s1);
        s2 = stripSign(s2);
        int index1 = s1.length() - 1;
        int index2 = s2.length() - 1;
        int carry = 0;
        
        StringBuilder builder = new StringBuilder();
        // Add the two String numbers together;
        while (index1 >= 0 || index2 >= 0) {
            int digit1 = (index1 >= 0) ? convertToInt(s1.charAt(index1--)) : 0;
            int digit2 = (index2 >= 0) ? convertToInt(s2.charAt(index2--)) : 0;
            int sum = digit1 + digit2 + carry;
            carry = sum / 10;
            int digit = sum % 10;
            builder.append(digit);
        }
        
        if (carry > 0) {
            builder.append(carry);
        }
        
        if (s1IsNegative) {
            builder.append('-');
        }
        
        return builder.reverse().toString();
    }
    
    private String subtractNumbers(String s1,String s2) {
        String[] order = orderNumbers(s1,s2);
        String larger = order[0];
        String smaller = order[1];
        boolean largerIsNegative = larger.charAt(0) == '-';
        larger = stripSign(larger);
        smaller = stripSign(smaller);
        int index1 = larger.length() - 1;
        int index2 = smaller.length() - 1;
        int borrow = 0;
        
        StringBuilder builder = new StringBuilder();
        // Subtract the smaller from the larger String number
        while (index1 >= 0 || index2 >= 0) {
            int digit1 = (index1 >= 0) ? convertToInt(larger.charAt(index1--)) : 0;
            int digit2 = (index2 >= 0) ? convertToInt(smaller.charAt(index2--)) : 0;
            int difference = digit1 - digit2 - borrow;
            if (difference < 0) {
                difference += 10;
                borrow = 1;
            } else {
                borrow = 0;
            }
            
            builder.append(difference);
        }
        
        if (largerIsNegative) {
            builder.append('-');
        }
        
        return removeLeadingZeros(builder);
    }
    
    /**
     * This method returns the String numbers in absolute value order.
     * 
     * @param s1 - String number 1
     * @param s2 - String number 2
     * @return - String array consisting of two values. The largest absolute value
     *         is first and the smallest absolute value is second.
     */
    private String[] orderNumbers(String s1,String s2) {
        boolean s1IsNegative = s1.charAt(0) == '-';
        boolean s2IsNegative = s2.charAt(0) == '-';
        s1 = stripSign(s1);
        s2 = stripSign(s2);
        String largest;
        String smallest;
        
        if (s1.length() < s2.length()) {
            largest = (s2IsNegative) ? "-" + s2 : s2;
            smallest = (s1IsNegative) ? "-" + s1 : s1;
        } else if (s1.length() > s2.length()) {
            largest = (s1IsNegative) ? "-" + s1 : s1;
            smallest = (s2IsNegative) ? "-" + s2 : s2;
        } else {
            boolean s1IsLarger = true;
            // Both Strings are the same size.  Find the largest digit,// starting from left to right;
            for (int index = 0; index < s1.length(); index++) {
                int digit1 = convertToInt(s1.charAt(index));
                int digit2 = convertToInt(s2.charAt(index));
                if (digit1 < digit2) {
                    s1IsLarger = false;
                    break;
                } else if (digit2 < digit1) {
                    s1IsLarger = true;
                    break;
                }
            }
            
            if (s1IsLarger) {
                largest = (s1IsNegative) ? "-" + s1 : s1;
                smallest = (s2IsNegative) ? "-" + s2 : s2;
            } else {
                largest = (s2IsNegative) ? "-" + s2 : s2;
                smallest = (s1IsNegative) ? "-" + s1 : s1;
            }
        }
        
        String[] output = new String[2];
        output[0] = largest;
        output[1] = smallest;
        
        return output;
    }
    
    private String removeLeadingZeros(StringBuilder builder) {
        int index = builder.length() - 1;
        boolean isNegative = builder.substring(index,index + 1).equals("-");
        
        if (isNegative) {
            builder.delete(index,index + 1);
            index--;
        }
        
        while (index > 0) {
            if (builder.substring(index,index + 1).equals("0")) {
                builder.delete(index,index + 1);
                index--;
            } else {
                break;
            }
        }
        
        if (isNegative) {
            builder.append('-');
        }
        
        return builder.reverse().toString();
    }
    
    private String stripSign(String s) {
        if (s.charAt(0) == '-' || s.charAt(0) == '+') {
            return s.substring(1);
        } else {
            return s;
        }
    }
    
    private int convertToInt(char c) {
        return (int) (c - '0');
    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。