Я не понимаю, почему обращение процесса вспять дает мне другие результаты. Самый большой продукт-палиндром

Эта задача из проекта Эйлера № 4. Я новичок в программировании и разбираюсь только в типах данных, переменных, циклах, массивах и функциях. если ответ окажется действительно сложным, пожалуйста, скажите мне, что искать.

Итак, проблема заключалась в следующем: число-палиндром читается одинаково в обоих направлениях. Самый большой палиндром, составленный из произведения двух двузначных чисел, равен 9009=91*99.

Найдите наибольший палиндром, составленный из произведения двух трёхзначных чисел.

Сложность этой задачи, по-видимому, проста, но это заняло у меня несколько дней. Исходная программа, которую я разработал, содержала некоторые синтаксические ошибки, поэтому я воспользовался помощьюchat-gpt.

#include <stdio.h>
#include <stdbool.h>

      // palindrome checker
bool is_palindrome(int p) {
    int original = p;
    int reversed = 0;
    int remainder;

      // Reverse the digits 
    while (p > 0) {
        remainder = p % 10;
        reversed = reversed * 10 + remainder;
        p = p / 10;
    }

    // Check if the original number is the same as the reversed number
    //turns out I don't have to say if original == reversed , return true.
    return original == reversed;
}

int main(void) {
    int largest_palindrome = 0;
    int factor1 = 0, factor2 = 0;

    // Check products of all pairs of 3-digit numbers
    for (int i = 10000; i <= 99999; i++) {
        for (int j = 10000; j <= 99999; j++) {
            int product = i * j;
            if (is_palindrome(product) && product > largest_palindrome) {
                largest_palindrome = product;
                factor1 = i;
              printf("Factor 1 : %d\n",i);//I wanted to see the patterns of the factors 
                factor2 = j;
              printf("Factor 2 : %d\n",j);
              
              printf(" product : %d\n",largest_palindrome);
            }
        }
    }

printf("The largest palindrome made from the product of two 5-digit numbers is %d (%d * %d).\n", largest_palindrome, factor1, factor2);
    
  return 0;
}*/
bool is_palindrome(int p) {
    int original = p;
    int reversed = 0;
    int remainder;

    while (p > 0) {
        remainder = p % 10;
        reversed = reversed * 10 + remainder;
        p = p / 10;
    }

    return original == reversed;
}

int main(void) {
    int largest_palindrome = 0;
    int factor1 = 0, factor2 = 0;

  //my genius idea
    for (int i = 99999; i >= 10000; i--) {
        for (int j =99999; j >= 10000; j--) {
            int product = i * j;

            // If the product is less than the largest palindrome yet, break loop
            if (product <= largest_palindrome) {
                break;
            }

            if (is_palindrome(product)) {
              
                factor1 = i;
              printf("Factor 1 : %d\n",i);
                factor2 = j;
              printf("Factor 2 : %d\n",j);
                largest_palindrome = product;
              printf(" product : %d\n",largest_palindrome);
              
            }
        }
    }

    printf("The largest palindrome made from the product of two 5-digit numbers is %d (%d * %d).\n", largest_palindrome, factor1, factor2);

    return 0;
}

Первая программа дала правильный результат для трехзначных чисел: 906609(993*991). На онлайн-компиляторе ушло 45 мс. 4 цифры заняли 1 секунду или что-то в этом роде. 99000099 (9999*9901). Для 5 цифр это заняло минуту. 2147447412 (21516 * 99807) Кажется, один фактор намного меньше другого, мне это показалось несколько интересным.

9999999999 =9999800001. и 1000010000=100000000, поэтому проверка факторов от верхнего предела и переход к i--,j-- должны быть намного быстрее.

для второй программы результат 2126776212 (21397 * 99396). Это заняло меньше секунды, и это круто, но ответ не совпал. Проверив printf, я увидел, что он движется в правильном направлении: 2126776212 (21397 * 99396) на 3 палиндрома отстает от 2147447412 (21516 * 99807), что является результатом первого. для трех- и четырехзначных пар коэффициентов обе программы дают одинаковый результат.

