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

nic*_*omp 2 c# biginteger

我正在使用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.
Run Code Online (Sandbox Code Playgroud)

Tit*_*mir 5

byte[]的表现BigInteger没有什么用ASCII字符.就像一个字节表示int与它的ASCII表示没有多大关系.

要解析数字,每个字符必须转换为数字值,并添加到先前解析的值乘以10.这可能是为什么它花了这么长时间,你编写的任何版本可能都不会更好.它必须做的事情如下:

    var nr=0;
    foreach(var c in "123") nr=nr*10+(c-'0');
Run Code Online (Sandbox Code Playgroud)

编辑

虽然不可能通过转换为字节数组来执行转换,但库实现速度要慢一些(至少对于不需要国际化的简单场景).使用Rudy Velthuis在评论中提出的技巧而不考虑十六进制格式或国际化,我能够生成一个版本,对于303104个字符运行速度快〜5倍(从18.2s到3.75s.对于100万个数字,快速方法需要47s,很长,但它是一个巨大的数字):

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 它可以更快地完成,但它需要你为它编写一个分而治之的算法.数量巨大的大问题是每次必须将一个巨大的数字乘以10(并且它会增长).将此字符串除以较小的片段,将其解析,然后将它们相乘,然后再乘以10的相应幂.然后,只有最后一个乘法将是巨大的,但其他的将处理越来越小的数字.相反的转换(从二进制到十进制)改进了创建huuuuuuge字符串从几个小时到几分钟. (3认同)