Belirli bir sayının bölen sayısını hesaplamak için algoritma


177

Belirli bir sayının bölen sayısını hesaplamak için en uygun algoritma (performans açısından) hangisidir?

Sahte kod veya bazı örneklere bağlantı sağlayabilirseniz harika olur.

EDIT: Tüm cevaplar çok yardımcı oldu, teşekkür ederim. Atkin Elekini uyguluyorum ve sonra Jonathan Leffler'in belirttiği şeye benzer bir şey kullanacağım. Justin Bozonier tarafından gönderilen linkte ne istediğim hakkında daha fazla bilgi var.


Verilen reqs faktör sayısı ile geliyor belirsiz. Benzersiz olmayan asal bölenlerin sayısını arıyorsanız tahmin ediyorum çünkü eğer kod istemiyorsanız sadece faktöre sayı bir ve 2 ise başka bir şey ise her zaman 1 dönmek için bir program yazın. 0 bir değişikliğe ihtiyaç duyabilir ...
Justin Bozonier

@sker: Bölenlere ihtiyacınız olan bir dizi Değer var mı? Faktörleri hesaplamanın birçok yolu vardır ve her yöntem belirli bir aralığa daha uygundur.
Ande Turner

2
İşte ilgili ilginç bir sorun projecteuler.net/problem=12
daniloquio

1
Düzenlenen Wikipedia makalesinden bile saf Atkin Elek asla büyük bir pratik sınırlara kadar maksimum tekerlek faktörlü Eratosthenes Elekinden daha hızlı olmayacaktır ve sayfa bölümlü versiyonlar SoE'nin lehine olacaktır (bkz. Çalışmalarının SoA'yı daha hızlı kanıtladığı yaygın yanlış İnternet bilgisi, ancak bunu kanıtlamak için kullanılan SoE'nin optimizasyonunu yapay olarak sınırladılar.Ayrı açıklama için SoA cevabımı görün
GordonBGood

Yanıtlar:


78

Dmitriy, Atkin Eleklerinin asal listeyi oluşturmasını isteyeceğiniz konusunda haklı ama bunun tüm konuyu hallettiğine inanmıyorum. Artık bir primer listesine sahip olduğunuza göre, bu primerlerden kaçının bölen olarak hareket ettiğini (ve ne sıklıkta) görmeniz gerekir.

İşte algo için bazı python Buraya bakın ve "Konu: matematik - ihtiyaç bölücüler algoritması" için arama yapın. Ancak listedeki öğelerin sayısını döndürmek yerine saymanız yeterlidir.

İşte matematikle ne yapmanız gerektiğini tam olarak açıklayan bir Dr. Math .

Esasen, numaranızın n:
n = a^x * b^y * c^z
(a, b ve c'nin n'nin ana bölenleri olduğu ve x, y ve z, bölenin kaç kez tekrarlandığı) olup olmadığına bağlıdır.
(x + 1) * (y + 1) * (z + 1).

Düzenleme: BTW, a, b, c, vb bulmak için doğru anlıyorsam açgözlü bir algo ne tutarları yapmak isteyeceksiniz. En büyük ana bölenle başlayın ve başka bir çarpma n sayısını geçinceye kadar kendi kendine çarpın. Ardından bir sonraki en düşük faktöre ve bir önceki asalın ^ geçerli asal ile çarpılma sayısının katına geçin ve bir sonraki n'yi geçinceye kadar asal ile çarpmaya devam edin ... vb. ve bu sayıları yukarıdaki formüle uygulayın.

Algo açıklamamdan% 100 emin değilim, ancak bu değilse benzer bir şey.


1
Çok sayıda faktörü çarpanlara ayırıyorsanız , asal listeye bakmak bile istemezsiniz . Tüm olasılıkları mümkün olduğunca çabuk ortadan kaldırmak istiyorsunuz! Daha fazla bilgi için cevabımı görün.
user11318

Bunun 2 yıl önce olduğunun farkındayım, ama python algo bağlantınız koptu, şimdi nerede olduğunu biliyor musunuz?
jb.

