Thuật toán để tính số lượng ước của một số đã cho


177

Điều gì sẽ là thuật toán tối ưu nhất (hiệu năng-khôn ngoan) để tính số lượng ước của một số đã cho?

Sẽ thật tuyệt nếu bạn có thể cung cấp mã giả hoặc liên kết đến một ví dụ nào đó.

EDIT: Tất cả các câu trả lời đã rất hữu ích, cảm ơn bạn. Tôi đang thực hiện Sàng của Atkin và sau đó tôi sẽ sử dụng một cái gì đó tương tự như những gì Jonathan Leffler đã chỉ ra. Liên kết được đăng bởi Justin Bozonier có thêm thông tin về những gì tôi muốn.


Cho reqs của bạn đến với số lượng các yếu tố là mơ hồ. Tôi đoán bạn đang tìm kiếm số ước số nguyên tố không duy nhất bởi vì nếu bạn không muốn tôi viết mã, hãy viết chương trình để luôn trả về 1 nếu số đó là một và 2 nếu đó là bất cứ điều gì khác. 0 có thể cần một sự thay đổi ...
Justin Bozonier

@sker: Có một loạt các Giá trị mà bạn cần các ước số. Có nhiều cách tính toán các yếu tố và mỗi phương pháp phù hợp hơn với một phạm vi cụ thể.
Ande Turner

2
Dưới đây là một vấn đề thú vị liên quan projecteuler.net/pro
Hiệu = 12

