一种简单方法构造 n 元有限域

最近《高等代数》刚学了域的概念,突然想起曾经这么的一个问题,找了许久才找到以前用的那种方法,觉得还是挺有启发性的。

那么问题就是给定正整数 \(n\ge 2\),需要构造一个 \(n\) 元有限域,也就是说我们给出一个 \(n\times n\) 的加法表和 \(n\times n\) 的乘法表。

不难得知,难点在于选择恰当的运算规则使得乘法逆存在。

Case 1

\(n\) 是质数,那么有如下构造 \(\mathbb{Z}_p=S=\{0,1,2,\dots,p-1\}\)

  • \(\forall a,b\in S,a\oplus b=a+b-[\dfrac{a+b}{p}]\times p \in S\)
  • \(\forall a,b\in S,a\otimes b=ab-[\dfrac{ab}{p}]\times p \in S\)

根据费马小定理,乘法逆可以定义为 \(a^{-1}=a^{p-2}\)

Case 2

\(n\) 含有至少两个质因子。我们断言,这种情况下不存在 \(n\) 元的有限域。

Case 3

剩余的情况,则 \(n=p^k\),其中 \(p\in prime,k\ge 2\)

我们构造多项式

\[f(x)=\sum_{i=0}^{k-1}a_ix^i \quad (a_i=0,1,2,\dots,p-1) \]

即构造一个定义系数在 \(\mathbb{Z}_p\) 上的度数不超过 \(p-1\) 的多项式域 \(G\),而该域的大小恰好为 \(p^k\)

我们可以通过 \(p\) 进制分解(或其他方式)将 \(S=\{0,1,2,\dots,n-1\}\)\(G\) 形成双射。

现在我们定义 \(G\) 的运算,考虑到需要保证其度数不超过 \(p-1\),我们先取一个系数在 \(\mathbb{Z}_p\) 上的度数为 \(p\) 的不可约多项式 \(M(x)\)

  • \(\forall f(x),g(x)\in G,f(x)\oplus g(x)=f(x)+g(x) \in S\)
  • \(\forall f(x),g(x)\in G,r(x)=f(x)\otimes g(x)=f(x)g(x)\mod M(x)\),即多项式的带余除法结果,\(\partial(r(x))<\partial(M(x))=p\),故 \(r(x)\in S\)

与此同时,多项式 \(I(x)=1\) 即为乘法幺元。
由于 \(M(x)\) 是不可约多项式,可以证明任取一个 \(G\) 中的元素 \(f\),均存在一个 \(g\in G\) 使 \(f(x)\otimes g(x) =I(x)\)。(存在多项式乘法逆)

需要注意,例如在 \(\mathbb{Z}_2\) 上,\(x^2+1\) 并不是不可约多项式,因为 \((x+1)(x+1)=x^2+1\);而 \(x^2+x+1\) 满足;在 \(\mathbb{Z}_3\) 上,可取 \(x^2+x+2\) 为不可约多项式。

至此,我们完成了构造。

附1

实现上述得到的一个 \(9\) 元域(加法表 和 乘法表)

0 1 2 3 4 5 6 7 8
1 2 0 4 5 3 7 8 6
2 0 1 5 3 4 8 6 7
3 4 5 6 7 8 0 1 2
4 5 3 7 8 6 1 2 0
5 3 4 8 6 7 2 0 1
6 7 8 0 1 2 3 4 5
7 8 6 1 2 0 4 5 3
8 6 7 2 0 1 5 3 4

0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8
0 2 1 6 8 7 3 5 4
0 3 6 7 1 4 5 8 2
0 4 8 1 5 6 2 3 7
0 5 7 4 6 2 8 1 3
0 6 3 5 2 8 7 4 1
0 7 5 8 3 1 4 2 6
0 8 4 2 7 3 1 6 5

附2

参考代码(手动寻找不可约多项式,只能处理少数固定大小的 \(n\)

#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;

typedef vector<int> poly;
int n, p, k;
poly d, av;
vector<poly> a;

void dfs(int x)
{
	if(x < 0)
	{
		a.emplace_back(av);
		return;
	}
	for(int j = 0; j < p; ++j)
		av[x] = j, dfs(x - 1);
}

int calc(const poly& a)
{
	int res = 0;
	for(int i = 0, q = 1; i < k; ++i)
		res += a[i] * q, q = q * p;
	return res;
}

poly operator + (const poly&a, const poly&b)
{
	poly c = a;
	for(int i = 0; i < k; ++i) c[i] = (a[i] + b[i]) % p;
	return c;
}

poly operator * (const poly&a, const poly&b)
{
	poly c(k + k - 1);
	for(int i = 0; i < k; ++i)
		for(int j = 0; j < k; ++j)
			c[i + j] += a[i] * b[j];
	for(int i = 2 * k - 2; i >= k; --i)
		for(int j = 0; j < k; ++j)
			c[i + j - k] -= c[i] * d[j];
	for(int i = 0; i < k; ++i)
		c[i] = (c[i] % p + p) % p;
	c.resize(k);
	return c;
}

int main()
{
	freopen("1.out","w",stdout);
	scanf("%d", &n);
	for(int x = 2; x <= n; ++x)
		if(n % x == 0)
		{
			p = x;
			int y = n;
			while(y % x == 0) y /= x, ++k;
			if(y != 1)
				return puts("-1"), 0;
			break;
		}
	puts("0");
	if(k == 1)
	{
		for(int x = 0; x < n; ++x)
			for(int y = 0; y < n; ++y)
				printf("%d%c", (x + y) % n, " \n"[y + 1 == n]);
		for(int x = 0; x < n; ++x)
			for(int y = 0; y < n; ++y)
				printf("%d%c", (x * y) % n, " \n"[y + 1 == n]);
		return 0;
	}
	if(k == 2)
	{
		if(p != 5 && p != 11)
			d = poly{-1, 1, 1};
		else
			d = poly{1, 1, 1};
	}
	else if(k == 3)
	{
		if(p == 3)
			d = poly{-1, 0, 1, 1};
		else
			d = poly{1, 1, 0, 1};
	}
	else if(k == 4)
		d = poly{1, 1, 1, 1, 1};
	else if(k == 5)
		d = poly{1, 1, -1, -1, 0, 1};
	else if(k == 7)
		d = poly{1, 1, -1, -1, 0, 0, 0, 1};
	else if(k == 8)
		d = poly{1, 1, -1, 0, 0, 0, 0, -1, 1};
	av = poly(k);
	dfs(k - 1);
	for(int x = 0; x < n; ++x)
		for(int y = 0; y < n; ++y)
			printf("%d%c", calc(a[x] + a[y]), " \n"[y + 1 == n]);
	for(int x = 0; x < n; ++x)
		for(int y = 0; y < n; ++y)
			printf("%d%c", calc(a[x] * a[y]), " \n"[y + 1 == n]);
}
posted @ 2021-09-16 22:15  bestwyj  阅读(1649)  评论(0编辑  收藏  举报