2
Yani n = (a^x * b^y * c^z)-(x + 1) * (y + 1) * (z + 1)kural
SIslam

1
@Shashank'ın dediği gibi, "EDIT:" bölümündeki algoritma yanlış: diyelim ki n = 45 = 3 * 3 * 5. En büyük ana bölen 5'tir, ancak bunu n'yi aşana kadar tek başına çoğaltmak, algoritmanın faktör 5'in 2 kopyasına sahip olduğunu bildirmesine neden olur (5 * 5 = 25 <45'ten beri).
j_random_hacker

1
'Elek Elek' en iyi O (N / log (log (N))) çalışma zamanı karmaşıklığına sahiptir . 1 ... Sqrt (n) 'den olası tüm bölücülerin kaba kuvvet kontrolü O (Sqrt (N)) çalışma zamanının karmaşıklığına göre çok daha üstündür. Bu cevap nasıl kabul edildi?
le_m

47

Bir var çok Atkin ait elek daha faktoring daha teknikleri. Örneğin 5893 faktörünü hesaba katmak istediğimizi varsayalım. Peki onun sqrt 76.76 ... Şimdi 5893 karelerin bir ürünü olarak yazmaya çalışacağız. Kuyu (77 * 77 - 5893) = 36, 6 kare, yani 5893 = 77 * 77 - 6 * 6 = (77 + 6) (77-6) = 83 * 71. Bu işe yaramasaydı, 78 * 78 - 5893'ün mükemmel bir kare olup olmadığına bakardık. Ve bunun gibi. Bu teknikle, n'nin karekökü yakınındaki faktörleri, bireysel primleri test etmekten çok daha hızlı bir şekilde test edebilirsiniz. Büyük primerleri elek ile ayırmak için bu tekniği birleştirirseniz, sadece elekten daha iyi bir faktoring yöntemine sahip olacaksınız.

Ve bu, geliştirilen çok sayıda teknikten sadece bir tanesidir. Bu oldukça basit. Eliptik eğrilere dayalı çarpanlara ayırma tekniklerini anlamanız için yeterli sayıda teori öğrenmeniz uzun zaman alacaktır. (Var olduklarını biliyorum. Onları anlamıyorum.)

Bu nedenle, küçük tamsayılarla uğraşmazsanız, bu sorunu kendim çözmeye çalışmam. Bunun yerine , zaten yüksek verimli bir çözümü uygulanmış olan PARI kütüphanesi gibi bir şey kullanmanın bir yolunu bulmaya çalışırdım . Bununla 124321342332143213122323434312213424231341 gibi 40 basamaklı bir sayıyı yaklaşık .05 saniyede çarpanlarına ayırabilirim. (Çarpanlarına ayırma, merak ettiyseniz, 29 * 439 * 1321 * 157907 * 284749 * 33843676813 * 4857795469949. Atkin elekini kullanarak bunu çözmediğinden oldukça eminim.)


1
Tekniğin çok zekisin, ama sayının kaç faktörü olduğunu söylemiyor, değil mi?
sker

23
Asal çarpanlara ayırdıktan sonra, kaç faktörün olduğunu anlamak basittir. Asal faktörlerin p1, p2, ..., pk olduğunu ve m1, m2, ..., mk kez tekrarlandığını varsayalım. Sonra (1 + m1) (1 + m2) ... (1 + mk) faktörleri var.
user11318

İlginç bir elek ikinci dereceden elektir . Bu sayı teorisini kullanır - kuadratik kongrüanslar ve bazı lineer cebirler. Üniversitede 2. sınıf teori dersinde kullanabileceğim kadar çok şey öğrendim.
Tanner

33

@Yasky

Bölücülerinizin işlevinde, mükemmel kareler için düzgün çalışmadığı yönünde bir hata vardır.

Deneyin:

int divisors(int x) {
    int limit = x;
    int numberOfDivisors = 0;

    if (x == 1) return 1;

    for (int i = 1; i < limit; ++i) {
        if (x % i == 0) {
            limit = x / i;
            if (limit != i) {
                numberOfDivisors++;
            }
            numberOfDivisors++;
        }
    }

    return numberOfDivisors;
}

6
İ = 0 olduğunda (x% i) sıfıra bölmeye neden olmaz mı? i = 1.
rhu

@rhu 0'ı kontrol etmek yine de anlamsızdır, çünkü 0 herhangi bir sayının faktörü değildir.
EJoshuaS - Monica

29

Atkin elekinin gidilecek yol olduğunu kabul etmiyorum, çünkü [1, n] 'deki her sayıyı ilkeliğe göre kontrol etmek, sayıyı bölümlere göre azaltmaktan daha uzun sürebilir.

İşte biraz hackier olmasına rağmen genellikle çok daha hızlı olan bazı kodlar:

import operator
# A slightly efficient superset of primes.
def PrimesPlus():
  yield 2
  yield 3
  i = 5
  while True:
    yield i
    if i % 6 == 1:
      i += 2
    i += 2
# Returns a dict d with n = product p ^ d[p]
def GetPrimeDecomp(n):
  d = {}
  primes = PrimesPlus()
  for p in primes:
    while n % p == 0:
      n /= p
      d[p] = d.setdefault(p, 0) + 1
    if n == 1:
      return d
def NumberOfDivisors(n):
  d = GetPrimeDecomp(n)
  powers_plus = map(lambda x: x+1, d.values())
  return reduce(operator.mul, powers_plus, 1)

ps Bu sorunu çözmek için python kodu çalışıyor.


11

İşte düz bir O (sqrt (n)) algoritması. Bunu proje eulerini çözmek için kullandım

def divisors(n):
    count = 2  # accounts for 'n' and '1'
    i = 2
    while i ** 2 < n:
        if n % i == 0:
            count += 2
        i += 1
    if i ** 2 == n:
        count += 1
    return count

ama sayıyı neden daima 2 arttırıyorsunuz? ... uyguladığınız bir teorem var mı?
SummerCode

3
çünkü sadece sqrt (n) 'ye kadar koşturuyorsunuz. Örneğin: 36'nın tüm bölenlerini bulmaya çalışıyorsanız - 2'den 6'ya kadar sayacaksınız. 1 & 36,2 & 18, 3 & 12, 4 & 9, 6,6'nın tüm bölen olduğunu ve çift olarak geldiğini biliyorsunuz.
Antony Thomas

2
çok teşekkürler Anthony, şimdi anladım: D! küçük bir zeyilname: bence sqrt (n) değerini ayrı ayrı ele almalıdır, çünkü şimdilik bir yerine iki kez dikkate alıyor, sanırım
SummerCode

O (sqrt (n)) çok kötü olmasa da, optimal değildir. asal faktör ayrışmasının hesaplanması çok daha hızlı yapılabilir ve bölen sayısını hesaplamak için yeterlidir.
le_m

Her yinelemede, i²'yi hesaplamanız gerekir, i'yi √n ile karşılaştırmak daha hızlı olmaz mı (sadece bir kez hesaplanır)?
Yukulélé

10

Bu ilginç soru göründüğünden çok daha zor ve cevaplanmadı. Soru 2 çok farklı soruya ayrılabilir.

1 verilen N, N'nin ana faktörlerinin L listesini bulun

2 L verilen, benzersiz kombinasyon sayısını hesaplayın

Şimdiye kadar gördüğüm tüm cevaplar # 1'e atıfta bulunuyor ve bunun çok büyük sayılar için izlenebilir olmadığını belirtmiyorum. Orta boyutlu N, hatta 64 bit sayılar için kolaydır; muazzam N için, faktoring problemi "sonsuza dek" sürebilir. Ortak anahtar şifrelemesi buna bağlıdır.

2. soru daha fazla tartışmaya ihtiyaç duyuyor. L yalnızca benzersiz sayılar içeriyorsa, n öğeden k nesneleri seçmek için birleştirme formülünü kullanarak basit bir hesaplamadır. Aslında, k'yi 1'den sizeof'e (L) değiştirirken formülün uygulanmasından elde edilen sonuçları toplamalısınız. Bununla birlikte, L genellikle birden çok primerin birden fazla oluşumunu içerecektir. Örneğin, L = {2,2,2,3,3,5}, N = 360'ın çarpanlarına ayırmasıdır. Şimdi bu problem oldukça zor!

2. öğenin yeniden düzenlenmesi, k öğelerini içeren koleksiyon C'nin verildiği şekilde, a öğesinin 'kopyaları ve b öğesinin b' kopyaları vs. vardır. 1 ila k-1 öğeden kaç tane benzersiz kombinasyon vardır? Örneğin, {2}, {2,2}, {2,2,2}, {2,3}, {2,2,3,3} 'ün her biri bir kez ve yalnızca L = {2,2 , 2,3,3,5}. Bu tür benzersiz her alt koleksiyon, alt koleksiyondaki öğeleri çarparak N'nin benzersiz bir bölenidir.


İşte 2. çok benzer bir sorun için bazı sözde kod bağlantısıdır answers.google.com/answers/threadview/id/392914.html
mR_fr0g

3
Soru # 2'nin iyi bilinen bir çözümü var. {P_i, k_i} çarpanlarına ayırmak için, burada çokluklu p_ibir sayının asal çarpanıdır, bu sayının k_itoplam bölen sayısıdır (k_1+1)*(k_2+1)*...*(k_n+1). Sanırım bunu şimdiye kadar biliyorsun ama burada rastgele bir okuyucu varsa bunu yararına yazıyorum.
Ness Ness

9

Sorunuzun cevabı büyük ölçüde tamsayı boyutuna bağlıdır. Küçük sayılar, örneğin 100 bit'den daha az ve ~ 1000 bit sayılar (kriptografide kullanılanlar gibi) için yöntemler tamamen farklıdır.


6

SADECE bir satır
Sorunuz hakkında çok dikkatli düşündüm ve son derece verimli ve performansa uygun bir kod parçası yazmaya çalıştım Belirli bir sayının tüm bölenlerini ekrana yazdırmak için sadece bir kod satırına ihtiyacımız var! (gcc ile derlerken -std = c99 seçeneğini kullanın)

for(int i=1,n=9;((!(n%i)) && printf("%d is a divisor of %d\n",i,n)) || i<=(n/2);i++);//n is your number

bölenlerin sayısını bulmak için aşağıdaki çok hızlı işlevi kullanabilirsiniz (1 ve 2 dışındaki tüm tamsayılar için doğru şekilde çalışın)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    return counter;
}

