我不确定这是否得到优化,但这段代码似乎比 ToByteArray 快 16 倍。它还避免了内存复制,这意味着您以 uint 而不是 byte 形式获得结果,因此您应该在那里进行进一步的改进。
//create delegate to get private _bit field
var par = Expression.Parameter(typeof(BigInteger));
var bits = Expression.Field(par, "_bits");
var lambda = Expression.Lambda(bits, par);
var func = (Func<BigInteger, uint[]>)lambda.Compile();
//test call our delegate
var bigint = BigInteger.Parse("3498574578238348969856895698745697868975687978");
int time = Environment.TickCount;
for (int y = 0; y < 10000000; y++)
{
var x = func(bigint);
}
Console.WriteLine(Environment.TickCount - time);
//compare time to ToByteArray
time = Environment.TickCount;
for (int y = 0; y < 10000000; y++)
{
var x = bigint.ToByteArray();
}
Console.WriteLine(Environment.TickCount - time);
从那里找到前 2 位应该很容易。第一位将在我假设的第一个 int 中,然后只需搜索第二个最高位即可。如果它在同一个整数中,则只需将第一位设置为零并找到最高位,否则搜索下一个非零 int 并找到最高位。
编辑:为了简单起见,只需将此类复制/粘贴到您的项目中即可。这会创建扩展方法,这意味着您只需调用 mybigint.GetUnderlyingBitsArray()。我还添加了一个获取 Sign 的方法,并且为了使其更通用,创建了一个函数,该函数将允许访问任何对象的任何私有字段。我发现这比调试模式下的原始代码慢,但在发布模式下速度相同。我建议您自己进行性能测试。
static class BigIntegerEx
{
private static Func<BigInteger, uint[]> getUnderlyingBitsArray;
private static Func<BigInteger, int> getUnderlyingSign;
static BigIntegerEx()
{
getUnderlyingBitsArray = CompileFuncToGetPrivateField<BigInteger, uint[]>("_bits");
getUnderlyingSign = CompileFuncToGetPrivateField<BigInteger, int>("_sign");
}
private static Func<TObject, TField> CompileFuncToGetPrivateField<TObject, TField>(string fieldName)
{
var par = Expression.Parameter(typeof(TObject));
var field = Expression.Field(par, fieldName);
var lambda = Expression.Lambda(field, par);
return (Func<TObject, TField>)lambda.Compile();
}
public static uint[] GetUnderlyingBitsArray(this BigInteger source)
{
return getUnderlyingBitsArray(source);
}
public static int GetUnderlyingSign(this BigInteger source)
{
return getUnderlyingSign(source);
}
}