You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

大数进制转换求助: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ł

火山引擎 最新活动