veya verilen sayıyı bölen olarak ele alırsanız (1 ve 2 dışındaki tüm tamsayılar için doğru şekilde çalışır)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    return ++counter;
}

NOT: yukarıdaki iki işlev, sayı 1 ve 2 hariç tüm pozitif tamsayı sayısı için doğru çalışır, bu nedenle 2'den büyük tüm sayılar için işlevseldir, ancak 1 ve 2'yi kapatmanız gerekiyorsa, aşağıdaki işlevlerden birini kullanabilirsiniz (biraz Yavaş)

int number_of_divisors(int n)
{
    int counter,i;
    for(counter=0,i=1;(!(n%i) && (counter++)) || i<=(n/2);i++);
    if (n==2 || n==1)
    {
    return counter;
    }
    return ++counter;
}

VEYA

int number_of_divisors(int n)
{
    int counter,i;
for(counter=0,i=1;(!(i==n) && !(n%i) && (counter++)) || i<=(n/2);i++);
    return ++counter;
}

küçük güzel :)


5

Atkin eleği, belirli bir tamsayıya kadar tüm asal sayıları veren Eratosthenes eleklerinin optimize edilmiş bir versiyonudur. Daha fazla ayrıntı için bunu Google'da yapabilmeniz gerekir.

Bu listeye sahip olduğunuzda, tam bir bölen olup olmadığını görmek için numaranızı her asal alana bölmek basit bir konudur (yani, kalan sıfırdır).

