2015-04-18 9 views
7

Ich versuche, eine Open-Source-Bibliothek von .Net 4,0-3,5 zu konvertieren und kann den folgenden langen Multiplikation Code nicht leicht umwandeln:Computing die hohe Bits einer Multiplikation in C#

/// <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 
    } 

Wie Sie das sehen Autor hat keinen Weg gefunden, dies zu tun. BigInteger ist in .NET 3.5 nicht vorhanden.

Wie kann ich die hohen Bits 64 Bits einer 64 * 64 Multiplikation auf .NET 3.5 berechnen?

+0

https://msdn.microsoft.com/en-us/magazine/cc163696.aspx –

+0

Danke für den Link, mit der J # -Bibliothek, könnte ich das zum Funktionieren bringen! Ich probiere es jetzt aus ... – Seneral

+0

hm nein funktioniert nicht für mich, [MDSN] (https://msdn.microsoft.com/de-de/library/7xsxf8e2%28v=vs.90%29.aspx) sagt, es ist nur verfügbar in VS 5 oder weniger, und ich muss VS2010 für die anderen Probleme verwenden (Standardparameter) – Seneral

Antwort

6

Sie können einen 2N-Bit-Multiplikator aus mehreren N-Bit-Multiplikatoren erstellen.

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

Es ist nur Grundschule Multiplikation, wirklich.

Mit vorzeichenbehafteten Nummern ist es etwas schwieriger, denn wenn Zwischenergebnisse in das Vorzeichen-Bit übertragen werden, läuft alles schief. Ein long kann nicht das Ergebnis einer 32-Bit von 32-Bit-Multiplikations ohne dass das passiert halten, so haben wir es in kleinere Stücke zu tun:

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; 
} 

Inspiriert von Harolds Kommentar über Hacker Delight, die signierte Version kann genauso effizient wie die anderen gemacht werden, indem man sorgfältig gesteuert wird, ob Zwischenergebnisse oder nicht angemeldet sind:

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; 
} 
+0

Oh, um ehrlich zu sein habe ich nicht erwartet, dass das funktioniert;) Und ich kann die Lösung nicht wirklich kontrollieren, es ist etwas von 4 Billionen (9 Billionen ist der Maximalwert?) Vielen Dank !! – Seneral

+0

@Senal: Stellen Sie sicher, dass eine Reihe von Komponententests ausgeführt werden. Da Sie Nummern signiert haben, können einige der Zwischenergebnisse in die Zeichenbits übertragen werden. Ich bin mir nicht sicher, ob dies das Endergebnis verfälschen wird. –

+0

@Seneral: Ich denke, ich habe eine Version, die auch auf negativen Zahlen funktionieren sollte. Hinzugefügt es. –