J'essaie d'implémenter l'algorithme de Luhn en langage C pour vérifier la validité de la carte de crédit, pour ceux qui ne le savent pas ... c'est ça:
Multipliez tous les autres chiffres par 2, en commençant par l'avant-dernier chiffre du numéro, puis ajoutez les chiffres de ces produits ensemble.
Ajoutez la somme à la somme des chiffres qui n'ont pas été multipliés par 2.
Si le dernier chiffre du total est 0 (ou, plus formellement, si le total
modulo 10 est congru à 0), le nombre est valide!
et pour implémenter cela, j'ai parcouru le nombre entier et si la place du nombre dans laquelle je me trouvais avait un modulo 2 égal à 0, je multiplierais par deux et ajouterais à une variable appelée totalEven
.
si ce n'était pas le cas, j'ajouterais le nombre dans totalOdd
à totalOdd
sans multiplication.
Je incrémenterais alors la place de un et vérifierais les autres nombres jusqu'à ce que j'atteigne 16 (le nombre maximum de chiffres pour une carte).
J'ajouterais plus tard les deux variables et vérifierais si le modulo dix total était égal à 0. Si cela signifie que le numéro de carte de crédit est correct, sinon il est faux.
voici le code:
#include <stdio.h> #include <cs50.h> long power(); int main(void) { //AMERX 15 STRT 34 OR 37 //MC 16 STRT 51, 52, 53, 54, 55 //VZA 13 OR 16 STRT 4 long input; bool isValid = true; string type; int mod = 10; int place = 1; int num = 0; int totalEven = 0; int totalOdd = 0; do { input = get_long("Number: "); } while(input < 0); for(int i = 0; i < 16; i++) { num = ((input % mod) - (input % (mod /10))) / (mod/10); if(place % 2 == 0) { totalEven = totalEven + num * 2; } else { totalOdd = totalOdd + num; } mod = mod * 10; place++; } if((totalEven + totalOdd) % 10 == 0 ) { isValid = true; } else { isValid = false; printf("%i , %i", totalEven, totalOdd); } if (isValid == true){ if((input < (38 * power(10, 13)) && input >=(37 * power(10, 13))) || (input < (35 * power(10,13)) && input >= (34 * power(10, 13)))) { type = "AMEX\n"; } else if(input >= (51 * power(10, 14)) && input < (56 * power(10, 14))) { type = "MASTERCARD\n"; } else if((input < (5 * power(10, 12)) && input >= (4 * power(10, 12))) || (input < (5 * power(10, 15)) && input >= (4 * power(10, 15)))) { type = "VISA\n"; } else{ type = "error\n"; } } else { type = "INVALID\n"; } if((totalEven + totalOdd) % 10 == 0 ) { isValid = true; } else { isValid = false; } printf("%s", type); } long power(int n, int p) { long result = 1; for(int i = 0; i<p; i++) { result = result * n; } return result;
//gets input and stores it in well.. input input = get_long("Number: "); // a formula to single out a number, starting with the ones and then as you can see, mod is muliplied by 10 to go over the second number. num = ((input % mod) - (input % (mod /10))) / (mod/10); //loops 16 times for(int i = 0; i < 16; i++) { // if the place is even execute below if(place % 2 == 0) { totalEven = totalEven + num * 2; } //else do this else if (place % 2 != 0) { totalOdd = totalOdd + num; } //moves to the next number mod = mod * 10; place++; } //fufils the last step of the algorithm if((totalEven + totalOdd) % 10 == 0 ) { isValid = true; } else { isValid = false; }
Le problème est que ce bloc de code me donne une valeur invalide ou !isValid
même si le numéro de carte de crédit est censé être correct et j'ai vérifié ma "formule" et cela fonctionne très bien ...
Je ne sais absolument pas quoi faire ... Je suis un modeste amateur, alors ne me rôtissez pas pour la monstruosité ci-dessus.
voici une version complète du code
#include <stdio.h> #include <cs50.h> //list of variables //is the card valid bool isValid = true; // the creditcard number long input; //mod stands for modules, and is used to single out each number as seen later int mod = 10; //the location at which number I am checking int place = 1; //num is the number I am checking that has been singled out int num = 0; //total of numbers * 2 located at locations numbered with even numbers int totalEven = 0; //total of numbers located at locations numbered with odd numbers int totalOdd = 0;
3 Réponses :
Pendant que je regardais votre code, je voudrais signaler certaines erreurs.
#include <string.h>
car vous avez déclaré string type
dans le code.input = get_long("Number: ");
devrait avoir sa propre boucle do-while
while au cas où l'utilisateur entre des lettres ou des nombres incorrects.if(place % 2 == 0){
totalEven = totalEven + num * 2;
}
else if (place % 2 != 0){
totalEven = totalEven + num;
}
devrait totalOdd = totalOdd + num
pour la deuxième partietotalEven = totalEven + num * 2
est juste et faux en même temps. Cela ne fonctionne que si le nombre multiplié par 2 est inférieur à 10. Si le nombre * 2> = 10, disons num = 6, alors 6 * 2 est 12 qui serait alors 1 + 2 + totalEven.num = ((input % mod) - (input % (mod /10))) / (mod/10);
Cela devrait être dans la première for loop
.#include <math.h>
, il y a une fonction power appelée pow
qui fait exactement comme votre fonction power()
.
A part: le type de string
n'est pas dans string.h
mais est un type non standard (et peu judicieux) dans cs50.h
qui a été inclus. Et pow()
est assez différent - il fonctionne avec des valeurs en virgule flottante. Il n'y en a même pas besoin, il existe de meilleures façons de décomposer un nombre.
Je vois, je n'étais pas au courant que la string
n'était pas une partie string.h
. Merci pour les informations sur pow()
.
@WeatherVane oui, en y repensant maintenant, j'aurais pu transformer l'ensemble du processus en un programme plus succinct ... peut-être que transformer l'intégralité de l'int en une chaîne puis l'utiliser comme un tableau pour valider le nombre saisi serait bien mieux ...
@ someGuy5864 il vaut mieux ne jamais avoir de numéro de carte, numéro de téléphone, code PIN, etc. sous forme d'entier en premier lieu. «Nombre» ne signifie pas «entier». Il est préférable de le traiter comme une chaîne de chiffres.
@WeatherVane ouais vrai ... merci pour l'homme de pointe
Je ne suis pas un expert en algorithme de Luhn, mais quand je lis https://en.wikipedia.org/wiki/Luhn_algorithm, il me semble que vous vous trompez.
Citation de https://en.wikipedia.org/wiki/Luhn_algorithm :
À partir du chiffre le plus à droite (à l'exclusion du chiffre de contrôle) et en se déplaçant vers la gauche, doublez la valeur de chaque deuxième chiffre. Le chiffre de contrôle n'est ni doublé ni inclus dans ce calcul; le premier chiffre doublé est le chiffre situé immédiatement à gauche du chiffre de contrôle. Si le résultat de cette opération de doublement est supérieur à 9 (par exemple, 8 × 2 = 16), ajoutez les chiffres du résultat (par exemple, 16: 1 + 6 = 7, 18: 1 + 8 = 9) ou, alternativement, le même résultat final peut être trouvé en soustrayant 9 de ce résultat (par exemple, 16:16 - 9 = 7, 18: 18 - 9 = 9).
Je ne vois nulle part dans votre code où vous gérez cette partie en gras.
Au lieu de
// Double every second element and check for overflow for (idx = 1; idx < 16; idx += 2) { digits[idx] = 2 * digits[idx]; if (digits[idx] > 9) digits[idx] = digits[idx] - 9; } // Calculate the sum sum = 0; for (idx = 0; idx < 16; ++idx) { sum = sum + digits[idx]; }
Je pense que tu as besoin
int digits[] = {8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1}; // Notice that index zero is the rightmost digit
Cela dit - je pense que vous rendez la mise en œuvre beaucoup plus complexe que nécessaire en stockant l'entrée sous forme de nombre. Au lieu d'un nombre, vous pouvez utiliser un tableau de chiffres.
C'est - au lieu de
long input = 1122334455667788
utilisation
int tmp = num * 2; if (tmp > 9) tmp = tmp - 9; totalEven = totalEven + tmp;
De cette façon, l'algorithme est beaucoup plus simple:
totalEven = totalEven + num * 2;
Si vous devez recevoir l'entrée sous forme de nombre, commencez par appeler une fonction qui convertit le nombre en un tableau de chiffres. Vous pouvez trouver de très nombreux exemples de la façon dont cette conversion est effectuée ici sur SO. Ici, la conversion d'un entier en tableau de chiffres n'est qu'un des nombreux exemples.
Merci mon pote pour le conseil, j'ai réécrit le code en utilisant un hybride de ce que vous avez suggéré et de ma méthode et cela a fonctionné !!
Attention: j'ai utilisé CS50X Library car la question semble être la même.
#include <stdio.h> #include <cs50.h> // Luhn's Algorithm int main(void) { long cardNumber = get_long("Please, enter your card number: "); int sum1 = 0, num = 0, remainder = 0, sum2 = 0; long temp = cardNumber; while (temp > 0) { num = ((temp / 10) % 10) * 2; // Multiplying every other digit by 2, starting with the numberâs second-to-last digit while (num > 0) { remainder = num % 10; sum1 += remainder; // Adding those productsâ digits together num /= 10; } temp /= 100; } // So as to restore the initial values of remainder and temp for the use in next loop remainder = 0; temp = cardNumber; while (temp > 0) { remainder = temp % 10; sum2 += remainder; // Sum of the digits that werenât multiplied by 2 temp /= 100; } ((sum1 + sum2) % 10) == 0 ? printf("Valid\n") : printf("Invalid\n"); return 0; }
Traitez les numéros de carte de crédit comme une chaîne de chiffres plutôt que comme un nombre. Il est plus facile de les traiter. Et vous pouvez vérifier qu'il y a 16 chiffres plus facilement. Il y a de nombreuses questions connexes dans la balise cs50 qui pourraient vous aider - toutes n'auront pas la balise luhn . Recherchez «
[cs50] luhn
».mod/10
est juste 10/10 qui est juste 1, donc je soupçonne qu'il y a une erreur dans `num = ((input% mod) - (input% (mod / 10))) / (mod / 10);`. Bien que sensiblement plus lent, je seconde l'idée que la manipulation des cordes serait plus facile à comprendre.Vous n'obtenez jamais chaque chiffre dans la boucle.
La
long
de votre ordinateur est-elle assez grande pour 16 chiffres? Essayez#include <limits.h>
etprintf("%ld\n", LONG_MAX);
suggestion de débogage: si vous êtes prêt à utiliser le module et les mathématiques pour faire l'extraction des chiffres, faites d'abord fonctionner cet algorithme et écrivez un programme qui le teste, en prenant un ensemble d'entrées et en vérifiant chaque sortie. Ensuite, développez à partir de là pour obtenir tous les autres chiffres pour chaque numéro. Une fois que cela fonctionne, terminez l'algorithme luhn avec ce code dont vous savez qu'il fonctionne.
C'est fou cependant, puisque le numéro de carte était à l'origine entré sous forme de chiffres. «Numéro» ne signifie pas automatiquement «entier», comme le
"221b Baker Street"
également les numéros de maison, tels que"221b Baker Street"
et les numéros de téléphone comme"0123456789"
où le0
principal essentiel serait perdu.@DanielFarrel Je sais que 10/10 est égal à 1, mais cela est censé se produire ... par exemple, si l'
input
était 1069 etmod
était 10, alorsnum
serait .... `num = ((1069% 10) - (1069% (10/10))) / (10/10); num = (9 - (1069% 1) / 1); num = (9 - 0/1); num = 9; `alors comme vous pouvez le voir si vous regardez le code plus profondément, lemod
est multiplié par 10 pour passer au chiffre suivant@Someprogrammerdude est-il possible de clarifier?
ah, alors le problème est que `num = ((input% mod) - (input% (mod / 10))) / (mod / 10); `est censé être dans la boucle
for
?@DanielFarrell oui, il est censé être là-dedans, et boucle 16 fois en déplaçant 16 chiffres
Votre code est bien trop complexe. Utilisez un tableau de chiffres au lieu d'un nombre où vous devez calculer le reste à l'intérieur de la boucle.