Bir sayı (n) için bölenleri hesaplayan temel adımlar [bu gerçek koddan dönüştürülen sözde kod bu yüzden hatalar tanıtmadım umuyoruz]:

for z in 1..n:
    prime[z] = false
prime[2] = true;
prime[3] = true;

for x in 1..sqrt(n):
    xx = x * x

    for y in 1..sqrt(n):
        yy = y * y

        z = 4*xx+yy
        if (z <= n) and ((z mod 12 == 1) or (z mod 12 == 5)):
            prime[z] = not prime[z]

        z = z-xx
        if (z <= n) and (z mod 12 == 7):
            prime[z] = not prime[z]

        z = z-yy-yy
        if (z <= n) and (x > y) and (z mod 12 == 11):
            prime[z] = not prime[z]

for z in 5..sqrt(n):
    if prime[z]:
        zz = z*z
        x = zz
        while x <= limit:
            prime[x] = false
            x = x + zz

for z in 2,3,5..n:
    if prime[z]:
        if n modulo z == 0 then print z

5

Bunu deneyebilirsiniz. Biraz acayip, ama oldukça hızlı.

def factors(n):
    for x in xrange(2,n):
        if n%x == 0:
            return (x,) + factors(n/x)
    return (n,1)

2
Bu işlev makul bir süre içinde n'nin bir ana faktör ayrışması sağlarken, a) optimal değildir ve b) OP'nin sorusuna göre belirli bir sayının bölen sayısını hesaplamaz
le_m 13:07

