Как найти все делители натурального числа паскаль

Хотел написать программу по заданию, но, как оказалось, в который раз я попытался решить практически неразрешимую задачу. Всё никак не мог достичь приемлемой скорости вычислений… Ещё бы. Общее количество делителей заданного числа оказалось равным 2963520000.

Цитата
Сообщение от Mike_Boone
Посмотреть сообщение

и так работает

Работает, конечно. Только считать будет до скончания веков. Или, если переполнение BigInteger аварийно завершает программу, то до момента переполнения переменной i. Если добавить условие окончания нахождения делителей, то выводить все делители на экран программа будет где-то пару лет.

Цитата
Сообщение от Artyom2124
Посмотреть сообщение

Найти все делители

Artyom2124, Вы уверены? Если программа будет выдавать по 1000 делителей в секунду, она будет работать более месяца, и, если делители записывать в текстовый файл, конечный объём файла будет примерно 160 гигабайт (более 170000000000 символов). Сильно сомневаюсь, что такое задание могли дать в каком-либо учебном заведении.

Artyom2124, может быть, нужно найти все простые делители?

Это я сделал. К счастью, максимальный простой делитель Вашего числа сравнительно маленький, и помещается в тип integer. Общее количество делителей числа не помещается в тип integer, для подсчёта указанной величины я использовал тип real.

Программа факторизации Вашего числа, находит все простые делители, их максимальные степени и общее количество делителей числа:

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
const
  hor = '+----+---------+-----------+';
 
var
  s, t: string; {делимое, частное}
  i, j, c, k: integer; {делитель, счётчик, остаток от деления, номер делителя}
  q: real; {общее количество всех делителей}
  d, p: array[0..15] of integer; {массивы делителей и максимальных степеней делителей}
 
begin
  d[0] := 1; {"лишний" нулевой элемент массива для упрощения алгоритма}
  {первое делимое (исходное число):}
  s := '196708423126676569286001022355850789704717014605805349202544575890563591254090079162973668806152370560989633700137089767703775820200092605536123071613442454080946743909994972297960260325884838413934893551073244410428771253965567859';
  i := 2; {начинаем поиск простых делителей с наименьшего простого числа}
  k := 0; {пока что простые делители не найдены, поэтому их количество пока 0}
  while s <> '1' do {делим число на простые делители до тех пор, пока число не станет равным 1}
    begin
      t := ''; {текуще частное пока не найдено}
      c := 0; {остаток от деления пока равен 0}
      for j := 1 to length(s) do {цикл деления числа}
        begin
          c := c * 10 - ord('0') + ord(s[j]); {приписываем к остатку текущую цифру}
          t := t + inttostr(c div i); {находим текущую цифру частного}
          c := c mod i {находим следующий остаток}
        end;
      if c = 0 then {если последний остаток равен 0, то}
        begin {число делится на текущий делитель, разбираемся с делителем}
          if d[k] <> i then {если новый делитель, то}
            begin
              inc(k); {увеличиваем номер делителя}
              d[k] := i {и записываем текущий делитель в массив}
            end;
          inc(p[k]); {подсчитываем количество текущих делителей}
          while t[1] = '0' do delete(t, 1, 1); {убираем из частного незначащие нули}
          s := t {и переписываем его в делимое}
        end
      else inc(i); {иначе, если последний остаток не равен 0, увеличиваем делитель на 1}
    end;
  {печатаем простые делители}
  writeln('Prime divisors:');
  writeln(hor);
  writeln('|  # | divisor | max power |');
  writeln(hor);
  for j := 1 to k do writeln('|', j:3, ' |',  d[j]:7, '|':3, p[j]:6, '|':6);
  writeln(hor);
  {находим и печатаем общее количество делителей}
  q := 1;
  for j := 1 to k do q := q * (p[j] + 1);
  writeln;
  write('Total quantity of all divisors = ', q)
end.

На моём древнем ноутбуке в Pascal ABC программа считает примерно 24 секунды, эта же программа, подрихтованная и запущенная в Free Pascal, считает примерно 4 секунды.

Прогон программы

