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

例如,我如何将2^6012345678901234567890123456789012345678901234567890转换为二进制? 基本上,数字太大而无法在Java中表示。

编辑:我将创建一个能够代表太大的数字的类。 我只是很难确定如何将十进制转换为二进制。

Edit2:而且,我不允许使用BigDecimal,BigInteger或任何其他库,抱歉没有提前指定。

尝试这个:

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

编辑:

为了制作一个大class,你可能想看一周前我的post 。 啊,问题是你,没关系。

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

我们想将123从十进制转换为基数为3的数字。 我们做什么?

  1. 取余数模3 – 将这个数字加到结果前面。
  2. 除以3。
  3. 如果该数字大于0,请在步骤1继续该数字

所以它看起来像这样:

  • 123 % 3 == 0 。 ==>最后一位是0
  • 123 / 3 == 41
  • 41 % 3 == 2 ==>倒数第二个数字是2
  • 41 / 3 == 13
  • 13 % 3 == 1 ==>第三位是1
  • 13 / 3 == 4
  • 4 % 3 == 1 ==>第四位再次为1
  • 4 / 3 == 1
  • 1 % 3 == 1 ==>第五位是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类的新对象(甚至两个)。)

这是一个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 ) ); } } 

输出:

dec2bin(12345)= 011000000111001

dec2bin(12345678901234567890123456789012345678901234567890)= 10000111001001111111011000110110100110101010111110000011110010100001010100000010011111110100011110101111100011000111111100011001011011001110001111110000101011010010


我的主要想法是始终使用字符串。

add -method添加两个二进制数字,表示为字符串
dec2bin -method是神奇发生的地方。

请允许我解释一下:

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

是将任何给定数乘以10的计算。

将二进制数乘以10与使用移位添加数字相同:

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

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

只需在结果字符串上添加下一个数字(从左到右)


基本上我正在做的是例如1234:
0 * 10 + 1 = 1
1 * 10 + 2 = 12
12 * 10 + 3 = 123
123 * 10 + 4 = 1234

但仅限于二进制(表示为字符串)。


我希望我可以帮助并抱歉我的英语不好。

这种方法怎么样:

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

所以我们需要一种方法来表示一个任意大的二进制数,并实现乘以10和加上小数。

表示任意大二进制数的最直接方式是其二进制数字的数组。 然后,您可以应用算法在小学中添加和乘法学习,除非数字超过1而不是9时会“溢出”。例如:

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

皮尤:谢谢,这适用于一些数字。 然而,数字6123456789012不起作用,但这是修复:

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

如果只使用整数,请使用BigInteger.toByteArray 。

如果没有,遗憾的是BigDecimal没有那种方法。 但是我想你总是(在这两种情况下)只对ASCII编码数字的字符串表示,如果二进制forms只是用于传输而不是在任何地方进行计算。

有一个快速的程序来获得一个巨大的十进制的二进制表示。 这个程序确实很快,用3000digits处理小数只需要20ms,例如:string(3000,’2’)+’12345’。 因为追求效率,它不是很可读。 您可以自己修改它以使其更容易理解。

  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()); }