NTT算法中素数的选取

     设这个素数为N,N-1必须要可以被小于n的2的次方整除,因为经常需要除以2的次方长度,必须要可以被整除,所以N可以表示为m*2^k+1的长度,后面我试了一下其他2^k>=ntt长度的素数,发现结果并不正确,后来才发现N还必须大于最大卷积结果N*max{a[i]}*{b[i]},否则mod就会产生错误.后面我又看了一下本原元的存在性证明,那个大佬用一句话就证明了,说是什么群论里的基础知识.没看懂顿时觉得自己对数论很小白.感觉编码课上好像学过什么本原元的,但是没有要证明什么的.好像只有一些结论没有过程.

    不过我觉得还是FFT适用的场景更多,虽然精度上有一点问题.

    贴一个两三个月前写的NTT题,路过需要的可以参考一下(hihocoder 1388,内含fft板子)

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#pragma warning(disable:4996)
using namespace std;
const int g = 3;
const long long int mymod = 31525197391593473LL;
int revg;
const double pi = acos(-1.0);
const int bign = 100033;
struct complex
{
	double r, v;
	complex()
	{ 
		r = 0.0;
		v = 0.0;
	}


	complex(double r1, double v1)
	{
		r = r1;
		v = v1;
	}
	complex operator+(const complex& ano)
	{
		return complex(r + ano.r,  v + ano.v);
	}
	complex operator-(const complex& ano)
	{
		return complex(r - ano.r, v - ano.v);
	}
	complex operator*(const complex& ano)
	{
		return complex(r * ano.r - v * ano.v, r * ano.v + v * ano.r);
	}
	complex operator/(double r1)
	{
		return complex(r / r1, v / r1);
	}
}a[4*bign],b[4*bign];


long long int mymul(long long int ta, long long int tb)
{
	long long int res = 0;
	for (;tb; tb >>= 1)
	{
		if (tb & 1)
			res = (res + ta) % mymod;
		ta = (ta << 1) % mymod;
	}
	return res;
}


long long mul(long long x, long long y) {
	return (x * y - (long long)(x / (long double)mymod * y + 1e-3) * mymod + mymod) % mymod;
}
long long int quickpow(long long ta, long long int tb)
{
	long long res = 1;
	for (; tb; tb >>= 1)
	{
		if (tb & 1)
			res = mul(res, ta);
		ta = mul(ta, ta);
	}
	return res;
}
int rev(int num, int len)
{
	int ans = 0;
	for (int i = 1,j = 0; j<len; i<<=1,j++)
	{
		if (i & num)
		{
			ans += (1<<(len - 1 - j));
		}
	}
	return ans;
}


void NTT(long long int c[], int len, int on)
{
	int tlen = (1 << len);


	for (int i = 0; i < tlen; i++)
	{
		int j = rev(i, len);
		if (j > i)
			swap(c[i], c[j]);
	}


	//long long int tg = g;
	//if (on == -1)
	//	tg = quickpow(g, mymod - 2);
	for (int i = 2; i <= tlen; i <<= 1)
	{
		long long int wn = quickpow(g,(mymod-1)/i);
		if (on == -1)
			wn = quickpow(wn, mymod-2);
		for (int j = 0; j < tlen; j += i)
		{
			long long int w = 1;
			for (int k = j; k < j + i / 2; k++)
			{
				long long int u = c[k];
				long long int v = mul(w , c[k + i / 2]);
				c[k] = (u + v) % mymod;
				c[k + i / 2] = (u - v + mymod) % mymod;
			//	long long int oldw = w;
				w = mul(w, wn);
			}
		}
	}
	if (on == -1)
	{
		//for (int i = 0; i < tlen / 2; i++)
		//{
		//	swap(c[i], c[tlen - i - 1]);
		//}
		for (int i = 0; i < tlen; i++)
			c[i] = mul(c[i], quickpow(tlen, mymod - 2));
	}
}


void FFT(complex c[], int len, int on)
{	
	int tlen = (1 << len);
	
	for (int i = 0; i < tlen; i++)
	{
		int j = rev(i,len);
		if (j > i)
			swap(c[i], c[j]);
	}


	for (int i = 2; i <= tlen; i <<= 1)
	{
		complex wn(cos(2*pi/i),on * sin(2*pi/i));
		for (int j = 0; j < tlen; j += i)
		{
			complex w(1,0);
			for (int k = j; k < j + i/2; k++)
			{
				complex u =  c[k];
				complex v = (w * c[k + i / 2]);
				c[k] = u + v;
				c[k + i / 2] = u - v;
				w = w * wn;
			}
		}
	}
	if (on == -1)
	{
		for (int i = 0; i < tlen; i++)
		{
			c[i].r /= tlen;
			c[i].v /= tlen;
		}
	}
}
long long int a1[4 * bign], b1[4 * bign];
int main()
{
	int T;
	//printf("%lld\n", quickpow(g, mymod - 1));
	scanf("%d", &T);
	
	while (T--)
	{
		int n;
		long long int ans = 0;
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
		{
			int x;
			scanf("%d", &x);
			ans += 1ll * x * x;
			a1[i] = x;
			a1[i + n] = a1[i];
		}
		for (int i = n - 1; i >= 0; i--)
		{
			int x;
			scanf("%d", &x);
			ans += 1ll * x * x;
			b1[i] = x;
		}
		int len = 0;
		int j;
		for (j = 1; j < 2 * n; j <<= 1,len++);
		for (int i = n; i < j; i++)
			b1[i] = 0;
		for (int i = 2 * n; i < j; i++)
			a1[i] = 0;
		NTT(a1, len, 1);
		NTT(b1, len, 1);
		for (int i = 0; i < j; i++)
			a1[i] = mul(a1[i],b1[i])%mymod;
		NTT(a1, len, -1);
		long long int tmax = 0;
		for (int i = n - 1; i < 2 * n - 1; i++)
		{
			long long int tmp = a1[i];
			if (tmp > tmax)
				tmax = tmp;
		}
		printf("%lld\n", ans - 2* tmax);
	}
}


