如何将无限长度的二进制转换为十进制

How to convert unlimited length binary to decimal

本文关键字:二进制 转换 十进制 无限      更新时间:2023-10-16

最常见的方法是得到二进制数的每个非零位置的 2 的幂,然后将它们相加。当二进制数很大时,这是行不通的,比如说,

10000...0001//1000000 个仓位

不可能

让计算机计算 pow(2,1000000)。所以传统方式是行不通的。

其他方法可以做到这一点?

有人可以给出一个关于如何计算的算术方法,而不是库吗?

正如Happydave所说,这种类型的事情已经存在库(如GMP)。如果您出于某种原因需要自己动手,这里有一个相当有效的方法的概述。你需要大减法、比较和乘法。

以二进制

格式缓存值 10^(2^n),直到下一个值大于二进制数。这将允许您通过执行以下操作快速生成 10 的幂:

Select the largest value in your cache smaller than your remaining number, store this
in a working variable.
do{
  Multiply it by the next largest value in your cache and store the result in a
  temporary value.
  If the new value is still smaller, set your working value to this number (swapping 
  references here rather than allocating new memory is a good idea),
  Keep a counter to see which digit you're at. If this changes by more than one
  between instances of the outer loop, you need to pad with zeros
} Until you run out of cache
This is your next base ten value in binary, subtract it from your binary number while
the binary number is larger than your digit, the number of times you do this is the 
decimal digit -- you can cheat a little here by comparing the most significant bits
and finding a lower bound before trying subtraction.
Repeat until your binary number is 0

这大约是关于二进制数字数的O(n^4),关于内存的O(nlog(n))。您可以使用更复杂的乘法算法使 n^4 更接近 n^3。

您可以编写自己的类来处理任意大的整数(您可以将其表示为整数数组或任何最有意义的整数),并自己实现操作(*,pow 等)。 或者你可以谷歌"C++大的整数库",并找到已经实现它的其他人。

不可能

让计算机计算 pow(2,1000000)。所以传统方式是行不通的。

这并非不可能。例如,Python可以立即进行算术计算,并在大约两秒钟内转换为十进制数(在我的机器上)。Python内置了处理超过机器字大小的大整数的工具。

在C++(和C)中,大整数库的一个不错的选择是GMP。它坚固耐用,经过良好测试,并积极维护。它包括一个C++包装器,该包装器使用运算符重载来提供漂亮的接口(除了,pow()操作没有C++运算符)。

下面是一个使用 GMP 的C++示例:

#include <iostream>
#include <gmpxx.h>
int main(int, char *[])
{
    mpz_class a, b;
    a = 2;
    mpz_pow_ui(b.get_mpz_t(), a.get_mpz_t(), 1000000);
    std::string s = b.get_str();
    std::cout << "length is " << s.length() << std::endl;
    return 0;
}

上述输出为

长度为 301030

在我的机器上执行 0.18 秒。

"这大约是关于二进制位数的O(n^4),关于内存的O(nlog(n))"。 您可以执行 O(n^(2 + epsilon)) 操作(其中 n 是二进制位数)和 O(n) 内存,如下所示:设 N 是大量二进制长度 n。计算残基 mod 2(容易;抓住低位)和 mod 5(不容易但不可怕;将二进制字符串分解成四个位的连续字符串;计算每个这样的 4 元组的残基 mod 5,并将它们相加,就像为十进制数抛出 9 一样。通过计算残基 mod 2 和 5,您可以读出低十进制数字。 减去这个;除以 10(互联网记录了执行此操作的方法),然后重复以获得下一个最低的数字。

我在 Smalltalk 中计算了 2 ** 1000000 并在 9.3 秒内将其转换为十进制,所以这并非不可能。 Smalltalk内置了大型整数库。

2 raisedToInteger: 1000000

如另一个答案中所述,您需要一个处理任意精度整数的库。 一旦你有了它,你对它执行 MOD 10 和 DIV 10 操作,以相反的顺序(最不重要到最重要)计算十进制数字。

粗略的想法是这样的:

LargeInteger *a;
char *string;

while (a != 0) {
    int remainder;
    LargeInteger *quotient;
    remainder = a % 10.
    *string++ = remainder + 48.
    quotient = a / 10.
    } 

这里缺少(或错误)了许多关于类型转换、内存管理和对象分配的细节,但它旨在演示一般技术。

使用 Gnu 多精度库非常简单。不幸的是,我无法测试这个程序,因为似乎我需要在编译器升级后重建我的库。但是没有太多的错误余地!

#include "gmpxx.h"
#include <iostream>
int main() {
    mpz_class megabit( "1", 10 );
    megabit <<= 1000000;
    megabit += 1;
    std::cout << megabit << 'n';
}