Polinomial sikotomik

17

Latar Belakang (lewati ke definisi)

Euler membuktikan teorema yang indah tentang bilangan kompleks: e ix = cos (x) + i sin (x).

Ini membuat teorema de Moivre mudah dibuktikan:

(e ix ) n = e i (nx)

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

Kita dapat memplot bilangan kompleks menggunakan bidang Euclidean dua dimensi, dengan sumbu horizontal mewakili bagian nyata dan sumbu vertikal mewakili bagian imajiner. Dengan cara ini, (3,4) akan sesuai dengan bilangan kompleks 3 + 4i.

Jika Anda terbiasa dengan koordinat polar, (3,4) akan menjadi (5, arctan (4/3)) dalam koordinat polar. Angka pertama, r, adalah jarak titik dari titik asal; angka kedua, θ, adalah sudut yang diukur dari sumbu x positif ke titik, berlawanan arah jarum jam. Akibatnya, 3 = r cosθ dan 4 = r sinθ. Oleh karena itu, kita dapat menulis 3 + 4i sebagai r cosθ + ri sinθ = r (cosθ + i sinθ) = re .

Mari kita memecahkan persamaan kompleks z n = 1, di mana n adalah bilangan bulat positif.

Kami membiarkan z = re . Kemudian, z n = r n e inθ . Jarak z n dari titik asal adalah r n , dan sudutnya adalah nθ. Namun, kita tahu bahwa jarak 1 dari titik asal adalah 1, dan sudutnya adalah 0. Oleh karena itu, r n = 1 dan nθ = 0. Namun, jika Anda memutar 2π lebih, Anda masih berakhir pada titik yang sama, karena 2π hanya lingkaran penuh. Oleh karena itu, r = 1 dan nθ = 2kπ, memberi kita z = e 2ikπ / n .

Kami menyatakan kembali penemuan kami: solusi untuk z n = 1 adalah z = e 2ikπ / n .

Polinomial dapat diekspresikan dalam hal akarnya. Misalnya, akar x 2 -3x + 2 adalah 1 dan 2, jadi x 2 -3x + 2 = (x-1) (x-2). Demikian pula dari penemuan kami di atas:

Namun, produk itu tentu mengandung akar n lain. Misalnya, ambil n = 8. Akar z 4 = 1 juga akan dimasukkan ke dalam akar z 8 = 1, karena z 4 = 1 menyiratkan z 8 = (z 4 ) 2 = 1 2 = 1. Ambil n = 6 sebagai contoh. Jika z 2 = 1, maka kita juga akan memiliki z 6 = 1. Demikian juga, jika z 3 = 1, maka z 6 = 1.

Jika kita ingin mengekstrak akar unik ke z n = 1, kita perlu k dan n untuk tidak berbagi pembagi umum kecuali 1. Atau, jika mereka berbagi pembagi umum d di mana d> 1, maka z akan menjadi (k / d) -th root dari z n / d = 1. Dengan menggunakan teknik di atas untuk menulis polinom dalam hal akarnya, kita memperoleh polinomial:

Perhatikan bahwa polinomial ini dilakukan dengan menghilangkan akar z n / d = 1 dengan d menjadi pembagi n. Kami mengklaim bahwa polinomial di atas memiliki koefisien bilangan bulat. Pertimbangkan LCM polinomial dalam bentuk z n / d -1 di mana d> 1 dan d membagi n. Akar LCM adalah persis akar yang ingin kita hapus. Karena setiap komponen memiliki koefisien integer, LCM juga memiliki koefisien integer. Karena LCM membagi z n -1, hasil bagi harus polinomial dengan koefisien integer, dan hasil bagi adalah polinomial di atas.

Akar z n = 1 semuanya memiliki jari-jari 1, sehingga mereka membentuk lingkaran. Polinomial mewakili titik-titik lingkaran yang unik ke n, jadi dalam arti polinomial membentuk partisi dari lingkaran. Oleh karena itu, polinomial di atas adalah polinomial siklomomik ke-n. (cyclo- = lingkaran; tom- = untuk memotong)

Definisi 1

Polinomial siklotomik ke-n, dilambangkan , adalah polinomial unik dengan koefisien bilangan bulat yang membagi x n -1 tetapi bukan x k -1 untuk k <n.

Definisi 2

Polinomial siklomomik adalah sekumpulan polinomial, satu untuk setiap bilangan bulat positif, sehingga:

dimana k | n berarti k membagi n.

Definisi 3

Polinomial siklomomik ke-n adalah polinomial xn -1 dibagi dengan LCM polinomial dalam bentuk xk -1 di mana k membagi n dan k <n.

