Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 优化Karatsuba实现_C#_Biginteger - Fatal编程技术网

C# 优化Karatsuba实现

C# 优化Karatsuba实现,c#,biginteger,C#,Biginteger,因此,我试图改进.NET4的biginger类提供的一些操作,因为这些操作看起来是二次的。我已经做了一个粗略的Karatsuba实现,但它仍然比我预期的慢 主要的问题似乎是BigInteger没有提供简单的方法来计算位数,因此,我不得不使用BigInteger.Log(…,2)。根据VisualStudio的数据,大约80-90%的时间用于计算对数 using System; using System.Collections.Generic; using System.Linq; using S

因此,我试图改进.NET4的
biginger
类提供的一些操作,因为这些操作看起来是二次的。我已经做了一个粗略的Karatsuba实现,但它仍然比我预期的慢

主要的问题似乎是BigInteger没有提供简单的方法来计算位数,因此,我不得不使用BigInteger.Log(…,2)。根据VisualStudio的数据,大约80-90%的时间用于计算对数

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;

namespace Test
{
    class Program
    {
        static BigInteger Karatsuba(BigInteger x, BigInteger y)
        {
            int n = (int)Math.Max(BigInteger.Log(x, 2), BigInteger.Log(y, 2));
            if (n <= 10000) return x * y;

            n = ((n+1) / 2);

            BigInteger b = x >> n;
            BigInteger a = x - (b << n);
            BigInteger d = y >> n;
            BigInteger c = y - (d << n);

            BigInteger ac = Karatsuba(a, c);
            BigInteger bd = Karatsuba(b, d);
            BigInteger abcd = Karatsuba(a+b, c+d);

            return ac + ((abcd - ac - bd) << n) + (bd << (2 * n));
        }

        static void Main(string[] args)
        {
            BigInteger x = BigInteger.One << 500000 - 1;
            BigInteger y = BigInteger.One << 600000 + 1;
            BigInteger z = 0, q;

            Console.WriteLine("Working...");
            DateTime t;

            // Test standard multiplication
            t = DateTime.Now;
            z = x * y;
            Console.WriteLine(DateTime.Now - t);

            // Test Karatsuba multiplication
            t = DateTime.Now;
            q = Karatsuba(x, y);
            Console.WriteLine(DateTime.Now - t);

            // Check they're equal
            Console.WriteLine(z == q);

            Console.Read();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统数字;
名称空间测试
{
班级计划
{
静态BigInteger Karatsuba(BigInteger x,BigInteger y)
{
intn=(int)Math.Max(biginger.Log(x,2),biginger.Log(y,2));
如果(n>n;
大整数a=x-(b>n;

biginger c=y-(d为什么要计算所有位

在vb中,我执行以下操作:

<Runtime.CompilerServices.Extension()> _
Function BitLength(ByVal n As BigInteger) As Integer
    Dim Data() As Byte = n.ToByteArray
    Dim result As Integer = (Data.Length - 1) * 8
    Dim Msb As Byte = Data(Data.Length - 1)
    While Msb
        result += 1
        Msb >>= 1
    End While
    Return result
End Function
最后

    static BigInteger Karatsuba(BigInteger x, BigInteger y)
    {
        int n = (int)Math.Max(x.BitLength(), y.BitLength());
        if (n <= 10000) return x * y;

        n = ((n+1) / 2);

        BigInteger b = x >> n;
        BigInteger a = x - (b << n);
        BigInteger d = y >> n;
        BigInteger c = y - (d << n);

        BigInteger ac = Karatsuba(a, c);
        BigInteger bd = Karatsuba(b, d);
        BigInteger abcd = Karatsuba(a+b, c+d);

        return ac + ((abcd - ac - bd) << n) + (bd << (2 * n));
    }
仅供参考:使用位长度方法,您还可以比BigInteger方法更快地计算出对数的良好近似值

bits = BitLength(a) - 1;
log_a = (double)i * log(2.0);
至于访问biginger结构的内部UInt32数组,这里有一个技巧

导入反射命名空间

Private Shared ArrM As MethodInfo
Private Shard Bits As FieldInfo
Shared Sub New()
    ArrM = GetType(System.Numerics.BigInteger).GetMethod("ToUInt32Array", BindingFlags.NonPublic Or BindingFlags.Instance)
    Bits = GetType(System.Numerics.BigInteger).GetMember("_bits", BindingFlags.NonPublic Or BindingFlags.Instance)(0)

End Sub
<Extension()> _
Public Function ToUInt32Array(ByVal Value As System.Numerics.BigInteger) As UInteger()
    Dim Result() As UInteger = ArrM.Invoke(Value, Nothing)
    If Result(Result.Length - 1) = 0 Then
        ReDim Preserve Result(Result.Length - 2)
    End If
    Return Result
End Function
或者交替地

Dim Data() As UInteger = Value.ToUInt32Array()

请注意,_bitsfieldinfo可用于直接访问BigInteger结构的底层UInteger()_bits字段。这比调用ToUInt32Array()更快方法。但是,当BigInteger B时,您能给出一些关于Karatsuba是什么的上下文吗?我不确定这是否有帮助,但也许您可以通过某种方式将其转换为一个位数组,这样您就可以计算位了。@aaronls:这要快得多,谢谢。@Chris:
出色的作品Alexander Higgins!+1感谢您的回答,它帮助我寻找完美的数字rs…很吸引人,但从一个简短的微基准来看,.Net似乎已经使用了这种优化;计时非常接近,有时会稍微快一点,但平均而言(不做数学计算),默认实现似乎以微弱优势获胜。实际上,有一个截止点之后,“小学”输给了“Karatsuba”由于4/3的改进。这是由于算法开销。还有其他快速乘法方法,例如Toom Cook,它比“小学”提高了9/5但在实践中,由于开销的原因,Karatsuba将赢得一些截止值。同样,在数千位的范围内,快速傅立叶将击败Toom Cook。
Private Shared ArrM As MethodInfo
Private Shard Bits As FieldInfo
Shared Sub New()
    ArrM = GetType(System.Numerics.BigInteger).GetMethod("ToUInt32Array", BindingFlags.NonPublic Or BindingFlags.Instance)
    Bits = GetType(System.Numerics.BigInteger).GetMember("_bits", BindingFlags.NonPublic Or BindingFlags.Instance)(0)

End Sub
<Extension()> _
Public Function ToUInt32Array(ByVal Value As System.Numerics.BigInteger) As UInteger()
    Dim Result() As UInteger = ArrM.Invoke(Value, Nothing)
    If Result(Result.Length - 1) = 0 Then
        ReDim Preserve Result(Result.Length - 2)
    End If
    Return Result
End Function
 Dim Data() As UInteger = ToUInt32Array(Value)
 Length = Data.Length 
Dim Data() As UInteger = Value.ToUInt32Array()
 Function KaratsubaSquare(ByVal x As BigInteger)
    Dim n As Integer = BitLength(x) 'Math.Max(BitLength(x), BitLength(y))

    If (n <= KaraCutoff) Then Return x * x
    n = ((n + 1) >> 1)

    Dim b As BigInteger = x >> n
    Dim a As BigInteger = x - (b << n)
    Dim ac As BigInteger = KaratsubaSquare(a)
    Dim bd As BigInteger = KaratsubaSquare(b)
    Dim c As BigInteger = Karatsuba(a, b)
    Return ac + (c << (n + 1)) + (bd << (2 * n))

End Function