Siklotomik polinom


17

Arka plan (tanımlara atla)

Euler karmaşık sayılarla ilgili güzel bir teorem kanıtladı: e ix = cos (x) + i sin (x).

Bu de Moivre teoreminin kanıtlanmasını kolaylaştırır:

(e ix ) n = e i (nx)

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

İki boyutlu Öklid düzlemini kullanarak karmaşık sayıları çizebiliriz, yatay eksen gerçek kısmı temsil eder ve dikey eksen hayali kısmı temsil eder. Bu şekilde, (3,4) karmaşık sayı 3 + 4i'ye karşılık gelir.

Kutupsal koordinatlara aşina iseniz, (3,4) kutupsal koordinatlarda (5, arktan (4/3)) olur. İlk sayı, r, noktanın başlangıç ​​noktasından uzaklığıdır; ikinci sayı, θ, pozitif x ekseninden noktaya saat yönünün tersine ölçülen açıdır. Sonuç olarak, 3 = r cosθ ve 4 = r sinθ. Bu nedenle, r cosθ + ri sinθ = r (cosθ + i sinθ) = re olarak 3 + 4i yazabiliriz .

Şimdi n n pozitif bir tamsayı olan z n = 1 karmaşık denklemini çözelim .

Biz z = re iθ olsun . Ardından, z n = r n e inθ . Z n'nin başlangıç ​​noktasından uzaklığı r n'dir ve açı nθ'dir. Bununla birlikte, başlangıç ​​noktasından 1 uzaklığının 1 ve açının 0 olduğunu biliyoruz. Bu nedenle, r n = 1 ve nθ = 0. Ancak, 2π daha fazla döndürürseniz, yine aynı noktada kalırsınız, çünkü 2π sadece tam bir çemberdir. Bu nedenle, r = 1 ve nθ = 2kπ, bize z = e 2ikπ / n verir .

Keşifimizi yeniden başlatıyoruz : z n = 1'in çözümleri z = e 2ikπ / n .

Bir polinomun kökleri açısından ifade edilebilir. Örneğin, x 2 -3x + 2'nin kökleri 1 ve 2'dir, bu nedenle x 2 -3x + 2 = (x-1) (x-2). Benzer şekilde, yukarıdaki keşfimizden:

Ancak, bu ürün kesinlikle diğer n köklerini içeriyordu. Örneğin, n = 8 alın. Z kökleri 4 = 1, Z kökleri içine dahil olacak 8 z beri = 1 4 = 1 Z ima 8 = (z 4 ) 2 = 1 2 , örnek olarak = çekme 1. n = 6. Z 2 = 1 olsaydı, o zaman z 6 = 1 olurdu . Benzer şekilde, z 3 = 1 ise, z 6 = 1'dir.

Eğer z n = 1'e özgü kökleri çıkarmak istiyorsak, 1 dışında hiçbir ortak böleni paylaşmak için k ve n'ye ihtiyacımız olurdu. Aksi takdirde, d> 1 olduğunda ortak böleni d paylaşırlarsa, z (k / d) -z n / d = 1'in kökü . Polinomu kökleri açısından yazmak için yukarıdaki tekniği kullanarak, polinomu elde ederiz:

Bu polinomun z n / d = 1 köklerinin çıkarılmasıyla yapıldığını , d'nin n'nin bölücüsü olduğunu unutmayın. Yukarıdaki polinomun tamsayı katsayıları olduğunu iddia ediyoruz. Polinomların LCM'sini, d> 1 ve d'nin n'ye böldüğü z n / d -1 şeklinde düşünün . LCM'nin kökleri tam olarak kaldırmak istediğimiz köklerdir. Her bileşen tamsayı katsayılarına sahip olduğundan, LCM ayrıca tamsayı katsayılarına sahiptir. LCM bölme z yana N -1, bölüm tamsayı katsayılı bir polinom olmalıdır, ve bölüm üzerinde polinomlarıdır.

Z n = 1 köklerinin yarıçapı 1'dir, bu nedenle bir daire oluştururlar. Polinom, n'ye özgü çemberin noktalarını temsil eder, bu yüzden bir anlamda polinomlar çemberin bir bölümünü oluşturur. Bu nedenle, yukarıdaki polinom n'inci siklotomik polinomdur. (siklo- = daire; tom- = kesmek için)

Tanım 1

N'inci devirli polinom ile gösterilen , bu bölme x tamsayı katsayılı benzersiz polinom N -1, ancak X k -1 k <n.

