问题描述
在Java中,long 类型的最大值约为 9 × 10^18,当需要处理更大的整数时(如100位、1000位甚至更多位的大数),基本数据类型无法满足需求。高精度计算(Big Integer)通过模拟人工竖式计算的方式,使用字符串或数组存储大数的每一位,实现任意精度整数的四则运算。
算法思路
存储方式
使用 int[] 或 ArrayList<Integer> 逆序存储每一位数字。例如数字 12345 存储为 [5, 4, 3, 2, 1],这样个位对齐,便于从低位到高位逐位运算。
加法
从低位到高位逐位相加,处理进位。时间复杂度 O(max(n, m))。
减法
先比较大小,用大数减小数,从低位到高位逐位相减,处理借位。时间复杂度 O(max(n, m))。
乘法
模拟竖式乘法:结果的第 i+j 位由第一个数的第 i 位和第二个数的第 j 位相乘累加得到。时间复杂度 O(n × m)。
除法
使用试商法,从被除数的高位开始,逐位确定商的每一位。时间复杂度 O(n × m)。
Java实现
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class BigInteger {
// 逆序存储:digits[0]是个位
private List<Integer> digits;
private boolean negative; // true表示负数
public BigInteger(String num) {
if (num == null || num.isEmpty()) {
throw new IllegalArgumentException("Invalid number");
}
digits = new ArrayList<>();
int start = 0;
negative = false;
if (num.charAt(0) == '-') {
negative = true;
start = 1;
} else if (num.charAt(0) == '+') {
start = 1;
}
// 去除前导零
while (start < num.length() - 1 && num.charAt(start) == '0') {
start++;
}
for (int i = num.length() - 1; i >= start; i--) {
char c = num.charAt(i);
if (c < '0' || c > '9') {
throw new IllegalArgumentException("Invalid digit: " + c);
}
digits.add(c - '0');
}
if (digits.isEmpty()) {
digits.add(0);
}
// 零的符号始终为正
if (digits.size() == 1 && digits.get(0) == 0) {
negative = false;
}
}
private BigInteger(List<Integer> digits, boolean negative) {
this.digits = new ArrayList<>(digits);
this.negative = negative;
normalize();
}
private void normalize() {
while (digits.size() > 1 && digits.get(digits.size() - 1) == 0) {
digits.remove(digits.size() - 1);
}
if (digits.size() == 1 && digits.get(0) == 0) {
negative = false;
}
}
public BigInteger abs() {
return new BigInteger(digits, false);
}
public boolean isNegative() {
return negative;
}
/**
* 比较绝对值大小
* @return 正数表示this大,负数表示other大,0表示相等
*/
private int compareAbs(BigInteger other) {
if (digits.size() != other.digits.size()) {
return digits.size() - other.digits.size();
}
for (int i = digits.size() - 1; i >= 0; i--) {
int diff = digits.get(i) - other.digits.get(i);
if (diff != 0) return diff;
}
return 0;
}
/**
* 加法:this + other
*/
public BigInteger add(BigInteger other) {
// 异号情况转化为减法
if (negative && !other.negative) {
BigInteger temp = new BigInteger(digits, false);
return other.subtract(temp);
}
if (!negative && other.negative) {
BigInteger temp = new BigInteger(other.digits, false);
return subtract(temp);
}
// 同号:绝对值相加,符号不变
List<Integer> result = new ArrayList<>();
int carry = 0;
int maxLen = Math.max(digits.size(), other.digits.size());
for (int i = 0; i < maxLen; i++) {
int a = i < digits.size() ? digits.get(i) : 0;
int b = i < other.digits.size() ? other.digits.get(i) : 0;
int sum = a + b + carry;
result.add(sum % 10);
carry = sum / 10;
}
if (carry > 0) {
result.add(carry);
}
return new BigInteger(result, negative);
}
/**
* 减法:this - other
*/
public BigInteger subtract(BigInteger other) {
// 异号情况转化为加法
if (negative && !other.negative) {
BigInteger temp = new BigInteger(digits, false).add(other);
return new BigInteger(temp.digits, true);
}
if (!negative && other.negative) {
BigInteger temp = new BigInteger(other.digits, false);
return add(temp);
}
// 同号:绝对值相减
int cmp = compareAbs(other);
if (cmp == 0) {
return new BigInteger("0");
}
boolean resultNegative = false;
List<Integer> larger, smaller;
if (cmp > 0) {
larger = digits;
smaller = other.digits;
resultNegative = negative; // 同号,大减小,符号不变
} else {
larger = other.digits;
smaller = digits;
resultNegative = !negative; // 小减大,符号翻转
}
List<Integer> result = new ArrayList<>();
int borrow = 0;
for (int i = 0; i < larger.size(); i++) {
int a = larger.get(i);
int b = i < smaller.size() ? smaller.get(i) : 0;
int diff = a - b - borrow;
if (diff < 0) {
diff += 10;
borrow = 1;
} else {
borrow = 0;
}
result.add(diff);
}
return new BigInteger(result, resultNegative);
}
/**
* 乘法:this × other
*/
public BigInteger multiply(BigInteger other) {
if ((digits.size() == 1 && digits.get(0) == 0) ||
(other.digits.size() == 1 && other.digits.get(0) == 0)) {
return new BigInteger("0");
}
List<Integer> result = new ArrayList<>(Collections.nCopies(digits.size() + other.digits.size(), 0));
for (int i = 0; i < digits.size(); i++) {
int carry = 0;
for (int j = 0; j < other.digits.size() || carry > 0; j++) {
long product = result.get(i + j)
+ (long) digits.get(i) * (j < other.digits.size() ? other.digits.get(j) : 0)
+ carry;
result.set(i + j, (int) (product % 10));
carry = (int) (product / 10);
}
}
boolean resultNegative = negative != other.negative;
return new BigInteger(result, resultNegative);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (negative) {
sb.append('-');
}
for (int i = digits.size() - 1; i >= 0; i--) {
sb.append(digits.get(i));
}
return sb.toString();
}
public static void main(String[] args) {
// 加法测试
BigInteger a = new BigInteger("12345678901234567890");
BigInteger b = new BigInteger("98765432109876543210");
System.out.println(a + " + " + b + " = " + a.add(b));
// 减法测试
BigInteger c = new BigInteger("10000000000000000000");
BigInteger d = new BigInteger("1");
System.out.println(c + " - " + d + " = " + c.subtract(d));
// 大数乘法测试
BigInteger e = new BigInteger("123456789");
BigInteger f = new BigInteger("987654321");
System.out.println(e + " × " + f + " = " + e.multiply(f));
// 验证:与Java内置BigInteger对比
java.math.BigInteger jA = new java.math.BigInteger("12345678901234567890");
java.math.BigInteger jB = new java.math.BigInteger("98765432109876543210");
System.out.println("\nJava内置验证:" + jA.add(jB));
}
}
扩展:阶乘计算
public class Factorial {
/**
* 计算n的阶乘(使用自定义BigInteger)
*/
public static BigInteger factorial(int n) {
if (n < 0) {
throw new IllegalArgumentException("n must be non-negative");
}
BigInteger result = new BigInteger("1");
for (int i = 2; i <= n; i++) {
result = result.multiply(new BigInteger(String.valueOf(i)));
}
return result;
}
public static void main(String[] args) {
for (int n : new int[]{10, 20, 30, 50, 100}) {
System.out.println(n + "! = " + factorial(n));
}
}
}
复杂度分析
| 运算 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 加法 | O(max(n, m)) | O(max(n, m)) |
| 减法 | O(max(n, m)) | O(max(n, m)) |
| 乘法 | O(n × m) | O(n + m) |
| 除法 | O(n × m) | O(n) |
实际应用
- 密码学:RSA、ECC等算法需要处理数百位甚至上千位的大整数
- 科学计算:天文学、量子物理中的高精度数值计算
- 组合数学:大数阶乘、组合数计算
- 竞赛编程:处理超出long范围的整数运算
总结
高精度计算是算法基础中的基础。通过模拟人工竖式运算,用数组逆序存储每一位,实现了任意精度整数的四则运算。理解高精度算法的实现原理,不仅有助于解决大数运算问题,更能加深对进位、借位等基本运算本质的理解。在实际工程中,推荐使用Java内置的 java.math.BigInteger,但在竞赛或面试中,手写实现仍是重要的基本功。