1
S sàng of Atkin ngây thơ ngay cả từ bài viết Wikipedia đã được chỉnh sửa sẽ không bao giờ nhanh hơn S sàng of Eratosthenes có yếu tố bánh xe tối đa đến giới hạn không thực tế lớn, và các phiên bản phân đoạn trang thậm chí còn được SoE ưu ái hơn (xem SoE primesease so với SoA primegen như được thực hiện bởi Bernstein, đối tác của Atkin. Kiến thức Internet không chính xác phổ biến là nghiên cứu của họ đã chứng minh SoA nhanh hơn, nhưng họ đã hạn chế một cách giả tạo việc tối ưu hóa SoE được sử dụng để chứng minh điều này. Xem câu trả lời SoA của tôi để được giải thích thêm
GordonBood

Câu trả lời:


78

Dmitriy nói đúng rằng bạn sẽ muốn Sàng Atkin tạo ra danh sách chính nhưng tôi không tin rằng sẽ quan tâm đến toàn bộ vấn đề. Bây giờ bạn có một danh sách các số nguyên tố bạn sẽ cần xem có bao nhiêu số nguyên tố đó đóng vai trò là một ước số (và mức độ thường xuyên).

Đây là một số con trăn cho thuật toán Nhìn vào đây và tìm kiếm "Chủ đề: toán học - thuật toán cần số chia". Tuy nhiên, chỉ cần đếm số lượng các mục trong danh sách thay vì trả lại chúng.

Đây là một Tiến sĩ Toán học giải thích chính xác những gì bạn cần làm về mặt toán học.

Về cơ bản, nó sẽ rút gọn nếu số của bạn nlà:
n = a^x * b^y * c^z
(trong đó a, b và c là các ước nguyên tố của n và x, y và z là số lần lặp lại của ước số), sau đó tổng số cho tất cả các ước là:
(x + 1) * (y + 1) * (z + 1).

Chỉnh sửa: BTW, để tìm a, b, c, v.v. bạn sẽ muốn làm những gì tương đương với một kẻ tham lam nếu tôi hiểu điều này một cách chính xác. Bắt đầu với ước số nguyên tố lớn nhất của bạn và nhân nó với chính nó cho đến khi phép nhân tiếp tục vượt quá số n. Sau đó di chuyển đến hệ số thấp nhất tiếp theo và nhân số nguyên tố trước ^ số lần nhân với số nguyên tố hiện tại và tiếp tục nhân với số nguyên tố cho đến lần tiếp theo sẽ vượt quá n ... vv Theo dõi số lần bạn nhân ước số với nhau và áp dụng các số đó vào công thức trên.

Không chắc chắn 100% về mô tả thuật toán của tôi nhưng nếu đó không phải là một cái gì đó tương tự.


1
Nếu bạn đang bao gồm một số lượng lớn, bạn thậm chí không muốn nhìn vào danh sách chính. Bạn muốn loại bỏ toàn bộ phạm vi khả năng càng nhanh càng tốt! Xem câu trả lời của tôi để biết thêm.
dùng11318

Tôi nhận ra điều này đã 2 năm trước, nhưng liên kết con trăn của bạn bị hỏng, tình cờ biết nó tồn tại ở đâu bây giờ?
jb.

2
Vì vậy, n = (a^x * b^y * c^z)-(x + 1) * (y + 1) * (z + 1)là sự cai trị
SIslam

1
Như @Shashank nói, thuật toán trong phần "EDIT:" đã sai: Giả sử n = 45 = 3 * 3 * 5. Số nguyên tố lớn nhất là 5, nhưng nhân số này cho đến khi vượt quá n sẽ khiến thuật toán báo cáo rằng nó có 2 bản sao của hệ số 5 (vì 5 * 5 = 25 <45).
j_random_hacker

1
'Sàng của Atkin' có độ phức tạp thời gian chạy là O (N / log (log (N))) . Brute-force kiểm tra tất cả các ước số có thể có từ 1 ... Sqrt (n) có độ phức tạp thời gian chạy là O (Sqrt (N)) vượt trội hơn nhiều. Làm thế nào đến câu trả lời này đã được chấp nhận?
le_m

47

rất nhiều kỹ thuật để bao thanh toán hơn sàng của Atkin. Ví dụ: giả sử chúng ta muốn nhân tố 5893. Vâng, sqrt của nó là 76,76 ... Bây giờ chúng ta sẽ thử viết 5893 như một sản phẩm của hình vuông. Vâng (77 * 77 - 5893) = 36 tức là 6 bình phương, vì vậy 5893 = 77 * 77 - 6 * 6 = (77 + 6) (77-6) = 83 * 71. Nếu điều đó không hiệu quả, chúng tôi đã xem xét liệu 78 * 78 - 5893 có phải là một hình vuông hoàn hảo hay không. Và như thế. Với kỹ thuật này, bạn có thể nhanh chóng kiểm tra các yếu tố gần căn bậc hai của n nhanh hơn nhiều so với kiểm tra các số nguyên tố riêng lẻ. Nếu bạn kết hợp kỹ thuật này để loại bỏ các số nguyên tố lớn với một cái rây, bạn sẽ có một phương pháp bao thanh toán tốt hơn nhiều so với chỉ một cái rây.

Và đây chỉ là một trong số lượng lớn các kỹ thuật đã được phát triển. Đây là một điều khá đơn giản. Bạn sẽ mất nhiều thời gian để tìm hiểu, giả sử, đủ lý thuyết số để hiểu các kỹ thuật bao thanh toán dựa trên các đường cong elip. (Tôi biết chúng tồn tại. Tôi không hiểu chúng.)

Do đó, trừ khi bạn đang xử lý các số nguyên nhỏ, tôi sẽ không cố gắng tự giải quyết vấn đề đó. Thay vào đó, tôi sẽ cố gắng tìm cách sử dụng một cái gì đó như thư viện PARI đã có một giải pháp hiệu quả cao được triển khai. Với điều đó, tôi có thể tính một số 40 chữ số ngẫu nhiên như 124321342332143213122323434312213424231341 trong khoảng 0,05 giây. (Yếu tố của nó, trong trường hợp bạn tự hỏi, là 29 * 439 * 1321 * 157907 * 284749 * 33843676813 * 4857795469949. Tôi khá tự tin rằng nó đã không phát hiện ra điều này khi sử dụng sàng Atkin ...)


1
Kỹ thuật của bạn rất thông minh, nhưng nó không cho tôi biết con số đó có bao nhiêu yếu tố?
trượt ván

23
Một khi bạn có yếu tố chính, hãy tìm hiểu xem có bao nhiêu yếu tố đơn giản. Giả sử các thừa số nguyên tố là p1, p2, ..., pk và chúng được lặp lại m1, m2, ..., mk lần. Sau đó, có các yếu tố (1 + m1) (1 + m2) ... (1 + mk).
dùng11318

Một cái rây thú vị là cái rây bậc hai . Điều này sử dụng lý thuyết số - đồng quy bậc hai và một số đại số tuyến tính. Tôi đã học đủ để sử dụng nó trong khóa học lý thuyết số năm thứ 2 tại trường đại học.
Tanner

33

@Yasky

Hàm số chia của bạn có một lỗi ở chỗ nó không hoạt động chính xác cho các ô vuông hoàn hảo.

Thử:

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
Sẽ không (x% i) gây ra chia cho 0 khi i = 0? tôi nên = 1..limit?
rhu

@rhu Kiểm tra 0 là vô nghĩa vì 0 không phải là một yếu tố của bất kỳ số nào.
EJoshuaS - Phục hồi Monica

29

Tôi không đồng ý rằng rây của Atkin là con đường để đi, bởi vì có thể dễ dàng mất nhiều thời gian hơn để kiểm tra mọi số trong [1, n] về tính nguyên thủy so với việc giảm số lượng theo cách chia.

Đây là một số mã, mặc dù hơi hack, nhưng thường nhanh hơn nhiều:

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 Đó là mã python hoạt động để giải quyết vấn đề này.


11

Đây là một thuật toán O (sqrt (n)) thẳng về phía trước. Tôi đã sử dụng điều này để giải quyết euler dự án

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

nhưng tại sao bạn luôn tăng số đếm lên 2? ... có định lý nào bạn áp dụng không?
SummerCode

3
bởi vì bạn chỉ tiếp tục cho đến khi sqrt (n). Ví dụ: nếu bạn đang cố gắng tìm tất cả các ước số cho 36 - bạn sẽ tính từ 2 đến 6. Bạn biết rằng 1 & 36,2 & 18, 3 & 12, 4 & 9, 6,6 đều là các ước số và chúng đi theo cặp.
Antony Thomas

2
cảm ơn rất nhiều Anthony, giờ tôi đã hiểu: D! một phụ lục nhỏ: tôi nghĩ rằng nó nên xử lý riêng giá trị sqrt (n) bởi vì bây giờ nó phải xem xét hai lần thay vì một, tôi nghĩ
SummerCode

Trong khi O (sqrt (n)) không quá tệ, nó không tối ưu. tính toán phân tích thừa số nguyên tố có thể được thực hiện nhanh hơn nhiều và đủ để tính toán số lượng ước.
le_m

Ở mỗi lần lặp, bạn phải tính i², sẽ không nhanh hơn khi so sánh i với √n (chỉ tính một lần)?
Yukulélé

10

Câu hỏi thú vị này khó hơn nhiều so với vẻ ngoài của nó và nó chưa được trả lời. Câu hỏi có thể được bao gồm thành 2 câu hỏi rất khác nhau.

1 cho N, tìm danh sách L của các thừa số nguyên tố của N

2 cho L, tính số kết hợp duy nhất

Tất cả các câu trả lời tôi thấy cho đến nay đều đề cập đến # 1 và không đề cập đến nó không thể thực hiện được với số lượng khổng lồ. Đối với các số N, thậm chí 64 bit có kích thước vừa phải, thật dễ dàng; đối với N rất lớn, vấn đề bao thanh toán có thể mất "mãi mãi". Mã hóa khóa công khai phụ thuộc vào điều này.

Câu hỏi số 2 cần thảo luận nhiều hơn. Nếu L chỉ chứa các số duy nhất, thì đó là một phép tính đơn giản sử dụng công thức kết hợp để chọn k đối tượng từ n mục. Trên thực tế, bạn cần tổng hợp các kết quả từ việc áp dụng công thức trong khi thay đổi k từ 1 đến sizeof (L). Tuy nhiên, L thường sẽ chứa nhiều lần xuất hiện của nhiều số nguyên tố. Ví dụ: L = {2,2,2,3,3,5} là hệ số của N = 360. Bây giờ vấn đề này khá khó khăn!

Nghỉ ngơi # 2, bộ sưu tập C đã cho chứa k mục, sao cho mục a có 'trùng lặp và mục b có b' trùng lặp, v.v ... có bao nhiêu cách kết hợp duy nhất từ ​​1 đến k-1? Ví dụ: {2}, {2,2}, {2,2,2}, {2,3}, {2,2,3,3} mỗi lần phải xảy ra một lần và chỉ một lần nếu L = {2,2 , 2,3,3,5}. Mỗi bộ sưu tập phụ duy nhất như vậy là một ước số duy nhất của N bằng cách nhân các mục trong bộ sưu tập phụ.


Dưới đây là một liên kết đến một số mã giả cho một vấn đề rất giống với 2. answers.google.com/answers/threadview/id/392914.html
mR_fr0g

3
Câu hỏi số 2 có một giải pháp nổi tiếng. Đối với hệ số của {p_i, k_i} trong đó p_ilà thừa số nguyên tố của một số có k_ibội số, tổng số ước của số đó là (k_1+1)*(k_2+1)*...*(k_n+1). Tôi đoán bây giờ bạn biết điều này nhưng tôi viết nó ra vì lợi ích nếu một người đọc ngẫu nhiên ở đây.
Will Ness

9

Một câu trả lời cho câu hỏi của bạn phụ thuộc rất lớn vào kích thước của số nguyên. Các phương thức cho số nhỏ, ví dụ dưới 100 bit và cho số ~ 1000 bit (như được sử dụng trong mật mã) là hoàn toàn khác nhau.


6

CHỈ một dòng
Tôi đã suy nghĩ rất cẩn thận về câu hỏi của bạn và tôi đã cố gắng viết một đoạn mã hiệu quả và hiệu quả cao Để in tất cả các ước của một số đã cho trên màn hình, chúng tôi chỉ cần một dòng mã! (sử dụng tùy chọn -std = c99 trong khi biên dịch qua gcc)

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

để tìm số lượng ước, bạn có thể sử dụng hàm rất nhanh sau đây (hoạt động chính xác cho tất cả các số nguyên trừ 1 và 2)

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

hoặc nếu bạn coi số đã cho là số chia (hoạt động chính xác cho tất cả số nguyên trừ 1 và 2)

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

GHI CHÚ: hai hàm trên hoạt động chính xác cho tất cả các số nguyên dương ngoại trừ số 1 và 2, vì vậy nó có chức năng cho tất cả các số lớn hơn 2 nhưng nếu bạn cần bao gồm 1 và 2, bạn có thể sử dụng một trong các hàm sau (một chút Chậm hơn)

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

HOẶC LÀ

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

nhỏ là đẹp :)