Tanım 2

Siklotomik polinomlar, her pozitif tamsayı için bir tane olan bir dizi polinomdur, öyle ki:

nerede k | n, k bölünmeleri anlamına gelir

Tanım 3

N. Siklotomik polinom, polinom x n- l'in, k'nin n ve k <n'yi böldüğü x k -1 formundaki polinomların LCM'sine bölünmesiyle elde edilir .

Örnekler

  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

Görev

Pozitif bir tamsayı verildiğinde n, nyukarıda tanımlandığı gibi -th siklotomik polinomunu makul bir biçimde döndürün (ieeg katsayılar listesine izin verilir).

kurallar

Kayan nokta / karmaşık sayıları doğru değere yuvarladıkları sürece döndürebilirsiniz.

puanlama

Bu . Bayt cinsinden en kısa cevap kazanır.

Referanslar


1
Belki bir test olarak 105 ekleyin?
Jonathan Allan

@JonathanAllan 48 terim yazmak istemiyorum
Leaky Nun

1
Kayan nokta yanlışlıklarına izin veriliyor mu?
mil

3
miles şamandıralardan tutkuyla nefret ediyorum>. <ama ölümüne şamandıra kullanma hakkını savunacağım.
Leaky Nun

1
En yakın tam sayı / gauss tamsayısına yuvarlandığında doğru yanıtı verdikleri sürece karmaşık kayan nokta sayıları çıkarabilir miyiz?
fireflame241

Yanıtlar:


12

Haskell , 120 bayt

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]

Çevrimiçi deneyin!

1.0000000000000078 :+ 3.314015728506092e-14Şamandıra yanlışlığı nedeniyle girişleri olan karmaşık şamandıraların bir listesini verir . Polinomu köklerinden kurtarmak için doğrudan çarpma yöntemi.

fromIntegerHaskell'ın tip sistemine büyük bir ödün olduğunu. Daha iyi bir yol olmalı. Öneriler bekliyoruz. Birliğin kökleriyle sembolik olarak çalışmak da işe yarayabilir.


Haskell , 127 bayt

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

Çevrimiçi deneyin!

İthalat yok.

Formülü kullanır

LHS'yi RHS'deki diğer terimlerin her birine bölerek Φ_n (x) değerini hesaplar.

Operatör %, kalanların sıfır olmasına bağlı olarak polinomlar üzerinde bölünme yapar. Bölenin monik olduğu varsayılır ve önde 1 olmadan ve ayrıca yaparken kesmeyi önlemek için sonsuz takip sıfırları ile verilir zipWith.


[0,0..]bir bayt daha kısadır repeat 0.
Laikoni

@flawr Polinomları böler. Bence çözümünüzle aynı yöntem.
xnor

Çok zarif görünüyor, yarın daha yakından bakmak
zorundayım

bu cevap Haskell'i öğrenmek istememi sağlıyor.
Giuseppe

1
@xnor -1 byte
H.PWiz

7

Mathematica, 43 41 bayt

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

Tabii ki, her zaman yerleşik olanı kullanabiliriz, ancak kullanmazsak, bu x'i böler n -1 Φ tarafından k ( x (yinelemeli hesaplanan)) her öz bölen için k bir n .

FactorSonunda bir polinom elde etmek için kullanıyoruz . Bence bunun işe x^#-1yaramasının sebebi , n'nin bölücülerinin tüm siklotomik polinomlarına faktörler olmasıdır ve sonra istemediklerimizi böleriz.

-2 bayt, Jenny_mathy sayesinde Factorsadece pay için geçerli yeniden yazma .


2
Bu harika! kullanarak bir bayt kaydedebilirsinizFactor@
J42161217