Contohnya

  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 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

Tugas

Dengan bilangan bulat positif n, kembalikan npolinomial siklomomik ke-10 seperti yang didefinisikan di atas, dalam format yang masuk akal (mis. Daftar koefisien koefisien diperbolehkan).

Aturan

Anda dapat mengembalikan angka floating point / kompleks selama mereka membulatkan ke nilai yang benar.

Mencetak gol

Ini adalah . Jawaban terpendek dalam byte menang.

Referensi

Biarawati Bocor
sumber
1
Mungkin menambahkan 105 sebagai ujian?
Jonathan Allan
@ JonathanAllan Saya tidak ingin mengetikkan 48 istilah
Leaky Nun
1
Apakah ketidakakuratan floating-point diperbolehkan?
mil
3
@miles Saya benci mengapung dengan penuh semangat>. <Tapi saya akan membela sampai mati hak Anda untuk menggunakan pelampung.
Leaky Nun
1
Bisakah kita menampilkan angka floating point yang kompleks selama mereka menghasilkan jawaban yang benar ketika dibulatkan ke integer / integer gaussian terdekat?
fireflame241

Jawaban:

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]

Cobalah online!

Memberikan daftar pelampung kompleks yang memiliki entri seperti 1.0000000000000078 :+ 3.314015728506092e-14karena ketidaklancaran float. Metode penggandaan langsung untuk memulihkan polinomial dari akarnya.

Ini fromIntegeradalah konsesi besar untuk sistem tipe Haskell. Pasti ada cara yang lebih baik. Saran diterima. Berurusan dengan akar persatuan secara simbolis juga mungkin berhasil.


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]

Cobalah online!

Tanpa impor.

Menggunakan formula

Menghitung Φ_n (x) dengan membagi LHS dengan masing-masing istilah lain dalam RHS.

Operator %melakukan pembagian polinomial, mengandalkan sisanya nol. Pembagi dianggap monic, dan diberikan tanpa angka 1, dan juga dengan nol trailing tak terbatas untuk menghindari pemotongan ketika melakukan zipWith.

Tidak
sumber
[0,0..]byte lebih pendek dari repeat 0.
Laikoni
@ flawr Membagi polinomial. Saya pikir ini metode yang sama dengan solusi Anda.
xnor
Terlihat sangat elegan, aku harus melihat lebih dekat besok :)
flawr
jawaban ini membuat saya ingin belajar Haskell.
Giuseppe
1
@xnor -1 byte
H.PWiz
7

Mathematica, 43 41 byte

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

Tentu saja, kita selalu dapat menggunakan built-in, tetapi jika tidak, ini akan membagi x n -1 oleh Φ k ( x ) (dihitung secara rekursif) untuk setiap pembagi k yang tepat dari n .

Kami menggunakan Factoruntuk mendapatkan polinomial di akhir. Saya pikir alasan ini berhasil adalah karena x^#-1faktor - faktor ke dalam semua polinomial siklotomik pembagi n , dan kemudian kita membagi yang tidak kita inginkan.

-2 byte terima kasih kepada Jenny_mathy, menulis ulang Factorhanya berlaku untuk pembilang.