5

Sàng của Atkin là một phiên bản tối ưu của sàng Eratosthenes cung cấp tất cả các số nguyên tố lên đến một số nguyên cho trước. Bạn có thể google nó để biết thêm chi tiết.

Khi bạn có danh sách đó, việc chia số của bạn cho mỗi số nguyên tố là một vấn đề đơn giản để xem liệu đó có phải là một ước số chính xác hay không (nghĩa là phần còn lại bằng 0).

Các bước cơ bản để tính các ước số cho một số (n) là [đây là mã giả được chuyển đổi từ mã thực vì vậy tôi hy vọng tôi chưa giới thiệu lỗi]:

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

Bạn có thể thử cái này Đó là một chút hackish, nhưng nó khá nhanh.

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

2
Mặc dù hàm này cung cấp phân rã nhân tố chính của n trong thời gian hợp lý, nhưng a) không tối ưu và b) không tính được số ước của một số đã cho theo câu hỏi của OP
le_m

Và sẽ không hoạt động với số lượng lớn vì sự đệ quy của nó
whackamadoodle3000

Mặc dù điều này không tối ưu, và thay vì đếm các yếu tố, nhưng thực tế nó liệt kê chúng, sự đơn giản và vẻ đẹp của điều này thật đáng kinh ngạc và khá nhanh. ^^
Gaurav Singhal

