こんにちは!
既に持っている単純な再帰的 FFT 実装に基づいて NTT アルゴリズムを開発しようとしています。
次のコードを考えてみcoefficients
ましょう ( ' 長さm
は正確に 2 のべき乗です)。
/// <summary>
/// Calculates the result of the recursive Number Theoretic Transform.
/// </summary>
/// <param name="coefficients"></param>
/// <returns></returns>
private static BigInteger[] Recursive_NTT_Skeleton(
IList<BigInteger> coefficients,
IList<BigInteger> rootsOfUnity,
int step,
int offset)
{
// Calculate the length of vectors at the current step of recursion.
// -
int n = coefficients.Count / step - offset / step;
if (n == 1)
{
return new BigInteger[] { coefficients[offset] };
}
BigInteger[] results = new BigInteger[n];
IList<BigInteger> resultEvens =
Recursive_NTT_Skeleton(coefficients, rootsOfUnity, step * 2, offset);
IList<BigInteger> resultOdds =
Recursive_NTT_Skeleton(coefficients, rootsOfUnity, step * 2, offset + step);
for (int k = 0; k < n / 2; k++)
{
BigInteger bfly = (rootsOfUnity[k * step] * resultOdds[k]) % NTT_MODULUS;
results[k] = (resultEvens[k] + bfly) % NTT_MODULUS;
results[k + n / 2] = (resultEvens[k] - bfly) % NTT_MODULUS;
}
return results;
}
複雑なFFTで機能しましBigInteger
た(複雑な数値型に置き換えます(私は自分で持っていました))。統一の原始根を見つける手順を適切に変更したにもかかわらず、ここでは機能しません。
おそらく、問題は次のとおりです:渡されたパラメーターには、もともと次の順序で 1 の複素根のrootsOfUnity
最初の半分しか含まれていませんでした:m
omega^0 = 1, omega^1, omega^2, ..., omega^(n/2)
これらの 3 行のコードでは次のようになっているため、これで十分でした。
BigInteger bfly = (rootsOfUnity[k * step] * resultOdds[k]) % NTT_MODULUS;
results[k] = (resultEvens[k] + bfly) % NTT_MODULUS;
results[k + n / 2] = (resultEvens[k] - bfly) % NTT_MODULUS;
私はもともと、任意のレベルの再帰 (任意のn
andの場合i
) で、 unity の複素根であるという事実を利用しました-omega^(i) = omega^(i + n/2)
。
しかし、その性質は明らかに有限体では成立しません。しかし、根の前半だけを計算できる類似のものはありますか?
または、サイクルを から まで拡張し、n/2
すべての1 乗根をn
事前に計算する必要がありますか?m
たぶん、このコードには他の問題がありますか? ...
事前にどうもありがとうございました!