【问题标题】:How Can I Convert Very Large Decimal Numbers to Binary In Java如何在 Java 中将非常大的十进制数转换为二进制数
【发布时间】:2011-07-19 08:10:31
【问题描述】:

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

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

Edit2:另外,我不允许使用 BigDecimal、BigInteger 或任何其他库,抱歉之前没有指定。

【问题讨论】:

    标签: java binary decimal


    【解决方案1】:

    这是一个 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 ) = 10000111001001111111011000110110100110101010111110000011110010100001010100000010011001110100011110101111100011000111111100011001011011001110001111110000101011010010 P>


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

    add - 方法将两个二进制数相加,表示为字符串
    dec2bin - 方法是魔术发生的地方。

    请允许我解释一下:

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

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

    将二进制数乘以 10 与将数字相加相同:

    x*10 x

    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

    但只能以二进制形式(表示为字符串)。


    我希望我能帮上忙,并为我的英语不好感到抱歉。

    【讨论】:

      【解决方案2】:

      试试这个:

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

      编辑:

      要制作大量课程,您可能需要查看my post about this a week ago。啊,问题是你的,没关系。

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

      我们希望将 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 作为结果。

      问题在于,为此您需要以十进制格式除以 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
      

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

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

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

      【讨论】:

      • @eLobato:是的,我在发送后评论了这一点。我添加了更多提示。
      【解决方案3】:

      这种方法怎么样:

      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
      

      【讨论】:

        【解决方案4】:

        Pew:谢谢,这适用于某些数字。然而,数字 6123456789012 不起作用,但这里是修复:

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

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

          • 我将只处理整数,这会有所帮助。但我不允许使用 BigInteger 或 BigDecimal 进行分配。
          • 哦,如果是作业,那么你只需要找出 BigInteger 使用的底层技术 :)
          • 哈哈,好吧。我根本不知道该怎么做。
          【解决方案6】:

          有一个快速的程序可以得到一个大十进制的二进制表示。 这个程序确实很快,处理一个3000位的小数只需要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());
          }
          

          【讨论】:

            猜你喜欢
            • 2017-02-25
            • 2018-03-15
            • 1970-01-01
            • 2010-10-31
            • 2012-09-14
            • 2010-10-19
            • 2012-10-26
            • 2010-10-31
            • 1970-01-01
            相关资源
            最近更新 更多