Ve özyineleme nedeniyle büyük sayılar için çalışmaz
whackamadoodle3000

Her ne kadar bu optimal olmasa da, faktörleri saymak yerine , aslında onları listeliyor , bunun basitliği ve güzelliği şaşırtıcı ve oldukça hızlı. ^^
Gaurav Singhal

5

Asal çarpanlara ayırdıktan sonra bölen sayısını bulmanın bir yolu vardır. Her bir faktördeki üslerin her birine bir tane ekleyin ve üsleri bir araya getirin.

Örneğin: 36 Ana Faktorizasyon: 2 ^ 2 * 3 ^ 2 Bölenler: 1, 2, 3, 4, 6, 9, 12, 18, 36 Bölen Sayısı: 9

Her üsse bir tane ekleyin 2 ^ 3 * 3 ^ 3 Üsleri çarpın: 3 * 3 = 9


3

Bir çözümü taahhüt etmeden önce, Elek yaklaşımının tipik bir durumda iyi bir cevap olmayabileceğini düşünün.

Bir süre önce bir ana soru vardı ve bir zaman testi yaptım - en azından asal değerin kaba kuvvetten daha yavaş olup olmadığını belirleyen 32 bit tamsayılar için. Devam eden iki faktör vardır:

1) Bir insan bir bölünme yapmak için biraz zaman alırken, bilgisayarda çok hızlıdır - yanıtı arama maliyetine benzer.

2) Bir ana tablonuz yoksa, tamamen L1 önbelleğinde çalışan bir döngü yapabilirsiniz. Bu onu daha hızlı yapar.


3

Bu etkili bir çözümdür:

#include <iostream>
int main() {
  int num = 20; 
  int numberOfDivisors = 1;

  for (int i = 2; i <= num; i++)
  {
    int exponent = 0;
    while (num % i == 0) {
        exponent++; 
        num /= i;
    }   
    numberOfDivisors *= (exponent+1);
  }

  std::cout << numberOfDivisors << std::endl;
  return 0;
}

2

Bölenler muhteşem bir şey yaparlar: tamamen bölünürler. Bir sayı için bölen sayısını kontrol etmek istiyorsanız n, tüm spektrumu yaymak açıkça gereksizdir 1...n. Bunun için derinlemesine bir araştırma yapmadım, ancak Project Euler'in 12 numaralı Üçgen Sayılar problemini çözdüm . 500'den fazla bölücü testi için benim çözüm 309504 mikrosaniye (~ 0.3s) için koştu. Çözüm için bu bölen fonksiyonunu yazdım.

