大数进制转换求助:int/long范围不足,如何用ArrayList实现?
大数进制转换解决方案(基于ArrayList实现)
嘿,你的思路完全没问题——用ArrayList(或者更通用的List)来存储大数的每一位,确实是解决int/long范围限制的靠谱方案。先帮你分析下现有代码的核心问题,再一步步实现基于List的大数进制转换。
现有代码的核心问题
你的naSystem方法存在几个致命问题:
- 数值溢出:用
int类型存储转换结果,只要输入的数稍微大一点(比如超过10位的十进制数,或者长一点的二进制数)就会溢出,结果完全错误。 - 精度丢失:
Math.pow返回的是double类型,当指数较大时,会丢失整数精度,导致计算结果偏差。 - 字符判断冗余:用正则判断是否是数字太麻烦,直接用
Character.isDigit()就可以搞定。
基于ArrayList的实现思路
我们可以模拟手工计算进制转换的过程,用ArrayList存储大数的每一位数字(按**个位、十位、百位...**的顺序存储,方便计算时进位),这样不管数字多大,都能避免溢出问题。
1. 其他进制 → 十进制
思路:从左到右遍历输入的每一位,每一步执行 当前结果 = 当前结果 × 进制 + 当前位数值,用ArrayList存储当前结果的每一位,处理进位。
比如转换二进制1010:
- 初始结果:[0]
- 第一步:0×2 + 1 = 1 → 结果[1]
- 第二步:1×2 + 0 = 2 → 结果[2]
- 第三步:2×2 + 1 = 5 → 结果[5]
- 第四步:5×2 + 0 = 10 → 结果[0,1](个位0,十位1)
- 最后逆序输出得到"10"
2. 十进制 → 其他进制
思路:反复对十进制数取余,把余数存入ArrayList,然后将十进制数除以进制,直到商为0,最后逆序ArrayList并转换为对应字符(大于9的用A-F表示)。
比如十进制10转二进制:
- 10 ÷2 =5 余0 → 存[0]
- 5÷2=2 余1 → 存[1]
- 2÷2=1 余0 → 存[0]
- 1÷2=0 余1 → 存[1]
- 逆序得到[1,0,1,0] → "1010"
完整代码实现
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class BigNumberBaseConverter { // 其他进制转十进制,返回十进制的字符串表示 public static String baseToDecimal(String number, int fromBase) { // 验证进制合法性(2-36,因为0-9+A-Z共36个字符) if (fromBase < 2 || fromBase > 36) { throw new IllegalArgumentException("进制必须在2-36之间"); } List<Integer> decimalDigits = new ArrayList<>(); decimalDigits.add(0); // 初始值为0 for (char c : number.toUpperCase().toCharArray()) { int digitValue; // 转换当前字符为对应数值 if (Character.isDigit(c)) { digitValue = c - '0'; } else { digitValue = c - 'A' + 10; } // 验证当前位是否符合进制要求 if (digitValue >= fromBase) { throw new IllegalArgumentException("输入的数字不符合当前进制规则"); } // 第一步:当前结果 × 进制 for (int i = 0; i < decimalDigits.size(); i++) { decimalDigits.set(i, decimalDigits.get(i) * fromBase); } // 第二步:加上当前位的数值 decimalDigits.set(0, decimalDigits.get(0) + digitValue); // 处理进位 handleCarry(decimalDigits); } // 逆序并转换为字符串 Collections.reverse(decimalDigits); StringBuilder sb = new StringBuilder(); for (int digit : decimalDigits) { sb.append(digit); } return sb.toString(); } // 十进制转其他进制,输入十进制字符串,返回目标进制的字符串 public static String decimalToBase(String decimalStr, int toBase) { if (toBase < 2 || toBase > 36) { throw new IllegalArgumentException("进制必须在2-36之间"); } // 用ArrayList存储十进制数的每一位(个位在前) List<Integer> decimalDigits = new ArrayList<>(); for (int i = decimalStr.length() - 1; i >= 0; i--) { decimalDigits.add(decimalStr.charAt(i) - '0'); } List<Character> resultDigits = new ArrayList<>(); while (!isZero(decimalDigits)) { int remainder = divideByBase(decimalDigits, toBase); // 转换余数为对应字符 char c = remainder < 10 ? (char) ('0' + remainder) : (char) ('A' + remainder - 10); resultDigits.add(c); } // 逆序得到最终结果 Collections.reverse(resultDigits); StringBuilder sb = new StringBuilder(); for (char c : resultDigits) { sb.append(c); } // 处理输入为0的情况 return sb.length() == 0 ? "0" : sb.toString(); } // 处理进位:遍历每一位,若大于等于10则进位 private static void handleCarry(List<Integer> digits) { for (int i = 0; i < digits.size(); i++) { int current = digits.get(i); if (current >= 10) { digits.set(i, current % 10); int carry = current / 10; // 如果是最后一位,添加新的进位位 if (i == digits.size() - 1) { digits.add(carry); } else { digits.set(i + 1, digits.get(i + 1) + carry); } } } } // 将存储的十进制数除以目标进制,返回余数 private static int divideByBase(List<Integer> digits, int base) { int remainder = 0; for (int i = digits.size() - 1; i >= 0; i--) { int current = remainder * 10 + digits.get(i); digits.set(i, current / base); remainder = current % base; } // 移除前面的0(因为是个位在前,所以是移除末尾的0) while (digits.size() > 0 && digits.get(digits.size() - 1) == 0) { digits.remove(digits.size() - 1); } return remainder; } // 判断存储的十进制数是否为0 private static boolean isZero(List<Integer> digits) { for (int digit : digits) { if (digit != 0) { return false; } } return true; } // 测试示例 public static void main(String[] args) { // 二进制转十进制 String binary = "10101010101010101010101010101010"; String decimal = baseToDecimal(binary, 2); System.out.println(binary + " 转十进制:" + decimal); // 输出17179869184 // 十进制转八进制 String octal = decimalToBase(decimal, 8); System.out.println(decimal + " 转八进制:" + octal); // 输出202020202020 // 十六进制转十进制 String hex = "FFFFFFFF"; String decFromHex = baseToDecimal(hex, 16); System.out.println(hex + " 转十进制:" + decFromHex); // 输出4294967295 } }
关键代码解释
handleCarry方法:处理计算过程中的进位,确保每一位都是0-9的数字。divideByBase方法:模拟大数除法,返回余数,同时更新大数的每一位为商。- 进制合法性校验:支持2-36进制,覆盖数字0-9和字母A-Z的范围。
- 空值/0处理:避免输入为0时返回空字符串的情况。
这样不管多大的数字,都能完美完成进制转换,完全不用担心溢出问题啦!
内容的提问来源于stack exchange,提问作者Em Eł