5

Một khi bạn có hệ số nguyên tố, có một cách để tìm số lượng ước. Thêm một vào mỗi số mũ trên mỗi yếu tố riêng lẻ và sau đó nhân số mũ với nhau.

Ví dụ: 36 Hệ số nguyên tố: 2 ^ 2 * 3 ^ 2 Số chia: 1, 2, 3, 4, 6, 9, 12, 18, 36 Số lượng chia: 9

Thêm một vào mỗi số mũ 2 ^ 3 * 3 ^ 3 Nhân số mũ: 3 * 3 = 9


3

Trước khi bạn cam kết với một giải pháp, hãy xem xét rằng phương pháp sàng có thể không phải là một câu trả lời tốt trong trường hợp điển hình.

Một thời gian trước, có một câu hỏi chính và tôi đã thực hiện một bài kiểm tra thời gian - đối với các số nguyên 32 bit ít nhất là xác định xem đó có phải là số nguyên tố chậm hơn lực lượng vũ phu hay không. Có hai yếu tố đang diễn ra:

1) Trong khi một người mất một thời gian để thực hiện một bộ phận, họ rất nhanh chóng trên máy tính - tương tự như chi phí tìm kiếm câu trả lời.

2) Nếu bạn không có bảng nguyên tố, bạn có thể tạo một vòng lặp chạy hoàn toàn trong bộ đệm L1. Điều này làm cho nó nhanh hơn.