/*
5
5
1000000 1000001 1000002 1000003 1000004
1000003 1000004 1000000 1000001 1000002
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 基于FPGA(现场可编程门阵列)的有限域NTT(快速数论变换)算法设计与实现是一种在硬件上实现数论变换算法的方法。NTT是一种高效的离散傅里叶变换(DFT)算法,其在数字信号处理和错误检测使用广泛。 基于FPGA的有限域NTT算法设计与实现需要考虑以下几个方面: 1. 算法设计:首先,需要设计FPGA上的有限域NTT算法。这涉及到选择适当的参数和有限域运算方法,如模乘和模加。还需要确定具体的NTT算法实现,如蝶形计算和位重排列等。 2. FPGA架构设计:根据算法的特点和需求,设计FPGA的硬件架构。可以使用并行化、流水线和并行处理等技术来提高算法的计算效率。 3. RTL设计与开发:在FPGA上实现有限域NTT算法需要进行RTL(寄存器传输级)设计与开发。这涉及到编写硬件描述语言(如VHDL或Verilog)代码,描述有限域NTT算法的功能、数据路径和控制逻辑等。 4. 时钟频率与资源利用:在设计与优化RTL代码时需要考虑时钟频率和FPGA资源的利用。通过合理的时钟设计和资源分配,可以提高算法的运行速度和资源效率。 5. 测试与验证:设计与实现完成后,需要对FPGA上的有限域NTT算法进行测试与验证。可以使用仿真工具和FPGA开发板进行功能验证和性能评估,确保算法的正确性和性能满足需求。 基于FPGA的有限域NTT算法设计与实现可以在硬件上实现高效的数论变换,提高计算性能和资源利用率。这种方法可以在数字信号处理、通信系统和加密算法等领域得到广泛应用。 ### 回答2: 有限域NTT算法是一种基于FPGA的高效算法实现,可以在有限域上进行快速数论变换。该算法通常被应用于数字信号处理、多项式乘法和离散对数等问题的解决。 在设计与实现NTT算法时,首先需要确定有限域的大小和NTT变换的参数。通常情况下,有限域的大小为2的幂次方,如16、32、64等,NTT变换的参数由有限域的大小和素数决定。 然后,需要设计并实现FPGA上的基于NTT算法的模块。该模块包括NTT变换的核心操作,如乘法、加法和求模运算,以及控制模块用于控制数据流和时序。在设计,需要合理利用FPGA的并行计算能力,以提高计算速度和效率。 在具体实现,需要编写硬件描述语言(如Verilog或VHDL)代码,描述NTT算法模块的功能和结构。该代码需要考虑时序、数据宽度和数据流控制等问题,并进行仿真和调试以保证功能正确性。 接下来,需要对设计的FPGA模块进行合成、布局和布线,生成最终的bit文件以加载到FPGA芯片。这一过程需要考虑时序约束和资源利用率,以保证实际实现的性能和可靠性。 最后,进行实际测试和评估。可以通过输入一组测试数据,对NTT算法的运行时间和资源利用率进行评估。同时,可以通过与其他算法进行对比,验证NTT算法的优越性和实用性。 总之,基于FPGA的有限域NTT算法设计与实现,需要经过算法设计、硬件描述语言编写、综合布局布线和测试评估等多个步骤。通过合理的设计和优化,可以实现高效的NTT算法,并在数字信号处理等领域应用发挥重要作用。 ### 回答3: 基于FPGA的有限域NTT(Number Theoretic Transform)算法设计与实现主要包括以下几个方面。 首先,有限域NTT算法的设计。NTT是一种快速傅立叶变换(FFT)的变种,广泛应用于数字信号处理和数据压缩等领域。在设计有限域NTT算法时,需要根据具体需求选择合适的有限域和NTT变换参数,并实现相应的模乘、模加等基本运算。 其次,FPGA的架构设计。FPGA具备灵活性高、可重构性强的特点,适用于实现有限域NTT算法。在架构设计,需要考虑算法的并行性、模块化设计、资源利用率等因素,以充分发挥FPGA的性能优势。 接下来,算法实现的优化。对于有限域NTT算法,存在多种优化策略,如乘法器并行优化、时钟频率优化、存储器优化等。对于FPGA实现而言,还可考虑数据流水线、流式存储器等技术,进一步提高算法的性能和效率。 最后,验证和测试。在完成有限域NTT算法的设计和实现后,需要对其进行验证和测试,确保算法的正确性和可靠性。可以采用仿真验证和硬件测试相结合的方式,对算法进行全面的检测与评估。 综上所述,基于FPGA的有限域NTT算法设计与实现是一个复杂的过程,需要综合考虑算法设计、FPGA架构、优化和验证等方面。通过科学的设计和合理的实现策略,可以实现高效、稳定的有限域NTT算法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值