Изучение чисел Мерсенна продолжается энтузиастами и сейчас. Самым большим на момент написания книги простым числом, является число М49 = 274207281 - 1, содержащее 22 338 618 знаков. А в начале 2018 года было найдено 50е число Мерсенна М50 = 277232917-1. Его проверка заняла на 32-ядерном сервере Xeon 82 часа. Существует даже сеть распределенных вычислений https://www.mersenne.org, присоединиться к которой может любой желающий, для этого достаточно установить на компьютер программу для расчета.
Кстати, вывести число 277232917-1 совсем несложно с помощью Python. Само вычисление числа проблем не составляет, а вот стандартная функция print для таких длинных чисел не работает - результата дождаться так и не удалось. Однако, число можно вывести посимвольно, если каждый раз выводить остаток от деления на 10, и уменьшать число во столько же раз.
bp2 = 2**77232917 - 1
while True:
print(bp2%10, end='')
bp2 = bp2/10
if bp2 == 0: break
Разумеется, только вывод на экран таким способом займет порядка нескольких часов. Второй недостаток программы в том, что число выводится задом наперед, т.к. первыми выводятся самые младшие разряды, после вывода данные в файле придется перевернуть. Зато мы все-таки можем посмотреть, как выглядит самое больше найденное число Мерсенна (в перевернутом виде) в современной истории: 1709712679608160372856311737129564169399997264989729636740737…
Впрочем, все это уже сделали за нас, уже готовое число M50 можно просто скачать по ссылке https://www.mersenne.ca/primes/digits/M77232917.txt, размер файла составляет 23Мбайт.
В завершение темы простых чисел, приведем вид так называемой “спирали Улама”. Математик Станислав Улам открыл ее случайно в 1963 году, рисуя во время скучного доклада на бумаге числовую спираль и отмечая на ней простые числа:
Как оказалось, простые числа образуют вполне повторяющиеся узоры из диагональных линий. В более высоком разрешении изображение выглядит так (картинка с сайта http://ulamspiral.com):
В общем, можно предположить что далеко не все тайны простых чисел раскрыты и до сих пор.
6. Совершенные числа
Еще одно удивительное свойство мира чисел было доказано еще Евклидом: если число вида 2p-1 является простым (уже известное нам число Мерсенна), то число 2P-1(2p-1) является совершенным, т.е. равно сумме всех его делителей.
Рассмотрим пример для p=13:
213-1 = 8191. Как показывает приведенная ранее программа, 8191 - действительно простое число.
212*(213-1) = 33550336.
Чтобы найти все делители числа и их сумму, напишем небольшую программу:
def is_perfect(n):
sum = 0
for i in range(1, int(n/2)+1):
if n % i == 0:
sum += i
print(i)
print("Сумма", sum)
return sum == n
is_perfect(33550336)
Действительно, 33550336 делится на числа 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8191, 16382, 32764, 65528, 131056, 262112, 524224, 1048448, 2096896, 4193792, 8387584, 16775168. И сумма этих чисел равна искомому 33550336.
Совершенные числа встречаются довольно-таки редко, их последовательность согласно Википедии, образует вид:
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,
Кстати, еще Эйлер доказал, что все совершенные числа имеют только вид 2p-1(2p-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 это интерпретатор, и работает заметно медленнее. Получаемый код не намного сложнее: