Đa thức Cyclotomic


17

Bối cảnh (bỏ qua các định nghĩa)

Euler đã chứng minh một định lý đẹp về các số phức: e ix = cos (x) + i sin (x).

Điều này làm cho định lý của de Moivre dễ dàng chứng minh:

(e ix ) n = e i (nx)

(cos (x) + i sin (x)) n = cos (nx) + i sin (nx)

Chúng ta có thể vẽ các số phức bằng mặt phẳng Euclide hai chiều, với trục hoành biểu thị phần thực và trục dọc biểu thị phần ảo. Theo cách này, (3,4) sẽ tương ứng với số phức 3 + 4i.

Nếu bạn quen thuộc với tọa độ cực, (3,4) sẽ là (5, arctan (4/3)) trong tọa độ cực. Số đầu tiên, r, là khoảng cách của điểm từ gốc tọa độ; số thứ hai, θ, là góc được đo từ trục x dương đến điểm, ngược chiều kim đồng hồ. Kết quả là 3 = r cosθ và 4 = r sinθ. Do đó, chúng ta có thể viết 3 + 4i là r cosθ + ri sinθ = r (cosθ + i sinθ) = re .

Hãy để chúng tôi giải phương trình phức z n = 1, trong đó n là số nguyên dương.

Chúng ta để z = re . Khi đó, z n = r n e inθ . Khoảng cách của z n từ gốc tọa độ là r n và góc là nθ. Tuy nhiên, chúng ta biết rằng khoảng cách 1 từ gốc tọa độ là 1 và góc là 0. Do đó, r n = 1 và nθ = 0. Tuy nhiên, nếu bạn xoay thêm 2π nữa, bạn vẫn kết thúc tại cùng một điểm, bởi vì 2π chỉ là một vòng tròn đầy đủ. Do đó, r = 1 và nθ = 2kπ, cho ta z = e 2ikπ / n .

Chúng tôi giới thiệu lại khám phá của chúng tôi: các giải pháp cho z n = 1 là z = e 2ikπ / n .

Một đa thức có thể được thể hiện dưới dạng gốc của nó. Ví dụ, gốc của x 2 -3x + 2 là 1 và 2, do đó x 2 -3x + 2 = (x-1) (x-2). Tương tự, từ khám phá của chúng tôi ở trên:

Tuy nhiên, sản phẩm đó chắc chắn có chứa rễ của n khác. Ví dụ: lấy n = 8. Các gốc của z 4 = 1 cũng sẽ được bao gồm bên trong các gốc của z 8 = 1, vì z 4 = 1 ngụ ý z 8 = (z 4 ) 2 = 1 2 = 1. Lấy n = 6 làm ví dụ. Nếu z 2 = 1, thì chúng ta cũng sẽ có z 6 = 1. Tương tự, nếu z 3 = 1, thì z 6 = 1.

Nếu chúng ta muốn trích xuất các gốc duy nhất cho z n = 1, chúng ta sẽ cần k và n để chia sẻ không có ước số chung ngoại trừ 1. Hoặc nếu không, nếu chúng chia sẻ một ước số chung d trong đó d> 1, thì z sẽ là (k / d) -th root của z n / d = 1. Sử dụng kỹ thuật trên để viết đa thức về gốc của nó, chúng ta thu được đa thức:

Lưu ý rằng đa thức này được thực hiện bằng cách loại bỏ các gốc của z n / d = 1 với d là ước của n. Chúng tôi cho rằng đa thức trên có hệ số nguyên. Xét LCM của các đa thức dưới dạng z n / d -1 trong đó d> 1 và d chia n. Rễ của LCM chính xác là rễ chúng ta muốn loại bỏ. Vì mỗi thành phần có hệ số nguyên, LCM cũng có hệ số nguyên. Vì LCM chia z n -1, thương số phải là đa thức có hệ số nguyên và thương số là đa thức ở trên.

Các gốc của z n = 1 đều có bán kính 1, do đó chúng tạo thành một vòng tròn. Đa thức biểu thị các điểm của đường tròn duy nhất cho n, do đó, theo một nghĩa nào đó, đa thức tạo thành một phân vùng của vòng tròn. Do đó, đa thức trên là đa thức cyclotomic n-th. (xích lô- = vòng tròn; tom- = để cắt)

Định nghĩa 1

Đa thức cyclotomic n-th, ký hiệu , là đa thức duy nhất với các hệ số nguyên chia x n -1 nhưng không x k -1 cho k <n.

Định nghĩa 2

Các đa thức cyclotomic là một tập hợp các đa thức, một cho mỗi số nguyên dương, sao cho:

trong đó k | n có nghĩa là k chia n.

Định nghĩa 3