int divisors (int x) {
    int limit = x;
    int numberOfDivisors = 1;

    for (int i(0); i < limit; ++i) {
        if (x % i == 0) {
            limit = x / i;
            numberOfDivisors++;
        }
    }

    return numberOfDivisors * 2;
}

Her algoritmaya göre zayıf bir nokta var. Bunun asal sayılara karşı zayıf olduğunu düşündüm. Ancak üçgen sayılar yazdırılmadığından, amacına kusursuz bir şekilde hizmet etti. Profilimden, bence oldukça iyi oldu.

Mutlu tatiller.


1
Buradaki ilk yinelemede
0'a bölünürdünüz

ne yazık ki değil. ++ i, i ++ 'dan farklıdır (sıfıra bölme hatasıyla
sonuçlanır

PHP fonksiyonunuzu yazdım ve çalıştırdım - işte ne aldım - i.minus.com/iKzuSXesAkpbp.png
barfoon

garip bir nedenden dolayı, bu benim için kusursuz çalıştı. Ah, benim hatam. başlangıç numberOfDivisorsve yineleyici 1'de; Bu sıfır hata ile bölme kurtulmak gerekir
iGbanam

1
Algoritmanız mükemmel kareler için çalışmıyor. Örneğin, x = 4 girişi için 4 döndürür, çünkü 2'yi iki kez sayar ... 1, 2, 2, 4. Yanıt 3: 1,2,4
Michael

1

Burada açıklanan Atkin Elekini istiyorsunuz: http://en.wikipedia.org/wiki/Sieve_of_Atkin


1
Bu size verilen sayının altındaki primerleri getirecektir - ancak bu primerlerin bölen olacağının garantisi yok mu? (Ben bir şey eksik sürece)
Andrew Edgecombe

Buradan, N'yi eşit olarak bölen tüm
primerlerin

1
Hızlı bir sıçrama olabilir, ancak tüm primerlerin <sqrt (N) test edilmesi, ne kadar verimli bulursanız olun, hala kötü bir faktoring tekniğidir. Bunu iyileştirmenin birçok yolu var.
user11318

Asalları test etmek O (N), zor kısmı olan asalları bulmak. Ancak, etotostenlerin optimize edilmemiş elekleri ile bile, bir saniyenin altında birkaç milyonun altındaki tüm primerleri bulabilirsiniz. Bu herhangi bir 64b sayısını kapsıyor ve eminim burada kripto seviyesi
faktörlerini

1

asal sayı yöntemi burada çok açıktır. P [], sq = sqrt (n) değerine eşit veya daha küçük asal sayı listesidir;

for (int i = 0 ; i < size && P[i]<=sq ; i++){
          nd = 1;
          while(n%P[i]==0){
               n/=P[i];
               nd++;
               }
          count*=nd;
          if (n==1)break;
          }
      if (n!=1)count*=2;//the confusing line :D :P .

     i will lift the understanding for the reader  .
     i now look forward to a method more optimized  .

1

Sayı teorisi ders kitapları bölen sayma işlevi tau olarak adlandırılır. İlk ilginç gerçek, çarpımsal olmasıdır. τ (ab) = τ (a) τ (b), a ve b'nin ortak bir faktörü olmadığında. (Kanıt: a ve b'nin her bir bölen çifti, ab'nin ayrı bir bölenini verir).