3

Đây là một giải pháp hiệu quả:

#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

Các ước số làm một cái gì đó ngoạn mục: họ chia hoàn toàn. Nếu bạn muốn kiểm tra số lượng ước cho một số n, thì rõ ràng là không cần thiết để mở rộng toàn bộ phổ , 1...n. Tôi chưa thực hiện bất kỳ nghiên cứu chuyên sâu nào cho vấn đề này nhưng tôi đã giải quyết vấn đề 12 của Project Euler về Số tam giác . Giải pháp của tôi cho bài kiểm tra ước số lớn hơn 500 sau đó đã chạy trong 309504 micro giây (~ 0,3 giây). Tôi đã viết hàm chia này cho giải pháp.

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

Đối với mọi thuật toán, có một điểm yếu. Tôi nghĩ rằng điều này là yếu so với số nguyên tố. Nhưng vì số tam giác không được in, nên nó phục vụ mục đích của nó một cách hoàn hảo. Từ hồ sơ của tôi, tôi nghĩ rằng nó đã làm khá tốt.

Chúc mừng ngày lễ.


1
Bạn sẽ có một số chia cho 0 trong lần lặp đầu tiên ở đây
barfoon

không may măn. ++ i khác với i ++ (sẽ dẫn đến lỗi chia cho 0)
iGbanam

Tôi đã viết hàm của bạn trong PHP và chạy nó - đây là những gì tôi có - i.minus.com/iKzuSXesAkpbp.png
barfoon

Đối với một số lý do kỳ lạ, điều này làm việc hoàn hảo cho tôi. oh tốt, xấu của tôi bắt đầu numberOfDivisorsvà lặp ở 1; điều này sẽ thoát khỏi sự phân chia bởi lỗi không
iGbanam

1
Thuật toán của bạn không hoạt động cho các hình vuông hoàn hảo. Ví dụ: nó trả về 4 cho đầu vào x = 4, vì nó đang đếm 2 lần ... 1, 2, 2, 4. Câu trả lời phải là 3: 1,2,4
Michael

1

Bạn muốn sàng của Atkin, được mô tả ở đây: http://en.wikipedia.org/wiki/Sieve_of_Atkin


1
Điều đó sẽ giúp bạn có các số nguyên tố dưới số đã cho - nhưng không đảm bảo rằng các số nguyên tố đó sẽ là ước số? (trừ khi tôi thiếu thứ gì đó)
Andrew Edgecombe

Đây là một bước nhảy vọt nhanh chóng từ đây để tìm ra tất cả các số nguyên tố <sqrt (N) chia đều cho N.
SquareCog

1
Nó có thể là một bước nhảy vọt nhanh chóng, nhưng thử nghiệm tất cả các số nguyên tố <sqrt (N) vẫn là một kỹ thuật bao thanh toán tồi cho dù bạn có tìm thấy chúng hiệu quả đến đâu. Có rất nhiều cách để cải thiện điều đó.
dùng11318

Kiểm tra các số nguyên tố là O (N), đó là tìm các số nguyên tố đó là phần khó. Nhưng ngay cả với sàng không bị tối ưu hóa của eratosthenes, bạn vẫn có thể tìm thấy tất cả các số nguyên tố dưới một vài triệu trong một giây. Nó bao gồm bất kỳ số 64b nào và tôi chắc chắn rằng chúng ta không nói về việc bao thanh toán các công cụ cấp độ tiền điện tử ở đây
Matthew Scharley

1

phương pháp số nguyên tố rất rõ ràng ở đây. P [] là danh sách số nguyên tố nhỏ hơn hoặc bằng sq = sqrt (n);

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

Sách giáo khoa lý thuyết số gọi hàm số chia là tau. Sự thật thú vị đầu tiên là nó nhân lên, tức là. (ab) = τ (a) τ (b), khi a và b không có thừa số chung. (Chứng minh: mỗi cặp ước của a và b cho một ước số riêng biệt của ab).

Bây giờ lưu ý rằng với pa Prime, τ (p ** k) = k + 1 (lũy thừa của p). Do đó, bạn có thể dễ dàng tính (n) từ hệ số của nó.