Код

Prime divisors:
+----+---------+-----------+
|  # | divisor | max power |
+----+---------+-----------+
|  1 |   1297  |     6     |
|  2 |   5651  |     2     |
|  3 |   6959  |     5     |
|  4 |  10799  |     2     |
|  5 |  12547  |     1     |
|  6 |  15161  |     4     |
|  7 |  16223  |     1     |
|  8 |  16417  |     4     |
|  9 |  17681  |     4     |
| 10 |  18541  |     4     |
| 11 |  20411  |     6     |
| 12 |  23563  |     6     |
| 13 |  26591  |     7     |
| 14 |  27943  |     1     |
| 15 |  28513  |     3     |
+----+---------+-----------+

Total quantity of all divisors = 2963520000

Первая колонка — номер простого делителя, вторая — величина простого делителя, третья — максимальная степень, при возведении в которую простого делителя, получившееся число всё ещё делит исходное число нацело.
Ниже таблицы — общее количество всех делителей.

Пояснения по количеству делителей: любой делитель числа может быть представлен в виде произведения степеней всех простых делителей числа, степень при конкретном простом делителе может быть от 0 до упомянутой выше максимальной степени. Таким образом, общее количество делителей равно количеству всех возможных комбинаций степеней при всех простых делителях, иными словами, произведению увеличенных на 1 максимальных степеней для каждого простого делителя.

Напоследок, если строго по заданию… Казалось бы, имеет смысл дописать мою программу… Осталось совсем немного: перебрать все степени при простых делителях, и умножить исходную единицу нужное количество раз на каждый простой делитель, и так 2963520000 раз… Короче, сущий пустяк, думаю, за год можно будет найти все делители заданного числа.

Добавлено через 2 часа 3 минуты
Если желаете, можете

Цитата
Сообщение от Artyom2124
Посмотреть сообщение

найти как можно больше положительных делителей заданного числа

хоть вручную. Сначала принимаете все степени равными 0, и получаете первый делитель:
285130279430265910235630204110185410176810164170162230151610125470107990695905651012970
=1

Затем начинаем увеличивать степени, например, в порядке справа налево, и перебираем все возможные комбинации следующим образом: если степень в самом правом сомножителе достигла максимальной по таблице, то обнуляем эту степень, и увеличиваем следующую (вторую справа), и продолжаем в том же духе до тех пор, пока не переполнится и вторая справа степень, тогда увеличиваем третью справа, а вторую справа обнуляем, и так до тех пор, пока набор степеней не будет такой же, как в таблице:

285130279430265910235630204110185410176810164170162230151610125470107990695905651012971
=1297
285130279430265910235630204110185410176810164170162230151610125470107990695905651012972
=1682209
285130279430265910235630204110185410176810164170162230151610125470107990695905651012973
=2181825073
285130279430265910235630204110185410176810164170162230151610125470107990695905651012974
=2829827119681
285130279430265910235630204110185410176810164170162230151610125470107990695905651012975
=3670285774226257
285130279430265910235630204110185410176810164170162230151610125470107990695905651012976
=4760360649171455329
285130279430265910235630204110185410176810164170162230151610125470107990695905651112970
=5651
285130279430265910235630204110185410176810164170162230151610125470107990695905651112971
=7329347

285130279430265910235630204110185410176810164170162230151610125470107990695905651112976
=26900798028467894064179
285130279430265910235630204110185410176810164170162230151610125470107990695905651212970
=31933801

285130279430265910235630204110185410176810164170162230151610125470107990695905651212976
=152016409658872069356675529
285130279430265910235630204110185410176810164170162230151610125470107990695915651012970
=6959

285130279430265910235630204110185410176810164170162230151610125470107990695915651212976
=1057882194816090730653105006311

285133279431265917235636204116185414176814164174162231151614125471107992695955651212976
=1967084231266765692860010223558507897047170146058053492025445758905635912540900 79162973668806152370560989633700137089767703775820200092605536123071613442454080 946743909994972297960260325884838413934893551073244410428771253965567859