Теперь я не знаю, правильный ли один из них или оба неправильные. Я не думаю, что смогу найти это с помощью онлайн-калькулятора.

Пожалуйста, скажите мне, что вы думаете. Спасибо.

int i = 10000; i <= 99999 Это пятизначные числа, а не трехзначные.
Barmar 26.06.2024 18:07

А когда вы умножаете 5-значные числа, вы получаете 10-значные числа, которые, вероятно, будут слишком большими для int, который обычно составляет 32 бита.

Barmar 26.06.2024 18:11

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

KungFuPanda 26.06.2024 18:11

Для десятизначных чисел нужно использовать long вместо int, а может даже long long.

Barmar 26.06.2024 18:11

подожди, дай мне попробовать

KungFuPanda 26.06.2024 18:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как отмечали другие, вы, вероятно, перегружены int своими 10-значными продуктами, что ухудшает ваши результаты. Как для емкости, так и для производительности все ваши интегральные переменные должны быть unsigned long.

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

#include <stdio.h>

static int is_palindrome(unsigned long p)
{
    unsigned long reversed = 0;
    unsigned long original = p;
    while (p)
    {
        // (1)
        unsigned long remainder = p % 10;
        p /= 10;
        reversed = (reversed * 10) + remainder;
    }
    return original == reversed;
}

int main()
{
    unsigned long largest_palindrome = 0;
    unsigned long factor1, factor2;
    for (unsigned long i = 99999; i >= 10000; --i)
    {
        // (2)
        for (unsigned long j = i; j >= 10000; --j)
        {
            unsigned long product = i * j;

            // If the product is less than the largest palindrome yet, break loop
            if (product <= largest_palindrome)
                break;
            if (is_palindrome(product))
            {
                largest_palindrome = product;
                factor1 = i;
                factor2 = j;
                printf("\t%lu\t%lu\t%lu\n", factor1, factor2, product);
            }
        }
    }
    printf("largest = %lu\n", largest_palindrome);
    return 0;
}
  1. Изменение is_palindrome делает операцию немного быстрее, поскольку ЦП вычисляет результат и остаток от деления в одной инструкции.

  2. j никогда не должно быть больше i, потому что эта комбинация уже должна быть проверена.

Добавьте условие if (i < factor2) break; после внутреннего цикла для большей оптимизации. т.е. для 6 цифр, когда вы добавляете это условие, вы значительно уменьшаете количество проводимых тестов в 10 раз.

Onyambu 27.06.2024 05:29

Числа-палиндромы с четным количеством цифр обладают странным свойством: все они кратны 11. Поэтому, когда i делится на 11, вам нужно будет проверить все возможные значения j; но если i нет, то вы хотите проверить только возможные значения j, кратные 11. С двумя шестизначными коэффициентами это уменьшает количество итераций примерно с 206 миллионов до примерно 32 миллионов (эти результаты уже включают @ оптимизация Оньямбу)

gimix 27.06.2024 20:45

У меня есть еще один вопрос. Вы сказали: «Как для емкости, так и для производительности все ваши целочисленные переменные должны иметь длину без знака». почему это? могу ли я просто записать самый большой тип данных для каждой программы, чтобы гарантировать, что у меня никогда не возникнет такая проблема? типа долго-долго? Возможно, глупый вопрос.

KungFuPanda 28.06.2024 12:15

Если вам не нужны отрицательные числа, всегда используйте unsigned. Процессоры выполняют беззнаковую арифметику, и точка. Целые числа со знаком, по сути, являются синтаксическим сахаром по сравнению с целыми числами без знака, и процессор имеет некоторую встроенную обработку битов для их поддержки, но при прочих равных условиях арифметика без знака более эффективна, чем арифметика со знаком. На любом современном 64-битном процессоре long и long long имеют одинаковый размер, или вы можете просто #include <stdint.h> и использовать тип uint64_t (который, скорее всего, имеет тип unsigned long)

TedB 28.06.2024 14:57

Я понимаю. Спасибо

KungFuPanda 28.06.2024 14:58

Другие вопросы по теме