Tuy nhiên, yếu tố số lượng lớn có thể chậm (tính bảo mật của phương pháp áp lạnh RSA phụ thuộc vào sản phẩm của hai số nguyên tố lớn khó có thể xác định được). Điều đó cho thấy thuật toán tối ưu hóa này

  1. Kiểm tra nếu số là số nguyên tố (nhanh)
  2. Nếu vậy, trả lại 2
  3. Mặt khác, nhân số (chậm nếu nhiều thừa số nguyên tố lớn)
  4. Tính (n) từ hệ số

1

Sau đây là chương trình C để tìm số ước của một số đã cho.

Độ phức tạp của thuật toán trên là O (sqrt (n)).

Thuật toán này sẽ hoạt động chính xác cho số là hình vuông hoàn hảo cũng như số không phải là hình vuông hoàn hảo.

Lưu ý rằng phần trên của vòng lặp được đặt thành căn bậc hai của số để có thuật toán hiệu quả nhất.

Lưu ý rằng việc lưu trữ Upperlimit trong một biến riêng biệt cũng giúp tiết kiệm thời gian, bạn không nên gọi hàm sqrt trong phần điều kiện của vòng lặp for, điều này cũng giúp tiết kiệm thời gian tính toán của bạn.

#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;
}

Thay vì vòng lặp ở trên, bạn cũng có thể sử dụng vòng lặp sau đây thậm chí còn hiệu quả hơn vì điều này loại bỏ nhu cầu tìm căn bậc hai của số.

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

1

Đây là một chức năng mà tôi đã viết. độ phức tạp thời gian tồi tệ nhất của nó là O (sqrt (n)), mặt khác thời gian tốt nhất là O (log (n)). Nó cung cấp cho bạn tất cả các ước số nguyên tố cùng với số lần xuất hiện của nó.

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

Tôi không biết hàm này tính toán gì, nhưng nó chắc chắn không phải là danh sách các ước của n.
le_m

1

Đây là cách cơ bản nhất để tính toán các div div số:

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

@Kallall

Tôi đã kiểm tra mã của bạn và thực hiện một số cải tiến, bây giờ nó thậm chí còn nhanh hơn. Tôi cũng đã thử nghiệm với mã @ هومن اویدپور, mã này cũng nhanh hơn mã của anh ấy.

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

Đây không phải chỉ là một câu hỏi về bao thanh toán số - xác định tất cả các yếu tố của số? Sau đó, bạn có thể quyết định xem bạn cần tất cả các kết hợp của một hoặc nhiều yếu tố.

Vì vậy, một thuật toán có thể sẽ là:

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

Sau đó, bạn phải kết hợp các yếu tố để xác định phần còn lại của câu trả lời.


0

Đây là một cái gì đó tôi đã đưa ra dựa trên câu trả lời của Justin. Nó có thể yêu cầu một số tối ưu hóa.

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

Tôi nghĩ rằng đây là những gì bạn đang tìm kiếm. Tôi làm chính xác những gì bạn yêu cầu. Sao chép và Dán nó trong Notepad. Lưu dưới dạng * .bat.Run.Nhập số. Đa số quá trình bằng 2 và đó là số lượng ước. Tôi đã thực hiện điều đó nhằm mục đích xác định các ước số nhanh hơn:

Xin lưu ý rằng giá trị hỗ trợ không thể thay đổi của CMD trên 999999999

@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 ước số
dondon

0

tôi đoán cái này sẽ tiện dụng cũng như chính xác

script.pyton

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


0

Hãy thử một cái gì đó dọc theo những dòng này:

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

Tôi không biết phương pháp hiệu quả nhất, nhưng tôi sẽ làm như sau:

  • Tạo một bảng các số nguyên tố để tìm tất cả các số nguyên tố nhỏ hơn hoặc bằng căn bậc hai của số (Cá nhân, tôi sẽ sử dụng Sàng của Atkin)
  • Đếm tất cả các số nguyên tố nhỏ hơn hoặc bằng căn bậc hai của số và nhân số đó với hai. Nếu căn bậc hai của số là một số nguyên, thì trừ một số từ biến đếm.

Nên làm việc \ o /

Nếu bạn cần, tôi có thể mã hóa thứ gì đó vào ngày mai bằng C để chứng minh.


2
Tôi bối rối. Đếm tất cả các số nguyên tố nhỏ hơn căn bậc hai của một số sẽ không cung cấp cho bạn số chia đó ... không phải mọi số nguyên tố nhỏ hơn căn bậc hai của một số sẽ là ước số cho số đó.
Garrett Berg
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.