简体   繁体   English

如何在Java中将非常大的十进制数转换为二进制数

[英]How Can I Convert Very Large Decimal Numbers to Binary In Java

For instance, How would I be able to convert 2^60 or 12345678901234567890123456789012345678901234567890 to binary? 例如,我如何将2^6012345678901234567890123456789012345678901234567890转换为二进制? Basically, numbers that are too large to represent in Java. 基本上,数字太大而无法用Java表示。

Edit: I will be making a class that will be able to represent number that are too large. 编辑:我将创建一个能够代表太大的数字的类。 I'm just having a hard time figuring our how to convert decimal to binary. 我只是很难确定如何将十进制转换为二进制。

Edit2: And also, I am not allowed to use BigDecimal, BigInteger, or any other library, sorry for not specifying earlier. Edit2:而且,我不允许使用BigDecimal,BigInteger或任何其他库,抱歉没有提前指定。

Try this: 试试这个:

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

Edit: 编辑:

For making a big-number class, you may want to have a look at my post about this a week ago . 为了制作一个大号课程,你可能想在一周前查看我的帖子 Ah, the question was by you, never mind. 啊,问题是你,没关系。

The conversion between different number systems in principle is a repeated "division, remainder, multiply, add" operation. 原则上,不同数量系统之间的转换是重复的“除法,余数,乘法,加法”运算。 Let's look at an example: 我们来看一个例子:

We want to convert 123 from decimal to a base 3 number. 我们想将123从十进制转换为基数为3的数字。 What do we do? 我们做什么?

  1. Take the remainder modulo 3 - prepend this digit to the result. 取余数模3 - 将这个数字加到结果前面。
  2. Divide by 3. 除以3。
  3. If the number is bigger than 0, continue with this number at step 1 如果该数字大于0,请在步骤1继续该号码

So it looks like this: 所以它看起来像这样:

  • 123 % 3 == 0 . 123 % 3 == 0 ==> The last digit is 0 . ==>最后一位是0
  • 123 / 3 == 41 . 123 / 3 == 41
  • 41 % 3 == 2 ==> The second last digit is 2 . 41 % 3 == 2 ==>倒数第二个数字是2
  • 41 / 3 == 13
  • 13 % 3 == 1 ==> The third digit is 1 . 13 % 3 == 1 ==>第三位是1
  • 13 / 3 == 4
  • 4 % 3 == 1 ==> The fourth digit is 1 again. 4 % 3 == 1 ==>第四位数字再次为1
  • 4 / 3 == 1
  • 1 % 3 == 1 ==> The fifth digit is 1 . 1 % 3 == 1 ==>第五位是1

So, we have 11120 as the result. 所以,我们有11120作为结果。

The problem is that for this you need to have already some kind of division by 3 in decimal format, which is usually not the case if you don't implement your number in a decimal-based format (like I did in the answer to your last question linked above). 问题是,为此你需要以十进制格式进行某种除法,如果你没有以基于十进制的格式实现你的数字,那通常不是这种情况(就像我在答案中所做的那样)上面提到的最后一个问题)

But it works for converting from your internal number format to any external format. 但它适用于从内部数字格式转换为任何外部格式。


So, let's look at how we would do the inverse calculation, from 11120 (base 3) to its decimal equivalent. 那么,让我们看看我们如何进行逆向计算,从11120 (基数3)到其十进制等值。 (Base 3 is here the placeholder for an arbitrary radix, Base 10 the placeholder for your internal radix.) In principle, this number can be written as this: (Base 3在这里是任意基数的占位符,Base 10是内部基数的占位符。)原则上,这个数字可以写成:

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

A better way (faster to calculate) is this: 一个更好的方法(更快地计算)是这样的:

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

(This is known as Horner scheme , normally used for calculating values of polynomials.) (这被称为Horner方案 ,通常用于计算多项式的值。)

You can implement this in the number scheme you are implementing, if you know how to represent the input radix (and the digits) in your target system. 如果您知道如何表示目标系统中的输入基数(和数字),则可以在要实现的数字方案中实现此目的。

(I just added such a calculation to my DecimalBigInt class, but you may want to do the calculations directly in your internal data structure instead of creating a new object (or even two) of your BigNumber class for every decimal digit to be input.) (我刚刚将这样的计算添加到我的DecimalBigInt类中,但您可能希望直接在内部数据结构中进行计算,而不是为每个要输入的十进制数字创建BigNumber类的新对象(甚至两个)。)

Here is a quik& dirty (very very very dirty) code: 这是一个quik& dirty (非常非常非常脏)的代码:

public class BigDec2Bin {

    public static int[] string2arrayReversed( String s )
    {
        char a[] = s.toCharArray();
        int  b[] = new int[ s.length() ];
        for( int i = 0; i < a.length; i++ )
        {
            b[a.length-1-i] = a[i] - 48;
        }
        return b;
    }

    // adds two binary numbers represented as strings
    public static String add( String s1, String s2 )
    {
        String result = "", stmp;
        int[] a1, a2;
        int ctmp, mark = 0;

        // a1 should be the longer one
        a1 = string2arrayReversed( ( s1.length() > s2.length() ? s1 : s2 ) );
        a2 = string2arrayReversed( ( s1.length() < s2.length() ? s1 : s2 ) );

        for( int i = 0; i < a1.length; i++ )
        {
            ctmp = a1[i] + ( i < a2.length ? a2[i] : 0 ) + mark;

            switch( ctmp )
            {
                default:
                case 0:
                    stmp = "0";
                    mark = 0;
                    break;
                case 1:
                    stmp = "1";
                    mark = 0;
                    break;
                case 2:
                    stmp = "0";
                    mark = 1;
                    break;
                case 3:
                    stmp = "1";
                    mark = 1;
                    break;
            }

            result = stmp + result;
        }

        if( mark > 0 ) { result = "1" + result; }

        return result;
    }

