Parcourir un conteneur en partant de l'avant dernier élément

La carte bancaire est une fausse

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

J’essaye d’implémenter l’algorithme de Luhn utilisé, par exemple, pour vérifier la validité d’une carte bancaire. L’algorithme est le suivant :

  • L’algorithme multiplie par deux un chiffre sur deux, en commençant par l’avant dernier et en se déplaçant de droite à gauche. Si un chiffre qui est multiplié par deux est plus grand que neuf (comme c’est le cas par exemple pour 8 qui devient 16), alors il faut le ramener à un chiffre entre 1 et 9. Pour cela, il y a 2 manières de faire (pour un résultat identique) :

    • Soit les chiffres composant le doublement sont additionnés (pour le chiffre 8: on obtient d’abord 16 en le multipliant par 2 puis 7 en sommant les chiffres composant le résultat : 1+6).
    • Soit on lui soustrait 9 (pour le chiffre 8 : on obtient 16 en le multipliant par 2 puis 7 en soustrayant 9 au résultat).
  • La somme de tous les chiffres obtenus est effectuée.
  • Le résultat est divisé par 10. Si le reste de la division est égal à zéro, alors le nombre original est valide.
Wikipédia

Voici ce que j’ai tenté :

bool checksum(std::vector<unsigned>);

int main()
{
    std::vector<unsigned> sequence{ 5, 2, 0, 5, 5, 9, 7, 2, 3, 1, 1, 4, 7, 9, 0, 8 };

    if (checksum(sequence))
        std::cout << "The credit card is valid." << std::endl;
    else
        std::cout << "The credit card is not valid." << std::endl;
}

bool checksum(std::vector<unsigned> seq)
{
    for (auto it{ seq.rbegin() }; it != seq.rend(); it += 2) {
        *it *= 2;
    
        if (*it > 9) *it -= 9;
    }

    return std::accumulate(seq.begin(), seq.end(), 0) % 10 == 0;
    
}

Mon problème est que je ne respecte pas la condition "en commençant par l’avant dernier" car je ne vois pas comment le faire en utilisant les itérateurs. Ce qui implique que ma fonction me retourne un résultat erroné.

Comment parcourir une collection en partant de l’avant dernier élément ?

Merci pour votre aide !

Édité par Wizix

+0 -0

Oui j’ai essayé mais j’obtiens l’erreur suivante :

Expression: cannot seek vector iterator before begin

Wizix

Etrange, je viens d’essayer et en incrémentant par 2 tu sautes rend() donc ta boucle continue :o
J’avais jamais remarqué ça, je pensais que tout incrément au delà de rend revenait à rend Oo

edit : donc ta boucle for devient for(auto it { seq.rbegin()+1 }; it <= seq.rend(); it+=2)

Édité par leroivi

Ce n’est pas parce qu’ils sont nombreux à avoir tort qu’ils ont raison - Coluche

+0 -0
Auteur du sujet

Merci, je ne savais pas que l’on pouvait comparer des itérateurs avec les symboles < et >.
Seulement, ça ne fonctionne toujours pas. J’obtiens encore la même erreur. J’ai l’impression que mon compilateur, msvc (je ne sais pas si c’est lui qui gère ça), ne me laisse pas aller plus loin que seq.rend() (pour de bonnes raisons). J’ai lu ce post sur Stackoverflow mais pas moyen d’implémenter la solution avec des reverse_iterator. :(

Édité par Wizix

+0 -0
Auteur du sujet

pourquoi ?

leroivi

Très bonne question. :D La première fois que j’ai testé je comparais la distance entre it qui est un reverse_iterator et seq.end() qui est un iterator. Forcément il était pas fan et je n’avais pas trouvé mon erreur. Mais maintenant tout fonctionne pour le mieux !

bool checksum(std::vector<unsigned> seq)
{
    for (auto it{ seq.rbegin() + 1 }; ; std::advance(it, 2)) {
        *it *= 2;

        if (*it > 9) *it -= 9;

        if (std::distance(it, seq.rend()) < 2)
            break;
    }

    return std::accumulate(seq.begin(), seq.end(), 0) % 10 == 0;
    
}

Merci pour votre aide !

Édité par Wizix

+1 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte