如何将大整数转换为二进制?

时间:2015-09-30 06:00:20

标签: java algorithm binary integer largenumber

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

所以问题是:如何将大整数转换为二进制表示?整数很大,足以适合原始类型(不能使用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)。有没有办法实现更好的运行时?提前谢谢!

3 个答案:

答案 0 :(得分:2)

试试这个:

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

编辑:

为了制作一个大号课程,你可能想在一周前查看我的帖子。啊,问题是你,没关系。

原则上不同数字系统之间的转换是重复的分组,余数,乘法,加法&#34;操作。让我们看一个例子:

我们想将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。

问题是,为此你需要以十进制格式进行某种除法,如果你没有以十进制格式实现你的数字,那通常不是这种情况(就像我做的那样)在上面链接的上一个问题的答案中。)

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

那么,让我们看看我们如何进行逆向计算,从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

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

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

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

答案 1 :(得分:1)

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

  1. 以小数形式工作,并在问题中概述的每一步中除以2
  2. 以二进制方式工作,并在每个步骤中乘以10,例如123 = ((1 * 10) + 2) * 10 + 3
  3. 如果您正在使用二进制计算机,则方法2可能更容易。

    请参阅示例this post,以便对该主题进行更深入的讨论。

答案 2 :(得分:0)

wikipedia中说:

<块引用>

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

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