【问题标题】:How to convert large integer number to binary?如何将大整数转换为二进制?
【发布时间】:2015-09-30 06:00:19
【问题描述】:

抱歉,可能有重复的帖子,我在这里看到了许多类似的主题,但没有一个是我真正需要的。在实际发布问题之前,我想明确声明这个问题不是家庭作业。

那么问题来了:如何将一个大整数转换成二进制表示?整数足够大以适合原始类型(Java long 不能使用)。输入可以表示为字符串格式或数字数组。免责声明,这不会是生产级别的解决方案,所以我不想使用 BigInteger 类。相反,我想实现一个算法。

到目前为止,我最终采用了以下方法: 以字符串表示的输入和输出值。如果输入的最后一位是偶数,我在输出前加上“0”,否则 - 加上“1”。之后,我将输入替换为输入除以 2。我使用另一种方法 - divideByTwo 进行算术除法。此过程循环运行,直到输入变为“0”或“1”。最后,我将输入添加到输出中。代码如下:

辅助方法

/**
* @param s input integer value in string representation
* @return the input divided by 2 in string representation
**/
static String divideByTwo(String s)
{
    String result = "";
    int dividend = 0;
    int quotent = 0;
    boolean dividendIsZero = false;

    while (s.length() > 0)
    {
        int i = 1;          
        dividend = Character.getNumericValue(s.charAt(0));

        while (dividend < 2 && i < s.length())
        {
            if (dividendIsZero) {result += "0";}
            dividend = Integer.parseInt(s.substring(0, ++i));
        }

        quotent = dividend / 2;
        dividend -= quotent * 2;            
        dividendIsZero = (dividend == 0);

        result += Integer.toString(quotent);
        s = s.substring(i);

        if (!dividendIsZero && s.length() != 0)
        {
            s = Integer.toString(dividend) + s;
        }
    }
    return result;      
}

主要方法

/**
* @param s the integer in string representation
* @return the binary integer in string representation
**/
static String integerToBinary(String s)
{
    if (!s.matches("[0-9]+"))
    {
        throw new IllegalArgumentException(s + " cannot be converted to integer");
    }

    String result = "";
    while (!s.equals("0") && !s.equals("1"))
    {
        int lastDigit = Character.getNumericValue(s.charAt(s.length()-1));
        result = lastDigit % 2 + result; //if last digit is even prepend 0, otherwise 1
        s = divideByTwo(s);
    }
    return (s + result).replaceAll("^0*", "");
}

如您所见,运行时间为 O(n^2)。 integerToBinary 方法的 O(n) 和循环内运行的 divideByTwo 的 O(n)。有没有办法实现更好的运行时?提前致谢!

【问题讨论】:

    标签: java algorithm binary integer largenumber


    【解决方案1】:

    试试这个:

    new BigDecimal("12345678901234567890123456789012345678901234567890").toString(2);
    

    编辑:

    为了创建一个大数字类,你可能想看看我一周前关于这个的帖子。啊,问题是你的,没关系。

    不同数制之间的转换,原则上是一个重复的“除、余、乘、加”运算。我们来看一个例子:

    我们希望将 123 从十进制转换为以 3 为底的数字。我们该怎么办?

    Take the remainder modulo 3 - prepend this digit to the result.
    Divide by 3.
    If the number is bigger than 0, continue with this number at step 1
    

    所以它看起来像这样:

    123 % 3 == 0. ==> The last digit is 0.
    123 / 3 == 41.
    41 % 3 == 2 ==> The second last digit is 2.
    41 / 3 == 13
    13 % 3 == 1 ==> The third digit is 1.
    13 / 3 == 4
    4 % 3 == 1 ==> The fourth digit is 1 again.
    4 / 3 == 1
    1 % 3 == 1 ==> The fifth digit is 1.
    

    所以,我们得到 11120 作为结果。

    问题在于,为此您需要以十进制格式除以 3,如果您不以基于十进制的格式实现您的数字,通常情况并非如此(就像我在回答上面链接的最后一个问题)。

    但它适用于从内部数字格式转换为任何外部格式。

    那么,让我们看看我们将如何进行逆计算,从 11120(以 3 为底)到它的十进制等值。 (Base 3 是任意基数的占位符,Base 10 是内部基数的占位符。)原则上,这个数字可以写成:

    1 * 3^4 + 1 * 3^3 + 1*3^2 + 2*3^1 + 0*3^0

    更好的方法(计算速度更快)是这样的:

    ((((1 * 3) + 1 )*3 + 1 )*3 + 2)*3 + 0 1 3 4 12 13 39 41 123 123

    (这被称为霍纳方案,通常用于计算多项式的值。)

    如果您知道如何在目标系统中表示输入基数(和数字),则可以在您正在实现的数字方案中实现这一点。

    (我刚刚在我的 DecimalBigInt 类中添加了这样的计算,但您可能希望直接在内部数据结构中进行计算,而不是为每个十进制数字创建 BigNumber 类的新对象(甚至两个)输入。)

    【讨论】:

    • 非常感谢 S Harish Morampudi 的即时回答,但我不想使用 BigInteger 类。我想改为实现算法。所以,如果我对你的理解正确,并且“不同数制之间的转换原则上是一个重复的“除、余、乘、加”运算”,那么O(n^2)是较低的边界。是这样吗?
    【解决方案2】:

    在简单的方法中,有两种可能的方法(这里出现的所有数字都是十进制的)

    1. 按照您在问题中概述的方式,以十进制计算并在每个步骤中除以 2
    2. 以二进制工作并在每个步骤中乘以 10,例如 123 = ((1 * 10) + 2) * 10 + 3

    如果您在二进制计算机上工作,方法 2 可能更容易。

    请参阅 this post 以了解有关该主题的更深入讨论。

    【讨论】:

      【解决方案3】:

      wikipedia,据说:

      对于非常大的数字,这些简单的方法效率低下,因为 他们执行大量的乘法或除法,其中一个 操作数很大。一个简单的分治算法更 渐近有效:给定一个二进制数,除以 10^k,其中 k 的选择使得商大致等于 余;然后将这些部分中的每一个都转换为十进制并且 两个连接在一起。给定一个十进制数,它可以一分为二 大小相同的片段,每个片段都转换为二进制, 因此,第一个转换的部分乘以 10^k 并添加到 第二个转换的部分,其中 k 是小数位数 转换前的第二个,最不重要的部分。

      我试过了,对于大于10,000位的数字,这种方法比传统方法快。

      【讨论】:

        猜你喜欢
        • 2015-04-28
        • 1970-01-01
        • 2012-04-10
        • 2019-03-29
        • 2020-12-05
        • 1970-01-01
        • 2012-08-18
        • 2017-07-13
        • 2018-10-10
        相关资源
        最近更新 更多