    public static String dec2bin( String s )
    {
        String result = "";

        for( int i = 0; i < s.length() ; i++ )
        {
            result = add( result + "0", result + "000" );
            result = add( result, Integer.toBinaryString( s.charAt(i) - 48 ) );
        }

        return result;
    }

    public static void main( String[] args )
    {
        String dec = "12345"; // should be 11000000111001
        System.out.println( "dec2bin( " + dec + " ) = " + dec2bin( dec ) );

        dec = "12345678901234567890123456789012345678901234567890";
        System.out.println( "dec2bin( " + dec + " ) = " + dec2bin( dec ) );
    }

}

Output: 输出:

dec2bin( 12345 ) = 011000000111001 dec2bin(12345)= 011000000111001

dec2bin( 12345678901234567890123456789012345678901234567890 ) = 10000111001001111111011000110110100110101010111110000011110010100001010100000010011001110100011110101111100011000111111100011001011011001110001111110000101011010010 dec2bin(12345678901234567890123456789012345678901234567890)= 10000111001001111111011000110110100110101010111110000011110010100001010100000010011111110100011110101111100011000111111100011001011011001110001111110000101011010010


My main idea is to use always strings. 我的主要想法是始终使用字符串。

add -method adds two binary numbers which are represented as strings add -method添加两个二进制数字,表示为字符串
dec2bin -method is where the magic happens. dec2bin -method是神奇发生的地方。

Allow me to explain: 请允许我解释一下:

result = add( result + "0", result + "000" );

is a calculation to multiply any given number by 10. 是将任何给定数乘以10的计算。

Multiplying a binary number by 10 is the same as adding the number with shifts: 将二进制数乘以10与使用shift添加数字相同:

x*10 <=> x<<1 + x<<3 x * 10 <=> x << 1 + x << 3

result = add( result, Integer.toBinaryString( s.charAt(i) - 48 ) );

just adds a the next digit (from left to right) on the result string 只需在结果字符串上添加下一个数字(从左到右)


Basicly what I'm doing is for example with 1234: 基本上我正在做的是例如1234:
0*10 + 1 = 1 0 * 10 + 1 = 1
1*10 + 2 = 12 1 * 10 + 2 = 12
12*10 + 3 = 123 12 * 10 + 3 = 123
123*10 + 4 = 1234 123 * 10 + 4 = 1234

but only in binary (represented as strings). 但仅限于二进制(表示为字符串)。


I hope i could help and sorry for my bad english. 我希望我可以帮助并抱歉我的英语不好。

What about this approach: 这种方法怎么样:

result = 0;
for each digit in the decimal number, from left to right
    result = result * 10 + digit;
return result;

So we need a way to represent an arbitrarily large binary number, and implement multiplication by 10 and addition of small numbers. 因此,我们需要一种方法来表示任意大的二进制数,并实现乘以10并添加小数。

The most straightforward way to represent an arbitrarily large binary number is an array of its binary digits. 表示任意大二进制数的最直接方式是其二进制数字的数组。 You can then apply the algorithms for addition and multiplication your learned in elementary school, except that digits will "overflow" when they exceed 1 rather than 9. For example: 然后,您可以应用算法在小学中添加和乘法学习,除非数字超过1而不是9时会“溢出”。例如:

  1010 * 1100111
----------------
        11001110 
+     1100111000
----------------
     10000000110

Pew: thanks, that works for some numbers. 皮尤:谢谢,这适用于一些数字。 The number 6123456789012 however doesn't work, but here is the fix: 然而,数字6123456789012不起作用,但这是修复:

// a1 should be the longer one
a1 = string2arrayReversed( ( s1.length() >= s2.length() ? s1 : s2 ) ); //GREATER EQUAL 

there is a fast program to get the binary representation of a huge decimal. 有一个快速的程序来获得一个巨大的十进制的二进制表示。 This programm is indeed fast, it takes only 20ms to deal with a decimal with 3000digits, eg:string(3000,'2')+'12345'. 这个程序确实很快,处理带有3000digits的小数只需要20ms,例如:string(3000,'2')+'12345'。 because of the pursuit of efficiency, it is not very readable. 因为追求效率,它不是很可读。 you can modify it yourself to make it easier to understand. 您可以自己修改它以使其更容易理解。

    inline string remove_pre_zero(const string& a)
{
    auto t = a.find_first_not_of('\0', 0);
    if (t == a.npos)
        return string("0");
    else
        return a.substr(t);
}

string convert_to_bin(const string& _s)
{
    const static string str[] = { "0", "1" };
    string s(_s.size(), '0');
    string binary;
    binary.reserve(_s.size()*3);
    int i = 0;
    for (const auto& c : _s)    
        s[i++] = (c - '0');

    while (s!="0")//simulate divide by 2
    {
        int t = 0, old_t = 0;
        for (auto& ch : s)
        {
            t = ((old_t * 10 + ch) & 1);
            ch = (ch + old_t * 10) >>1;
            old_t = t;
        }
        binary += str[t];
        if (s[0] == 0)
            s = remove_pre_zero(s);
    }   
        return string(binary.rbegin(), binary.rend());
}

If you only work with integers, use BigInteger.toByteArray . 如果只使用整数,请使用BigInteger.toByteArray

If not, unfortunately BigDecimal doesn't have that method. 如果没有,遗憾的是BigDecimal没有那种方法。 But I suppose you can always (in both cases) just ASCII encode the string representation of the number, if the binary form is just meant for transfer and not calculation anywhere. 但是我想你总是(在两种情况下)只对ASCII编码数字的字符串表示,如果二进制形式只是用于传输而不是在任何地方进行计算。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM