Исследования , разделяй и властвуй
Совершенные числа имеют вид 2 p - 1 * (2 p - 1).
Коду потребуется расширенная точность для формирования 191561942608236107294793378084303638130997321548169216
Повышение эффективности
Итерация до <= n / 2
требует слишком многодолго. Итерация до <= n / d
// while(d <= n / 2) {
while(d <= n / d) {
Пример улучшенного кода:
bool isprime(unsigned long long x) {
if (x > 3) {
if (x % 2 == 0) {
return false;
}
for (unsigned long t = 3; t <= x / t; t += 2) {
if (x % t == 0) {
return false;
}
}
return true;
}
return x >= 2;
}
Дополнительно: См. Тест простоты Лукаса – Лемера для быстрого простого теста чисел Мерсенна
Приведенный ниже код работает для всех, кроме 10-го совершенного числа, так как код должен проверять isprime (2 67 - 1), и я должен что-то оставить для OP.
static void buff_mul(char *buff, unsigned power_of_2) {
unsigned long long m = 1ull << power_of_2;
size_t len = strlen(buff);
unsigned long long carry = 0;
for (size_t i = len; i > 0;) {
i--;
unsigned long long sum = (buff[i] - '0') * m + carry;
buff[i] = sum % 10 + '0';
carry = sum / 10;
}
while (carry) {
memmove(buff + 1, buff, ++len);
buff[0] = carry % 10 + '0';
carry /= 10;
}
}
void print_perfext(unsigned p) {
// 2**(p-1) * (2**p - 1)
assert(p > 1 && p <= 164);
char buff[200] = "1";
buff_mul(buff, p);
buff[strlen(buff) - 1]--; // Decrement, take advantage that the LSDigit is never 0
buff_mul(buff, p - 1);
puts(buff);
fflush(stdout);
}
//unsigned next_prime(unsigned first_numeber_to_test_if_prime) {
#include <stdio.h>
int main() {
unsigned p = 0;
for (unsigned i = 0; i < 9; i++) {
// If p prime && 2**p − 1 is prime, then 2**(p − 1) * (2**p − 1) is a perfect number.
while (!isprime(p) || !isprime((1uLL << p) - 1))
p++;
printf("%2u ", p);
print_perfext(p);
p++;
}
return 0;
}
Выход
2 6
3 28
5 496
7 8128
13 33550336
17 8589869056
19 137438691328
31 2305843008139952128
61 2658455991569831744654692615953842176