Şimdi pa üssü için τ (p ** k) = k + 1 (p'nin gücü) olduğuna dikkat edin. Böylece τ (n) 'yi çarpanlarına ayırma işleminden kolayca hesaplayabilirsiniz.

Bununla birlikte, büyük sayıların çarpanlarına ayrılması yavaş olabilir (RSA kriyoprafisinin güvenliği, çarpanlarına ayırmanın zor olduğu iki büyük primerin ürününe bağlıdır). Bu optimize edilmiş algoritmayı önerir

  1. Numaranın asal olup olmadığını test edin (hızlı)
  2. Öyleyse, geri dönün 2
  3. Aksi takdirde, sayıyı çarpanlarına ayırın (birden çok büyük asal faktör varsa yavaş)
  4. Çarpanlara ayırma işleminden τ (n) değerini hesaplama

1

Aşağıdaki, belirli bir sayının bölen sayısını bulmak için bir C programıdır.

Yukarıdaki algoritmanın karmaşıklığı O (sqrt (n)) dir.

Bu algoritma, mükemmel kare olmayan sayının yanı sıra mükemmel kare olmayan sayılar için de doğru şekilde çalışacaktır.

Döngünün üst sınırının, algoritmanın en verimli olması için sayının kareköküne ayarlandığını unutmayın.

Üst sınırı ayrı bir değişkente saklamanın da zaman kazandırdığını, for döngüsünün koşul bölümünde sqrt işlevini çağırmamalısınız, bu da hesaplama zamanınızdan tasarruf etmenizi sağlar.

#include<stdio.h>
#include<math.h>
int main()
{
    int i,n,limit,numberOfDivisors=1;
    printf("Enter the number : ");
    scanf("%d",&n);
    limit=(int)sqrt((double)n);
    for(i=2;i<=limit;i++)
        if(n%i==0)
        {
            if(i!=n/i)
                numberOfDivisors+=2;
            else
                numberOfDivisors++;
        }
    printf("%d\n",numberOfDivisors);
    return 0;
}

Döngü için yukarıdakiler yerine, sayının karekökünü bulma ihtiyacını ortadan kaldırdığı için daha da verimli olan aşağıdaki döngüyü de kullanabilirsiniz.

for(i=2;i*i<=n;i++)
{
    ...
}

1

İşte yazdığım bir fonksiyon. en kötü zaman karmaşıklığı O (sqrt (n)), en iyi zaman ise O (log (n)). Size ortaya çıktığı sayı ile birlikte tüm ana bölenleri verir.

public static List<Integer> divisors(n) {   
    ArrayList<Integer> aList = new ArrayList();
    int top_count = (int) Math.round(Math.sqrt(n));
    int new_n = n;

    for (int i = 2; i <= top_count; i++) {
        if (new_n == (new_n / i) * i) {
            aList.add(i);
            new_n = new_n / i;
            top_count = (int) Math.round(Math.sqrt(new_n));
            i = 1;
        }
    }
    aList.add(new_n);
    return aList;
}

Bu fonksiyonun neyi hesapladığını bilmiyorum, ama kesinlikle n'nin bölücülerinin listesi değil.
le_m

1

Bu, sayı makasını hesaplamanın en temel yoludur:

class PrintDivisors
{
    public static void main(String args[])
    {

    System.out.println("Enter the number");

    // Create Scanner object for taking input
    Scanner s=new Scanner(System.in);

    // Read an int
    int n=s.nextInt();

        // Loop from 1 to 'n'
        for(int i=1;i<=n;i++)
        {

            // If remainder is 0 when 'n' is divided by 'i',
            if(n%i==0)
            {
            System.out.print(i+", ");
            }
        }

    // Print [not necessary]    
    System.out.print("are divisors of "+n);

    }
}

1

@Kendall

Kodunuzu test ettim ve bazı iyileştirmeler yaptım, şimdi daha da hızlı. Ayrıca @ هومن جاویدپور kodu ile test ettim, bu da onun kodundan daha hızlı.

long long int FindDivisors(long long int n) {
  long long int count = 0;
  long long int i, m = (long long int)sqrt(n);
  for(i = 1;i <= m;i++) {
    if(n % i == 0)
      count += 2;
  }
  if(n / m == m && n % m == 0)
    count--;
  return count;
}

0

Bu sadece sayıyı çarpanlarına ayırma - sayının tüm faktörlerini belirleme meselesi değil mi? Daha sonra bir veya daha fazla faktörün tüm kombinasyonlarına ihtiyacınız olup olmadığına karar verebilirsiniz.

Yani, olası bir algoritma şöyle olur:

factor(N)
    divisor = first_prime
    list_of_factors = { 1 }
    while (N > 1)
        while (N % divisor == 0)
            add divisor to list_of_factors
            N /= divisor
        divisor = next_prime
    return list_of_factors

Cevabın geri kalanını belirlemek için faktörleri birleştirmek size kalmıştır.


0

Bu Justin cevabına dayanarak bulduğum bir şey. Bazı optimizasyonlar gerekebilir.

n=int(input())

a=[]
b=[]

def sieve(n):
    np = n + 1
    s = list(range(np)) 
    s[1] = 0
    sqrtn = int(n**0.5)
    for i in range(2, sqrtn + 1): 
        if s[i]:
            s[i*i: np: i] = [0] * len(range(i*i, np, i))
    return filter(None, s)

k=list(sieve(n))

for i in range(len(k)):
        if n%k[i]==0:
                a.append(k[i])

a.sort()

for i in range(len(a)):
        j=1
        while n%(a[i]**j)==0: 
                j=j+1
        b.append(j-1)

nod=1

for i in range(len(b)):
        nod=nod*(b[i]+1)

print('no.of divisors of {} = {}'.format(n,nod))

0

Sanırım aradığınız şey bu, tam olarak istediğini yapıyorum. Kopyalayın ve Not Defteri'ne yapıştırın.

Pls, bir CMD değişkeninin 999999999 üzerindeki değerleri destekleyemeyeceğini unutmayın

@echo off

modecon:cols=100 lines=100

:start
title Enter the Number to Determine 
cls
echo Determine a number as a product of 2 numbers
echo.
echo Ex1 : C = A * B
echo Ex2 : 8 = 4 * 2
echo.
echo Max Number length is 9
echo.
echo If there is only 1 proces done  it
echo means the number is a prime number
echo.
echo Prime numbers take time to determine
echo Number not prime are determined fast
echo.

set /p number=Enter Number : 
if %number% GTR 999999999 goto start

echo.
set proces=0
set mindet=0
set procent=0
set B=%Number%

:Determining

set /a mindet=%mindet%+1

if %mindet% GTR %B% goto Results

set /a solution=%number% %%% %mindet%

if %solution% NEQ 0 goto Determining
if %solution% EQU 0 set /a proces=%proces%+1

set /a B=%number% / %mindet%

set /a procent=%mindet%*100/%B%

if %procent% EQU 100 set procent=%procent:~0,3%
if %procent% LSS 100 set procent=%procent:~0,2%
if %procent% LSS 10 set procent=%procent:~0,1%

title Progress : %procent% %%%



if %solution% EQU 0 echo %proces%. %mindet% * %B% = %number%
goto Determining

:Results

title %proces% Results Found
echo.
@pause
goto start

882161280 - 1282 bölenler
dondon

0

sanırım bu hem kullanışlı hem de hassas olacak

script.pyton

>>>factors=[ x for x in range (1,n+1) if n%x==0] print len(factors)


0

Bu çizgiler boyunca bir şeyler deneyin:

int divisors(int myNum) {
    int limit = myNum;
    int divisorCount = 0;
    if (x == 1) 
        return 1;
    for (int i = 1; i < limit; ++i) {
        if (myNum % i == 0) {
            limit = myNum / i;
            if (limit != i)
                divisorCount++;
            divisorCount++;
        }
    }
    return divisorCount;
}

-1

EN etkili yöntemi bilmiyorum, ama aşağıdakileri yaparım:

  • Sayının karekökünden küçük veya ona eşit olan tüm primerleri bulmak için bir asal tablo oluşturun (Şahsen, Atkin Elekini kullanırım)
  • Sayının karekökünden küçük veya ona eşit olan tüm sayıları sayın ve bunu iki ile çarpın. Sayının kare kökü bir tamsayı ise, sayım değişkeninden bir tane çıkarın.

Çalışmalı \ o /

İhtiyacınız olursa, yarın C'de göstermek için bir şey kodlayabilirim.


2
Kafam karıştı. Bir sayının karekökünden daha az olan tüm asal sayıları saymak size onun bölenlerini vermeyecektir ... bir sayının karekökünden daha az olan her asal o sayı için bir bölen olmayacaktır.
Garrett Berg
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.