Đa thức cyclotomic n-th là đa thức x n -1 chia cho LCM của đa thức có dạng x k -1 trong đó k chia n và k <n.

Ví dụ

  1. Φ 1 (x) = x - 1
  2. Φ 2 (x) = x + 1
  3. Φ 3 (x) = x 2 + x + 1
  4. Φ 30 (x) = x 8 + x 7 - x 5 - x 4 - x 3 + x + 1
  5. Φ 105 (x) = x 48 + x 47 + x 46 - x 43 - x 42 - 2x 41 - x 40 - x 39 + x 36 + x 35 + x 34 + x 33 + x 32 + x 31 - x 28 - x 26 - x 24 - x 22 - x 20 + x 17 + x 16 + x 15 + x 14 + x 13 + x 12 - x9 - x 8- 2x 7 - x 6 - x 5 + x 2 + x + 1

Bài tập

Cho một số nguyên dương n , trả về nđa thức cyclotomic thứ ba như được xác định ở trên, trong một định dạng hợp lý (danh sách các hệ số ieeg được cho phép).

Quy tắc

Bạn có thể trả về số dấu phẩy động / số phức miễn là chúng làm tròn đến giá trị chính xác.

Chấm điểm

Đây là . Câu trả lời ngắn nhất trong byte thắng.

Người giới thiệu


1
Có thể thêm 105 như một bài kiểm tra?
Jonathan Allan

@Jonathan ALLan Tôi không muốn gõ 48 thuật ngữ
Leaky Nun

1
Là điểm không chính xác được phép?
dặm

3
@miles Tôi ghét phao với một niềm đam mê>. <nhưng tôi sẽ bảo vệ cho đến chết quyền sử dụng phao của bạn.
Leaky Nun

1
Chúng ta có thể xuất các số dấu phẩy động phức tạp miễn là chúng mang lại câu trả lời đúng khi làm tròn đến số nguyên / gaussian gần nhất không?
fireflame241

Câu trả lời:


12

Haskell , 120 byte

import Data.Complex
p%a=zipWith(\x y->x-a*y)(p++[0])$0:p
f n=foldl(%)[1][cis(2*pi/fromInteger n)^^k|k<-[1..n],gcd n k<2]

Hãy thử trực tuyến!

Cung cấp một danh sách các phao phức tạp có các mục như 1.0000000000000078 :+ 3.314015728506092e-14do thiếu dấu phẩy. Một phương pháp trực tiếp nhân ra để phục hồi đa thức từ gốc của nó.

Đây fromIntegerlà một sự nhượng bộ lớn đối với hệ thống loại của Haskell. Có một cách tốt hơn. Đề nghị được chào đón. Đối phó với rễ của sự thống nhất một cách tượng trưng cũng có thể làm việc.


Haskell , 127 byte

(h:t)%q|all(==0)t=[]|1>0=h:zipWith(\x y->x-h*y)t q%q
f n=foldl(%)(1:(0<$[2..n])++[-1])[tail$f k++[0,0..]|k<-[1..n-1],mod n k<1]

Hãy thử trực tuyến!

Không nhập khẩu.

Sử dụng công thức

Tính Φ_n (x) bằng cách chia LHS cho mỗi điều khoản khác trong RHS.

Toán tử %thực hiện phép chia trên đa thức, dựa vào phần còn lại bằng không. Số chia được giả sử là monic, và được đưa ra mà không có số 1 đứng đầu, và cũng có các số 0 ở cuối vô hạn để tránh bị cắt cụt khi thực hiện zipWith.


[0,0..]là một byte ngắn hơn repeat 0.
Laikoni

@flawr Chia đa thức. Tôi nghĩ đó là phương pháp tương tự như giải pháp của bạn.
xnor

Trông thật tao nhã, tôi sẽ phải xem xét kỹ hơn vào ngày mai :)
flawr

câu trả lời này khiến tôi muốn học Haskell.
Giuseppe

1
@xnor -1 byte
H.PWiz

7

Toán học, 43 41 byte

