我正在使用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)
本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)