最近《高等代數》剛學了域的概念,突然想起曾經這么的一個問題,找了許久才找到以前用的那種方法,覺得還是挺有啟發性的。
那么問題就是給定正整數 \(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\)。
我們構造多項式
即構造一個定義系數在 \(\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]);
}