如何在Java中将非常大的十进制数转换为二进制数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Java中将非常大的十进制数转换为二进制数相关的知识,希望对你有一定的参考价值。
例如,我怎样才能将2^60
或12345678901234567890123456789012345678901234567890
转换为二进制?基本上,数字太大而无法用Java表示。
编辑:我将创建一个能够代表太大的数字的类。我只是很难确定如何将十进制转换为二进制。
Edit2:而且,我不允许使用BigDecimal,BigInteger或任何其他库,抱歉没有提前指定。
试试这个:
new BigDecimal("12345678901234567890123456789012345678901234567890").toString(2);
编辑:
要制作一个大班,你可能想看看my post about this a week ago。啊,问题是你,没关系。
原则上,不同数量系统之间的转换是重复的“除法,余数,乘法,加法”运算。我们来看一个例子:
我们想将123从十进制转换为基数为3的数字。我们做什么?
- 取余数模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方案,通常用于计算多项式的值。)
如果您知道如何表示目标系统中的输入基数(和数字),则可以在要实现的数字方案中实现此目的。
(我just added对我的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与使用shift添加数字相同:
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并添加小数。
表示任意大二进制数的最直接方式是其二进制数字的数组。然后你可以将你在小学学到的加法算法和multiplication应用,除了数字超过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编码数字的字符串表示,如果二进制形式只是用于传输而不是在任何地方进行计算。
有一个快速的程序来获得一个巨大的十进制的二进制表示。这个程序确实很快,处理带有3000digits的小数只需要20ms,例如:string(3000,'2')+'12345'。因为追求效率,它不是很可读。您可以自己修改它以使其更容易理解。
inline string remove_pre_zero(const string& a)
{
auto t = a.find_first_not_of(' ', 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());
}
以上是关于如何在Java中将非常大的十进制数转换为二进制数的主要内容,如果未能解决你的问题,请参考以下文章