public static bool UnitTest() { FourierPoint a, b; Random random = new Random(1001); byte[] ra = new byte[32]; BigInteger p = (BigInteger.One << 128) - (BigInteger.One << 54) + BigInteger.One; for (int i = 20 * 1000; --i >= 0;) { random.NextBytes(ra); ra[ra.Length - 1] = 0; a = new FourierPoint(BitConverter.ToUInt64(ra, 0), BitConverter.ToUInt64(ra, 8)); b = new FourierPoint(BitConverter.ToUInt64(ra, 16), BitConverter.ToUInt64(ra, 24)); BigInteger ba = new BigInteger(ra.Take(16).Concat(Enumerable.Repeat((byte)0, 1)).ToArray()); BigInteger bb = new BigInteger(ra.Skip(16).Take(16).Concat(Enumerable.Repeat((byte)0, 1)).ToArray()); FourierPoint.mulmod(ref a, ref b); ba = (ba * bb) % p; byte[] rbb1 = ba.ToByteArray(); Array.Resize(ref rbb1, 16); byte[] rbb2 = new byte[16]; BitConverter.GetBytes(a.Low).CopyTo(rbb2, 0); BitConverter.GetBytes(a.High).CopyTo(rbb2, 8); for (int k = 16; --k >= 0;) { if (rbb1[k] != rbb2[k]) { return(false); } } } return(true); }
private static void ifft(this FourierPoint[] list) { int n = list.Length; var handle = GCHandle.Alloc(list, GCHandleType.Pinned); try { IntPtr listAddress = handle.AddrOfPinnedObject(); for (int k = 1; k < n; k <<= 1) { FourierPoint.butterflyCore(listAddress, 0, k); FourierPoint wpower = FourierPoint.One; for (int j = k << 1, x = 0; j < n; x++, j += k << 1) { int pos = 0; while ((x & (1 << pos)) != 0) { pos++; } FourierPoint.mulmod(ref wpower, ref FourierPoint.RootsInverters[pos]); FourierPoint.inverseFFTCore(listAddress, j, k, ref wpower); } } } finally { handle.Free(); } }
public static bool UnitTest(int seed) { Random random = new Random(seed); int bits = 17; int n = 1 << bits; FourierPoint[] a0 = new FourierPoint[n]; FourierPoint[] a1 = new FourierPoint[n]; byte[] bytes = new byte[16]; for (int i = n; --i >= 0;) { random.NextBytes(bytes); a0[i] = a1[i] = new FourierPoint(BitConverter.ToUInt64(bytes, 0), BitConverter.ToUInt64(bytes, 8)); } a0.FFT(false); a0.IFFT(false); //var scale = FourierPoint.PowMod(FourierPoint.HalfOne, new FourierPoint((ulong)bits, 0)); for (int i = n; --i >= 0;) { //a0[i] *= scale; a0[i] >>= bits; } for (int i = n; --i >= 0;) { if (a0[i] != a1[i]) { return(false); } } return(true); }
public static void remodP(ref FourierPoint a) { if (a.High == ulong.MaxValue && a.Low >= (1023UL << 54) + 1UL) { a.Low -= (1023UL << 54) + 1UL; a.High = 0; } }
public override bool Equals(object obj) { if (!(obj is FourierPoint)) { return(false); } FourierPoint other = (FourierPoint)obj; return(this == other); }
private static void GroupDigits(ulong[] number, int bitsPerDigit, FourierPoint[] result) { long numberOfDigits = Math.Min(result.Length, (number.LongLength * 64 + bitsPerDigit - 1) / bitsPerDigit); long position = numberOfDigits * bitsPerDigit; for (long i = numberOfDigits; --i >= 0;) { position -= bitsPerDigit; result[i] = new FourierPoint(ReadBits(number, position, bitsPerDigit), 0UL); } }
public static void Multiply(ulong[] input1, ulong[] input2, ulong[] result, int n) { // AsmX64Operations.FastestMultiplication(input1, input2, result, n); // return; int fftBitsPerDigit, fftLog2Size; GetFFTParameters(n, out fftBitsPerDigit, out fftLog2Size); long fftN = 1L << fftLog2Size; //double directComputations = (double)n * n; //double karatsubaComputations = 4.7 * Math.Pow(n, LOG2_3); //double fftComputations = 7.2 * (3.0 * fftLog2Size + 4.0) * fftN; FourierPoint[] number1 = new FourierPoint[fftN]; GroupDigits(input1, fftBitsPerDigit, number1); FourierPoint[] number2 = new FourierPoint[fftN]; GroupDigits(input2, fftBitsPerDigit, number2); //FourierPoint scale = FourierPoint.PowMod(FourierPoint.HalfOne, new FourierPoint((ulong)fftLog2Size, 0UL)); number1.FFT(false); number2.FFT(false); for (int i = number1.Length; --i >= 0;) { FourierPoint point = number1[i]; FourierPoint.mulmod(ref point, ref number2[i]); //FourierPoint.mulmod(ref point, ref scale); point >>= fftLog2Size; number1[i] = point; } number1.IFFT(false); var number1Handle = GCHandle.Alloc(number1, GCHandleType.Pinned); try { FourierPoint.PropagateCarries(number1Handle.AddrOfPinnedObject(), fftBitsPerDigit, number1.Length); } finally { number1Handle.Free(); } UngroupDigits(number1, fftBitsPerDigit, result); }
static FourierPoint() { FourierPoint p = PrimeModulo; p.Low -= 1; FourierPoint halfp = new FourierPoint((p.Low >> 1) | (p.High << 63), p.High >> 1); var fp1 = PowMod(Generator, p); var fp2 = PowMod(Generator, halfp); remodP(ref fp1); remodP(ref fp2); var fp3 = PowMod(Root, new FourierPoint(1UL << 53, 0)); if (fp1 != One || fp2 != MinusOne || fp3 != MinusOne) { throw new InvalidOperationException("Generator does not pass unit test."); } Roots = new FourierPoint[54]; FourierPoint[] inverters = new FourierPoint[Roots.Length]; Roots[Roots.Length - 1] = Root; inverters[Roots.Length - 1] = FourierPoint.PowMod(Root, new FourierPoint(PrimeModulo.Low - 2, PrimeModulo.High)); for (int i = Roots.Length - 1; --i >= 0;) { Roots[i] = Roots[i + 1] * Roots[i + 1]; remodP(ref Roots[i]); inverters[i] = inverters[i + 1] * inverters[i + 1]; remodP(ref inverters[i]); } RootsMultipliers = new FourierPoint[Roots.Length - 1]; RootsInverters = new FourierPoint[Roots.Length - 1]; for (int i = 0; i < RootsMultipliers.Length; i++) { RootsMultipliers[i] = PrimeModulo - Roots[i] * Roots[i + 1]; RootsInverters[i] = PrimeModulo - inverters[i] * inverters[i + 1]; } }
public static extern void PowMod(ref FourierPoint a, ref FourierPoint power);
public static extern void inverseFFTCore(IntPtr number, int startIndex, int n, ref FourierPoint wpower);
public static extern void submod(ref FourierPoint a, ref FourierPoint b);
public static void ShiftRightDirect(ref FourierPoint x, int shift) { x = new FourierPoint((x.Low >> shift) | (x.High << (64 - shift)), x.High >> shift); }
public static extern void butterfly(ref FourierPoint a, ref FourierPoint b);
public static FourierPoint PowMod(FourierPoint a, FourierPoint power) { PowMod(ref a, ref power); return(a); }