如何在 C# 中将 huuuuuge 字符串加载到 BigInteger 中,而不会丢失 ASCII 编码



我正在使用BigInteger.Parse(一些字符串),但它需要很长时间,我什至不确定它是否完成。

但是,我可以将巨大的字符串转换为字节数组,并在很短的时间内将字节数组塞入 BigInteger 构造函数中,但由于 BigInteger 和字节数组的字节序问题,它会破坏存储在字符串中的原始数字。

有没有办法将字符串转换为字节数组并将字节数组放入 BigInteger 对象中,同时保留字符串中存储在 ASCII 中的原始数字?

String s = "12345";  // Some huge string, millions of digits.
BigInteger bi = new BigInteger(Encoding.ASCII.GetBytes(s);  // very fast but the 12345 is lost 
// OR...
BigInteger bi = BigInteger.Parse(s);  // Takes forever therefore unuseable.

BigIntegerbyte[]表示形式与 ASCII 字符关系不大。就像int的字节表示形式与它的ASCII表示形式几乎没有关系一样。

要解析数字,必须将每个字符转换为数字值,并添加到先前解析的值乘以 10。这可能就是为什么它需要这么长时间的原因,而且你编写的任何版本都可能不会表现得更好。它必须执行以下操作:

var nr=0;
foreach(var c in "123") nr=nr*10+(c-'0');

编辑

虽然不可能仅通过转换为字节数组来执行转换,但库实现比必须的要慢(至少对于不需要国际化的简单场景)。使用 Rudy Velthuis 在评论中建议的技巧,并且不考虑十六进制格式或国际化,我能够制作一个版本,该版本对于303104字符的运行速度提高了 ~5 倍(从 18.2 秒到 3.75 秒。对于 1 百万位数字,快速方法需要 47 秒,很长,但这是一个巨大的数字):

public static class Helper
{
static BigInteger[] factors = Enumerable.Range(0, 19).Select(i=> BigInteger.Pow(10, i)).ToArray();
public static BigInteger ParseFast(string str)
{
var result = new BigInteger(0);
var n = str.Length;
var hasSgn = str[0] == '-';
int j;
for (var i = hasSgn ? 1 : 0; i < n; i += j - i)
{
long gr = 0;
for (j = i; j < i + 18 && j < n; j++)
{
gr = gr * 10 + (str[j] - '0');
}
result = result * factors[j-i]+ gr;
}
if (hasSgn)
{
result = BigInteger.MinusOne * result;
}
return result;
}
}

最新更新