Misha Lavrov
sumber
2
Ini bagus! Anda dapat menyimpan byte dengan menggunakanFactor@
J42161217
@Jenny_mathy Melakukan hal itu sepertinya diuraikan sebagai Factor[x^#-1]/Times@@...gantinya; jika kami tidak memiliki tanda kurung di sana, kami ingin tanda kurung.
Misha Lavrov
1
ok ... tapi saya harus mengatakan bahwa ketika saya mengujinya, itu memberikan hasil yang tepat ...
J42161217
Itu menarik. Itu berarti kita dapat menyimpan byte lain dengan menulisnya Factor[x^#-1]/Times@@..., dan itu juga berarti saya tidak tahu cara kerjanya.
Misha Lavrov
5

MATL , 32 31 27 25 byte

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

Output mungkin non-integer karena ketidaktepatan floating-point (yang diizinkan). Footer melakukan pembulatan untuk kejelasan.

Cobalah online!

Luis Mendo
sumber
4

Haskell , 250 236 233 218 216 byte

Ini adalah versi verbose, (@xnor dapat melakukannya di hampir setengah skor ) tetapi dijamin akan bekerja nselama Anda memiliki cukup memori, tetapi tidak menggunakan builtin untuk menghasilkan polinomial siklomomik ke-n. Input adalah bilangan bulat ukuran arbitrer dan outputnya adalah tipe polinomial dengan koefisien rasional (tepat).

Ide kasar di sini adalah menghitung polinomial secara rekursif. Untuk n=1atau nprima itu sepele. Untuk semua angka lainnya, pendekatan ini pada dasarnya menggunakan rumus dari definisi 2

dipecahkan untuk . Terima kasih @ H.Wiz untuk cukup banyak 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]

Untuk n=105ini menghasilkan polinomial berikut (saya merapikan semua %1penyebut):

[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]

Polinomial n=15015dapat ditemukan di sini (koefisien terbesar adalah 23).

Cobalah online!

cacat
sumber
+1karena tidak menjadi builtin.
DJMcMayhem
@ flawr Mengapa Anda menggunakan Rationals? Tampaknya berfungsi dengan baik tanpa mereka
H.PWiz
Melakukannya? Saya punya masalah dengan quotRemPoly, izinkan saya coba lagi kalau begitu!
flawr
Ah, "masalahnya" adalah bahwa ia menghasilkan Doublekoefisien jika Anda tidak menggunakannya Ratio Integer, yang mungkin menyebabkan masalah untuk sangat (sangat) besar n.
flawr
Eh ... Saya kira itu bukan masalah.
H.PWiz
3

Jelly , 23 byte

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

Cobalah online!

Keluaran sebagai daftar koefisien.

Memiliki floating point dan ketidakakuratan yang kompleks. Footer melakukan pembulatan untuk membuat output lebih cantik.

fireflame241
sumber
3

J , 36 bytes

1+//.@(*/)/@(,.~-)_1^2*%*i.#~1=i.+.]

Cobalah online!

Menggunakan formula

rumus

Ada beberapa ketidakakuratan floating-point, tetapi diizinkan.

mil
sumber
2

Mathematica, 81 byte

Round@CoefficientList[Times@@(x-E^(2Pi*I#/k)&/@Select[Range[k=#],#~GCD~k<2&]),x]&
J42161217
sumber
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}

Cobalah online!

Versi yang jauh lebih sederhana; menggunakan forloop daripada a Reduce.

Giuseppe
sumber
2

Pari / GP , 8 byte

Built-in.

polcyclo

Cobalah online!


Pari / GP , 39 byte, tanpa built-in

f(n)=p=x^n-1;fordiv(n,d,d<n&&p/=f(d));p

Menggunakan rumus:

Φn(x)=xn-1d<nd|nΦd(x).

Cobalah online!

alephalpha
sumber
1

CJam ( 52 51 byte)

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

Demo online . Ini adalah blok anonim (fungsi) yang mengambil integer pada stack dan meninggalkan array koefisien endian besar pada stack.

Pembedahan

{                    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
}
Peter Taylor
sumber
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]))}

Penjelasan (Dipilih):

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

Inisialisasi z = (1 + 0i) * x ^ 0

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

Perhitungan GCD.

h=Math

Karena saya perlu menggunakan fungsi Matematika cukup banyak, saya menggunakan variabel lain di sini.

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

Penggandaan polinomial.

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

Formula yang digunakan adalah

masukkan deskripsi gambar di sini

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

Kompres kembali output ke array integer.

Output:

Array bilangan bulat, dengan elemen pada posisi i mewakili koefisien x ^ i.

Salah satu masalah yang dimiliki JS adalah karena JS tidak menyediakan pustaka asli untuk perhitungan pada polinomial dan bilangan kompleks, mereka perlu diimplementasikan dengan cara seperti array.

console.log (phi (105)) memberi

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): Mengubah kode untuk memeriksa nilai yang tidak ditentukan

333> 284 (-49): Mengubah fungsi multiplikasi polinomial karena dapat disederhanakan

284> 277 (-7): Menghapus beberapa kode redundan

277> 265 (-12): Gunakan 2 variabel, bukan array 2-elemen untuk menjatuhkan beberapa byte dalam penggunaan array

265> 264 (-1): Gunakan Array.push () alih-alih Array.concat () untuk mengurangi 4 byte, tetapi menambahkan 3 untuk kurung for-loop dan variabel z

264> 263 (-1): Lebih lanjut bermain golf pada amandemen terakhir

263> 262 (-1): Golf pada for for loop

262> 260 (-2): Keluar dari klausa if

260> 258 (-2): Selanjutnya menggabungkan deklarasi

258> 252 (-6): Bermain golf dengan menggunakan kembali referensi array

252> 250 (-2): Ganti beberapa operator unary sebagai operator biner

250> 245 (-5): Pindahkan kenaikan di Array.map () ke referensi penghitung terakhir untuk menghapus byte

245> 242 (-3): Gunakan sintaksis alih-alih Array.push ()

Shieru Asakoto
sumber