计算C#中乘法的高位

问题描述 投票:9回答:1

我正在尝试将.Net 4.0的开源库转换为3.5,并且无法轻松转换以下长乘法代码:

    /// <summary>
    /// Calculate the most significant 64 bits of the 128-bit
        product x * y, where x and y are 64-bit integers.
    /// </summary>
    /// <returns>Returns the most significant 64 bits of the product x * y.</returns>
    public static long mul64hi(long x, long y)
    {
 #if !NET35
        BigInteger product = BigInteger.Multiply(x, y);
        product = product >> 64;
        long l = (long)product;
        return l;
 #else
        throw new NotSupportedException(); //TODO!
 #endif
    }

正如您所看到的,作者没有找到这样做的方法。 .NET 3.5中不存在BigInteger

如何在.NET 3.5上计算64 * 64乘法的高位64位?

c# .net biginteger multiplication
1个回答
9
投票

您可以从多个N位乘法器构建2N位乘法器。

public static ulong mul64hi(ulong x, ulong y)
{
    ulong accum = ((ulong)(uint)x) * ((ulong)(uint)y);
    accum >>= 32;
    ulong term1 = (x >> 32) * ((ulong)(uint)y);
    ulong term2 = (y >> 32) * ((ulong)(uint)x);
    accum += (uint)term1;
    accum += (uint)term2;
    accum >>= 32;
    accum += (term1 >> 32) + (term2 >> 32);
    accum += (x >> 32) * (y >> 32);
    return accum;
}

这真的只是小学长期的乘法。

有了签名的数字,它有点难,因为如果中间结果进入符号位,一切都会出错。如果不发生这种情况,long无法保存32位乘32位乘法的结果,因此我们必须在较小的块中进行:

public static long mul64hi(long x, long y)
{
    const long thirtybitmask = 0x3FFFFFFF;
    const long fourbitmask = 0x0F;
    long accum = (x & thirtybitmask) * (y & thirtybitmask);
    accum >>= 30;
    accum += ((x >> 30) & thirtybitmask) * (y & thirtybitmask);
    accum += ((y >> 30) & thirtybitmask) * (x & thirtybitmask);
    accum >>= 30;
    accum += ((x >> 30) & thirtybitmask) * ((y >> 30) & thirtybitmask);
    accum += (x >> 60) * (y & fourbitmask);
    accum += (y >> 60) * (x & fourbitmask);
    accum >>= 4;
    accum += (x >> 60) * (y >> 4);
    accum += (y >> 60) * (x >> 4);
    return accum;
}

受Harold关于Hacker's Delight的评论的启发,通过仔细控制中间结果是否签名,签名版本可以与其他版本一样高效:

public static long mul64hi(long x, long y)
{
    ulong u = ((ulong)(uint)x) * ((ulong)(uint)y);
    long s = u >> 32;
    s += (x >> 32) * ((long)(uint)y);
    s += (y >> 32) * ((long)(uint)x);
    s >>= 32;
    s += (x >> 32) * (y >> 32);
    return s;
}
© www.soinside.com 2019 - 2024. All rights reserved.