Добавлено через 4 часа 36 минут
Хотя… Если применить что-нибудь получше строк, то… Программа на Free Pascal Compiler для печати заданного количества делителей, начиная с делителя с заданным номером:

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
const
  nd = 15;
 
type
  arr = array[1..nd] of integer;
 
const
  d: arr = (1297, 5651, 6959, 10799, 12547, 15161, 16223, 16417, 17681, 18541, 20411, 23563, 26591, 27943, 28513);
  p: arr = (6, 2, 5, 2, 1, 4, 1, 4, 4, 4, 6, 6, 7, 1, 3);
  n = 17;
  m = 100000000000000;
  mn = 2963520000;
 
var
  a: array[1..n] of uint64;
  i, j, c, k: integer;
  q, b, v: longword;
  r: arr;
 
begin
  write('Start number (1..', mn, '): ');
  readln(b);
  write('Count (1..', mn, '): ');
  readln(q);
  v := b - 1;
  for i := 1 to nd do
    begin
      r[i] := v mod (p[i] + 1);
      v := v div (p[i] + 1)
    end;
  dec(r[1]);
  repeat {начало цикла вычисления делителей}
    //write(b:10, ' |'); //раскомментировать для печати номеров делителей
    inc(b);
    {вычисляем и печатаем очередной набор степеней для простых делителей}
    dec(q);
    c := 1; {перенос}
    for i := 1 to nd do
      begin
        r[i] += c;
        if r[i] > p[i] then
          begin
            r[i] := 0;
            c := 1
          end
        else c := 0;
        //write(r[i]:2) //раскоментировать для печати набора степеней
      end;
    //writeln; раскомментировать для печати набора степеней
    {пока очередной делитель равен 1}
    a[1] := 1;
    for i := 2 to n do a[i] := 0;
    {перемножаем очередной делитель на каждый простой делитель d[i], r[i] раз}
    for i := 1 to nd do
      for j := 1 to r[i] do
        begin
          for k := 1 to n do a[k] := a[k] * d[i];
          for k := 1 to n - 1 do
            begin
              a[k + 1] := a[k + 1] + a[k] div m;
              a[k] := a[k] mod m
            end
        end;
    {печатаем найденный делитель}
    k := n;
    while a[k] = 0 do dec(k);
    write(a[k]);
    for k := k - 1 downto 1 do
      begin
        c := m div 10;
        while (c > 10) and (c > a[k]) do
          begin
            write('0');
            c := c div 10
          end;
        write(a[k])
      end;
    writeln
  until (q = 0) or (b > mn); {конец цикла вычисления делителей}
  readln
end.

Делитель числа размещается в массиве, который используется в качестве 17-разрядного длинного числа в 100000000000000-ричной системе счисления. Так как основание системы счисления является степенью числа 10, то перевести такое число в десятичное не вызывает никаких проблем. Большее основание системы счисления применить не получилось из-за целочисленного переполнения.
В программе нет проверки вводимых значений.
можно объединить обе программы.
Можно переделать для вывода делителей в файл.
Можно переделать под Pascal ABC, но неохота из-за танцев с бубном ввиду отсутствия в Pascal ABC достаточно ёмкого целочисленного типа.
Проверить программу очень просто: нужно ввести Start number: 2963520000 и Count: 1, и будет напечатан последний делитель заданного числа, а именно, само заданное число.



0



Пример программы паскаль, которая находит все делители натурального числа и их сумму

Пример программы паскаль, которая находит все делители натурального числа и их сумму

Итак, продолжаю выкладывать наиболее востребованные исходники Паскаль ABC по теме циклы паскаль (FOR). Задача Pascal такая: Дано натуральное число. Найти все его делители и их сумму. Число вводится с клавиатуры, делители выводятся через пробелы, сумма в следующей строке. Допустим диалог с пользователем.

Исходный код программы:

Var n, i, sum: integer;  //Описание переменных
Begin                    //Начло программы
writeln ('Введите число'); //Диалог с пользователем
readln(n);                  //Считывание числа
sum := n;                   //Присваивание сумме значение самого числа (само число - уже делитель самого себя)
writeln('Делители числа:');   //Диалог с пользователем
for i := 1 to n div 2 do      //Цикл For от до половины n
  if (n mod i) = 0 then begin  //Если число делится на i, то выводим
    write(i,'  ');
    sum := sum + i;            //К значению суммы прибавляем делитель
  end;                         //Конец условного оператора if
writeln(n); //Вывод самого числа, т.к. оно тоже делитель
writeln('Сумма делителей: ',sum);  //Вывод суммы делителей
End.                               //Конец программы

Дата: 2013-06-25 10:53:19   Просмотров: 48719

Теги: Паскаль Pascal исходник исходники скачать FOR циклы

Введение.

Итак, я продолжаю решать самые популярные и самые распространенные задачи на языке программирования PascalABC с использованием циклов FOR, на этот раз это задача на нахождение делителей числа и их суммы.

Задача.

Дано
натуральное число X, наша задача — найти его делители и их сумму SUMMA. Число X считывается с клавиатуры, делители выводятся на экран через знак пробела, а их сумма SUMMA располагается в следующей строке. Решим поставленную перед нами задачу с использованием цикла FOR, добавляя к каждой строке необходимые пояснения для абсолютного понимания алгоритма.

Код.

Var n, i, sum: integer; //Описание переменных
Begin //Начло программы
writeln (‘Введите число’); //Диалог с пользователем
readln(n); //Считывание числа
sum := n; //Присваивание сумме значение самого числа (само число — уже делитель самого себя)
writeln(‘Делители числа:’); //Диалог с пользователем
for i := 1 to n div 2 do //Цикл For от до половины n
if (n mod i) = 0 then begin //Если число делится на i, то выводим
write(i,’ ‘);
sum := sum + i; //К значению суммы прибавляем делитель
end; //Конец условного оператора if
writeln(n); //Вывод самого числа, т.к. оно тоже делитель
writeln(‘Сумма делителей: ‘,sum); //Вывод суммы делителей
End. //Конец программы

Натурáльные чи́сла (от лат.naturalis «естественный») — числа, возникающие естественным образом при счёте (1, 2, 3, 4, 5, 6, 7 и так далее…). Последовательность всех натуральных чисел, расположенных в порядке возрастания, называется натуральным рядом.

Ниже рассмотрен пример поиска всех делителей натурального числа на Pascal.

var a,n,c,d:word;
begin
    readln( a );
    n:=1;
    while ( n <= sqrt(a) ) do begin
       c:=a mod n;
       d:=a div n;
       if c = 0 then begin
          writeln( n );
          if n <> d then writeln( d );
       end;
       inc( n );
    end;
end.

Program
pr32 (Input, Output);         

Объявление
имени программы

Var         

Блок
объявления глобальных переменных

N            
: Integer;              

Переменная
N — заданное число

i              
: Integer;              

Переменная
i — параметр цикла и делитель

Begin    

Начало
тела программы

WriteLn
(‘PASCAL: Нахождения всех делителей
заданного числа.’);           

Формулировка
цели алгоритма

Write
(‘Введите число, для которого ищутся
делители: ‘);           

Запрос
N — числа, для которого ищутся делители

ReadLn
(N);         

Ввод
N

WriteLn
(‘Делители числа N = ‘, N, ‘ равны:’);             

Сообщение
пользователю о выводе найденных
делителей

For
i := 1 To N Do              

Цикл
для i от 1 до N нахождения делителей числа
N

If
(N Div i) = (N / i)    Если
целая часть дроби N/i равна дроби N/i,            

Проверка
равенства кратности числа N делителю i

Then
WriteLn (i);               
i является очередным делителем числа
N                           

В
случае кратности выводим очередной
делитель — число i

ReadLn;

Ожидание
нажатия клавиши Enter для завершения

End.       

Конец
программы

Like this post? Please share to your friends:
  • Как найти неопределенность предела
  • Как найти сумму кординат векторов
  • Как найти предков если не знаешь ничего
  • Как найти полезные ископаемые уголь
  • Неправильно оприходовали материалы как исправить если квартал закрыт