Factor[x^#-1]/Times@@#0/@Most@Divisors@#&

Tất nhiên, chúng ta luôn có thể sử dụng tích hợp, nhưng nếu không, điều này chia x n -1 cho Φ k ( x ) (tính toán đệ quy) cho mọi ước số k chính xác của n .

Chúng tôi sử dụng Factorđể có được một đa thức vào cuối. Tôi nghĩ lý do điều này hoạt động là x^#-1các yếu tố trong tất cả các đa thức cyclotomic của ước số của n , và sau đó chúng tôi chia ra những cái chúng tôi không muốn.

-2 byte nhờ Jenny_mathy, viết lại Factorthành chỉ áp dụng cho tử số.


2
Điều đó thật tuyệt! bạn có thể lưu một byte bằng cách sử dụngFactor@
J42161217

@Jenny_mathy Làm điều đó dường như phân tích cú pháp Factor[x^#-1]/Times@@...thay thế; nếu chúng tôi không có dấu ngoặc ở đó, chúng tôi muốn có dấu ngoặc đơn.
Misha Lavrov

1
ok ... nhưng tôi phải nói rằng khi tôi thử nghiệm nó, nó đã cho kết quả đúng ...
J42161217

Nó thật thú vị. Nó có nghĩa là chúng ta có thể lưu một byte khác bằng cách viết nó Factor[x^#-1]/Times@@..., và nó cũng có nghĩa là tôi không biết nó hoạt động như thế nào.
Misha Lavrov

5

MATL , 32 31 27 25 byte

Z\"@:@/]XHxvHX~18L*Ze1$Yn

Đầu ra có thể không phải là số nguyên do không chính xác dấu phẩy động (được phép). Các footer làm tròn cho rõ ràng.

Hãy thử trực tuyến!


4

Haskell , 250 236 233 218 216 byte

Đây là phiên bản dài dòng, (@xnor có thể làm điều đó với gần một nửa số điểm ) nhưng nó được đảm bảo để hoạt động cho bất kỳn miễn là bạn có đủ bộ nhớ, nhưng nó không sử dụng tích hợp để tạo đa thức cyclotomic thứ n. Đầu vào là một số nguyên kích thước tùy ý và đầu ra là một loại đa thức với các hệ số hợp lý (chính xác).

Ý tưởng sơ bộ ở đây là tính toán các đa thức đệ quy. Cho n=1hay ntố nó là tầm thường. Đối với tất cả các số khác, phương pháp này về cơ bản sử dụng công thức từ định nghĩa 2

giải quyết cho . Cảm ơn @ H.PWiz vì khá nhiều byte!

import Math.Polynomial
import Data.Ratio
import NumberTheory
p=powPoly x
q=poly LE
c n|n<2=q[-1,1%1]|isPrime n=sumPolys$p<$>[0..n-1]|1>0=fst$quotRemPoly(addPoly(p n)$q[-1])$foldl1 multPoly[c d|d<-[1..n-1],n`mod`d<1]

Đối với n=105sản lượng này sau đa thức (tôi đã thu dọn tất cả các %1mẫu số):

[1,1,1,0,0,-1,-1,-2,-1,-1,0,0,1,1,1,1,1,1,0,0,-1,0,-1,0,-1,0,-1,0,-1,0,0,1,1,1,1,1,1,0,0,-1,-1,-2,-1,-1,0,0,1,1,1]

Đa thức cho n=15015có thể được tìm thấy ở đây (hệ số lớn nhất là 23).

Hãy thử trực tuyến!


+1không phải là một nội dung.
DJMcMayhem

@flawr Tại sao bạn lại sử dụng Rationals? Nó dường như hoạt động tốt mà không có họ
H.PWiz

Phải không? Tôi đã có vấn đề với quotRemPoly, hãy để tôi thử lại sau đó!
flawr

À, "vấn đề" là nó mang lại Doublehệ số nếu bạn không sử dụng Ratio Integerthay vào đó, điều này có thể gây ra vấn đề rất lớn n.
flawr

Ơ ... tôi không nghĩ đó là vấn đề.
H.PWiz

3

Thạch , 23 byte

R÷
ÆḌÇ€FQœ-@Ç×ı2×ØPÆeÆṛ

Hãy thử trực tuyến!

Đầu ra như một danh sách các hệ số.

Có điểm nổi VÀ không chính xác phức tạp. Footer không làm tròn để làm cho đầu ra đẹp hơn.



2

Toán học, 81 byte

Round@CoefficientList[Times@@(x-E^(2Pi*I#/k)&/@Select[Range[k=#],#~GCD~k<2&]),x]&

2

R , 176 171 139 112 byte

function(n){for(r in exp(2i*pi*(x=1:n)[(g=function(x,y)ifelse(o<-x%%y,g(y,o),y))(x,n)<2]/n))T=c(0,T)-r*c(T,0)
T}

Hãy thử trực tuyến!

Phiên bản đơn giản hơn nhiều; sử dụng một forvòng lặp chứ không phải là a Reduce.



1

CJam ( 52 51 byte)

{M{:K,:!W+K,0-{K\%!},{j($,\:Q,-[{(\1$Qf*.-}*;]}/}j}

Bản demo trực tuyến . Đây là một khối ẩn danh (hàm) lấy một số nguyên trên ngăn xếp và để lại một hệ số hệ số cuối lớn trên ngăn xếp.

Mổ xẻ

{                    e# Define a block
  M{                 e#   Memoised recursion with no base cases.
    :K,:!W+          e#     Store argument in K and build (x^K - 1)
    K,0-{K\%!},      e#     Find proper divisors of K
    {                e#     Foreach proper divisor D...
      j              e#       Recursive call to get Dth cyclotomic poly
      ($,\:Q,-       e#       The cleverest bit. We know that it is monic, and the
                     e#       poly division is simpler without that leading 1, so
                     e#       pop it off and use it for a stack-based lookup in
                     e#       calculating the number of terms in the quotient.
                     e#       Ungolfed this was (;:Q1$,\,-
                     e#       Store the headless divisor in Q.
      [              e#       Gather terms into an array...
        {            e#         Repeat the calculated number of times...
          (\         e#           Pop leading term, which goes into the quotient.
          1$Qf*.-    e#           Multiply Q by that term and subtract from tail.
        }*;          e#         Discard the array of Q,( zeroes. 
      ]
    }/
  }j
}

0

JavaScript (ES6), 337 333 284 ... 252 250 245 242 byte

(v,z=[e=[1,u=0]],g=(x,y)=>y?g(y,x%y):x,h=Math,m=(l,x,p=h.cos(l),q=h.sin(l),i=0)=>x.map(()=>[(i&&(n=x[i-1])[0])-(w=x[i])[0]*p+w[1]*q,(i++&&n[1])-w[1]*p-w[0]*q]))=>{for(;++u<v;z=g(v,u)-1?z:[...m(h.PI*2*u/v,z),e]);return z.map(r=>h.round(r[0]))}

Giải thích (Đã chọn):

z=[e=[1,u=0]]

Khởi tạo z = (1 + 0i) * x ^ 0

g=(x,y)=>y?g(y,x%y):x

Tính toán GCD.

h=Math

Vì tôi cần sử dụng các hàm Math khá nhiều, tôi đã sử dụng một biến khác ở đây.

m=(l,x,p=h.cos(l),q=h.sin(l),i=-1)=>blah blah blah

Phép nhân đa thức.

for(;++u<v;z=g(v,u)-1?z:[...m(h.PI*2*u/v,z),e]);

Công thức được sử dụng là

nhập mô tả hình ảnh ở đây

return z.map(r=>h.round(r[0]))

Nén đầu ra trở lại một mảng số nguyên.

Đầu ra:

Một mảng các số nguyên, với phần tử ở vị trí i đại diện cho hệ số của x ^ i.

Một trong những vấn đề mà JS gặp phải là vì JS không cung cấp thư viện riêng để tính toán các đa thức và số phức, nên chúng cần được thực hiện theo cách giống như mảng.

console.log (phi (105)) đưa ra

Array(49)
 0:  1    1:  1    2:  1    3: -0    4: -0    5: -1    6: -1 
 7: -2    8: -1    9: -1   10:  0   11: -0   12:  1   13:  1 
14:  1   15:  1   16:  1   17:  1   18:  0   19: -0   20: -1 
21:  0   22: -1   23: -0   24: -1   25:  0   26: -1   27: -0 
28: -1   29:  0   30:  0   31:  1   32:  1   33:  1   34:  1 
35:  1   36:  1   37: -0   38: -0   39: -1   40: -1   41: -2 
42: -1   43: -1   44: -0   45: -0   46:  1   47:  1   48:  1 
length: 49
__proto__: Array(0)

337> 333 (-4): Đã thay đổi mã để kiểm tra giá trị không xác định

333> 284 (-49): Thay đổi hàm nhân đa thức vì nó có thể được đơn giản hóa

284> 277 (-7): Đã xóa một số mã dự phòng

277> 265 (-12): Sử dụng 2 biến thay vì mảng 2 phần tử để giảm một số byte trong sử dụng mảng

265> 264 (-1): Sử dụng Array.push () thay vì Array.concat () để giảm 4 byte, nhưng đã thêm 3 cho dấu ngoặc cho vòng lặp for và biến z

264> 263 (-1): Đánh gôn thêm vào lần sửa đổi cuối cùng

263> 262 (-1): Chơi gôn trên vòng lặp for

262> 260 (-2): Bỏ ra mệnh đề if

260> 258 (-2): Kết hợp thêm các khai báo

258> 252 (-6): Được sử dụng lại các tham chiếu mảng

252> 250 (-2): Thay thế một số toán tử đơn nguyên làm toán tử nhị phân

250> 245 (-5): Di chuyển gia số trong Array.map () sang tham chiếu cuối cùng của bộ đếm để xóa byte

245> 242 (-3): Sử dụng cú pháp trải rộng thay vì Array.push ()

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.