@Jenny_mathy Bunu yapmak ayrışıyor gibi görünüyor Factor[x^#-1]/Times@@...; orada parantezler olmasaydı parantez isterdik.
Misha Lavrov

1
tamam ... ama bunu test ettiğimde doğru sonuçları verdiğini
söylemeliyim

İlginç. Bu, başka bir baytı yazarak kaydedebileceğimiz anlamına gelir Factor[x^#-1]/Times@@...ve aynı zamanda nasıl çalıştığına dair hiçbir fikrim yok demektir.
Misha Lavrov

5

MATL , 32 31 27 25 bayt

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

Kayan nokta yanlışlıkları (izin verilen) nedeniyle çıktı tamsayı olmayabilir. Altbilgi netlik için yuvarlama yapar.

Çevrimiçi deneyin!


4

Haskell , 250 236 233 218 216 bayt

Bu kapsamlı bir versiyon, (@xnor skorun neredeyse yarısında yapabilir ) ancak herhangi biri için çalışacağı garanti edilir.n , ancak yeterli belleğe sahip olduğunuz sürece , ancak n. Siklotomik polinomu oluşturmak için bir yerleşik kullanılmaz. Girdi keyfi bir boyut tamsayısıdır ve çıktı (kesin) rasyonel katsayıları olan bir polinom tipidir.

Buradaki kaba fikir, polinomları özyineli olarak hesaplar. İçin n=1veyan asal önemsiz. Diğer tüm sayılar için bu yaklaşım temel olarak tanım 2'den formül kullanır.

için çözüldü . Bir sürü bayt için @ H.PWiz'e teşekkürler!

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]

İçin n=105polinomun sonrasında bu verimleri (I tidied tüm%1 paydalar):

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

İçin polinom n=15015bulunabilir burada (en büyük katsayı 23'tür).

Çevrimiçi deneyin!


+1yerleşik olmadığın için.
DJMcMayhem

@flawr Neden kullanıyorsunuz Rationals?
Onlarsız

Yapar? Sorun yaşadım quotRemPoly, o zaman tekrar deneyeyim!
flawr

Ah "sorun" çok (çok) büyük için sorunlara neden olabilir, yerine Doublekullanmazsanız katsayılar vermesiydi . Ratio Integern
flawr

Eh ... Bunun bir sorun olduğunu düşünmüyorum.
H.PWiz

3

Jöle , 23 bayt

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

Çevrimiçi deneyin!

Katsayıların bir listesi olarak çıktılar.

Kayan nokta VE karmaşık yanlışlıklar vardır. Altbilgi, çıktıyı daha güzel hale getirmek için yuvarlama yapar.


3

J , 36 bayt

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

Çevrimiçi deneyin!

Formülü kullanır

formula

Bazı kayan nokta yanlışlıkları vardır, ancak buna izin verilir.


2

Mathematica, 81 bayt

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

2

R , 176 171 139 112 bayt

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}

Çevrimiçi deneyin!

Çok daha basit sürüm; a foryerine bir döngü kullanır Reduce.



1

CJam ( 52 51 bayt)

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

Çevrimiçi demo . Bu, yığın üzerinde bir tamsayı alan ve yığın üzerinde büyük-endian bir katsayı dizisi bırakan anonim bir bloktur (işlev).

teşrih

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

(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]))}

Açıklama (Seçilmiş):

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

Sıfırla z = (1 + 0i) * x ^ 0

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

GCD hesabı.

h=Math

Math işlevlerini çok fazla kullanmam gerektiğinden, burada başka bir değişken kullandım.

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

Polinom çarpımı.

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

Kullanılan formül

enter image description here

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

Çıktıyı bir tamsayı dizisine geri sıkıştırın.

Çıktılar:

İ konumunda konum x x i katsayısını temsil eden bir tamsayı dizisi.

JS'nin sahip olduğu problemlerden biri, JS polinomlar ve karmaşık sayılar üzerinde hesaplamalar için yerel kütüphane sağlamadığından, diziye benzer bir şekilde uygulanması gerektiğidir.

console.log (phi (105)) verir

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): Tanımlanmamış değeri kontrol etme kodu değiştirildi

333> 284 (-49): Polinom çarpma fonksiyonunu değiştirdi çünkü basitleştirilebilir

284> 277 (-7): Bazı gereksiz kodlar silindi

277> 265 (-12): Dizi kullanımında bazı baytları bırakmak için 2 öğeli dizi yerine 2 değişken kullanın

265> 264 (-1): 4 baytı azaltmak için Array.concat () yerine Array.push () kullanın, ancak for-döngüsü ayraçları ve z değişkeni için 3 ekledi

264> 263 (-1): Son değişiklikle ilgili daha fazla golf yapıldı

263> 262 (-1): for döngüsünde golf oynadı

262> 260 (-2): if fıkrasının yerine geçti

260> 258 (-2): Beyanları daha da birleştirdi

258> 252 (-6): Dizi referanslarının yeniden kullanılması durumunda golf

252> 250 (-2): Bazı tekli operatörleri ikili operatör olarak değiştir

250> 245 (-5): Baytları kaldırmak için Array.map () içindeki artışı sayacın son referansına taşıyın

245> 242 (-3): Array.push () yerine forma sözdizimini kullan

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.