Рассказы о математике | страница 14




Совершенные числа встречаются довольно-таки редко, их последовательность согласно Википедии, образует вид:

6,

28,

496,

8128,

33 550 336,

8 589 869 056,

137 438 691 328,

2 305 843 008 139 952 128,

2 658 455 991 569 831 744 654 692 615 953 842 176,


Кстати, еще Эйлер доказал, что все совершенные числа имеют только вид 2>p-1(2>p-1). А вот нечетных совершенных чисел пока не обнаружено, но и не доказано что их не существует. Интересно проверить этот факт практически. Совершенное число 137438691328 обнаружил еще немецкий математик Иоганн Мюллер в 16 веке. Сегодня такое число несложно проверить на компьютере.


Во-первых, слегка оптимизируем приведенную выше программу. Как нетрудно видеть, если число N делится нацело на P, то мы “автоматом” сразу находим и второй делитель N/P. Например, если 10 делится нацело на 2, то оно делится и на 10/2=5. Это позволяет заметно сократить число вариантов перебора. Во-вторых, используем тип чисел Decimal, позволяющий использовать большие числа. Обновленная программа выглядит так:


from decimal import *


def is_perfect(n):

s = Decimal(1)

p = Decimal(2)

while p < n.sqrt()+1:

if n % p == 0:

s += p

if p != n/p: s += n/p

p += 1

return s == n


print(is_perfect(Decimal('137438691328')))


Запускаем, программа работает - число '137438691328' действительно является совершенным. Оно делится на 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524287, 1048574, 2097148, 4194296, 8388592, 16777184, 33554368, 67108736, 134217472, 268434944, 536869888, 1073739776, 2147479552, 4294959104, 8589918208, 17179836416, 34359672832 и 68719345664, сумма этих чисел равна 137438691328. Однако, на моем компьютере проверка “совершенности” данного числа заняла … 54 секунды. Это конечно быстро по сравнению с 16м веком, но совершенно недостаточно чтобы проверить все числа, хотя бы до миллиарда. Значит пора использовать более тяжелую артиллерию - перепишем программу на языке Си. Все-таки Python это интерпретатор, и работает заметно медленнее. Получаемый код не намного сложнее:


#include

#include

#include

#include


bool isPerfect(unsigned long long int n)

{

unsigned long long int sum = 1, i;

for(i=2; i<=sqrt(n)+1; i++)

{

if (n%i==0) {

sum += i;

if (i != n/i) {

sum += n/i;

}

}

}

return sum == n;