Необычное поведение суммы в C ++?

Я пишу метод, чтобы проверить, является ли число палиндром или нет. Например, 12321 - палиндром, а 98765 - нет. В моей программе я использовал рекурсивную функцию, чтобы создать точно противоположное заданному числу, например 56789 для 98765, а затем проверить, равны ли два числа или нет. Но я не получаю полную противоположность 98765, то есть 56789, вместо этого я получаю 56787.

Вот мой код

#include<iostream>
#include<bits/stdc++.h>

using namespace std;

long int oppositeNum(int n){

    if(n<10 && n>=0) return n;
    if(n<0) return 0;

    static int m=0;
    int x = n%10;
    long int num = oppositeNum(n/10);
    cout << num << "
";
    return (num+ (x*pow(10,++m)));
}

int main(){
    int n = 98765;
    int oppNum = oppositeNum(n);
    cout << oppNum;
    if(oppNum==n){
        cout << "Number is palindrome";
    }else{
        cout << "Number is not palindrome";
    }
    return 0;
}

Я не получаю полную противоположность моему первоначальному номеру. последняя цифра уменьшается на 1 каждый раз, что я и наблюдал. Кто-нибудь может помочь?

Всего 6 ответов


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

long int oppositeNum(int n, int &m){
    if(n<10) return n;

    int x = n%10;
    long int num = oppositeNum(n/10, m);
    cout << num << "
";
    m *= 10;
    return num + x * (long int)m;
}
long int oppositeNum(int n){
    if(n<0) return 0;
    int m = 1;
    return oppositeNum(n, m);
}

Что я изменил:

  1. Убрал static модификатор из m и вместо этого передал его по ссылке. Это позволяет использовать функцию более одного раза во время выполнения программы. (Также это позволило бы использовать функцию несколькими потоками одновременно, но я думаю, что это не проблема).
  2. Я удалил функцию с плавающей точкой pow и вместо этого просто умножил переменную m на десять на каждую итерацию.
  3. Я добавил оболочку для рекурсивной функции, чтобы ее можно было вызывать только с одним аргументом. Кроме того, это позволяет проверять отрицательные числа только один раз.

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


Попробуй это:

return round(num+ (x*pow(10,++m)));

Иногда функция pow возвращает приблизительный результат. например, pow(10, 5) может быть 9999.9999999 , если вы округлите его, вы получите 100000, в противном случае он принимает минимальное значение (я думаю).


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

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

Вы можете написать функцию без использования функции pow .

Учтите, что обратное число может быть слишком большим, чтобы хранить объект типа long, потому что в некоторых системах тип long имеет такую ​​же ширину, что и тип int. Поэтому я настраиваю вместо типа long использовать тип long long в качестве возвращаемого типа.

А, вот и ты.

#include <iostream>

long long int oppositeNum( int n )
{
    static long long int multiplier = 1;

    const int Base = 10;

    int digit = n % Base;

    return ( n /= Base ) == 0 
           ? ( multiplier = 1, digit ) 
           : ( n = oppositeNum( n ) , multiplier *= Base, digit  * multiplier + n );
}

int main() 
{
    int n = 12321;

    std::cout << n << " -> " << oppositeNum( n ) << '
'

    n = - 12321;

    std::cout << n << " -> " << oppositeNum( n ) << '
'

    n =  98765;

    std::cout << n << " -> " << oppositeNum( n ) << '
'

    n = -98765;

    std::cout << n << " -> " << oppositeNum( n ) << '
'

    return 0;
}

Выход программы

12321 -> 12321
-12321 -> -12321
98765 -> 56789
-98765 -> -56789

Другой подход заключается в преобразовании числа в строку и сравнении концов строк в середине, как в этом примере std::equal :

#include <algorithm> // std::equal
#include <iterator>  // std::next
#include <string>    // std::to_string

bool is_palindrome(const std::string& str) {
    return 
        std::equal(
            str.begin(),                            // iterator starting from the beginning
            std::next(str.begin(), str.size() / 2), // iterator pointing at the middle
            str.rbegin()                            // reverse iterator from the end
        );
}

Затем вызовите его с вашей числовой переменной:

bool result = is_palindrome( std::to_string(numeric_variable) );

Обратите внимание, что #include<bits/stdc++.h> следует избегать по причинам, указанным в
Почему я не должен #include <bits/stdc++.h> ?


Обратите внимание, что pow возвращает double, поэтому номер тура может быть обрезан, потому что вся функция возвращает int .

Я думаю, что следующий подход является хорошим подходом

   #include<string>

    bool palindrome(const std::string& s, size_t  i=0){

        if( s.size() == 0 || i==s.size()/2) return true;    
        return  s[i] == s[s.size()-i-1] && palindrome(s, ++i);
    }
    bool palindrome(int number){
        return palindrome(std::to_string(number));

    }

    return (num + float(x*pow(10,++m)));

Просто сделай это, и это сработает. Ответ неправильный, потому что пау-функ выдает 4999 и 5999, поэтому он меняет расположение юнитов.


Есть идеи?

10000