Déterminer si un nombre est un multiple de dix ou dans un ensemble particulier de plages

J’ai quelques boucles dont j’ai besoin dans mon programme. Je peux écrire le pseudo-code mais je ne sais pas trop comment l’écrire logiquement.

J’ai besoin –

if (num is a multiple of 10) { do this } if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this } else { do this } //this part is for 1-10, 21-30, 41-50, 61-70, 81-90 

Ceci est pour un jeu de société de serpents et échelles, si cela a plus de sens pour ma question.

J’imagine que la première si j’aurai besoin d’utiliser le module, if (num == 100%10) serait correct?

Le second je n’en ai aucune idée. Je peux l’écrire comme if (num > 10 && num is < 21 || etc) mais il doit y avoir quelque chose de plus intelligent.

    Pour le premier, vérifier si un nombre est un multiple d’utilisation:

     if (num % 10 == 0) // its divisible by 10 

    Pour le second:

     if(((num - 1) / 10) % 2 == 1 && num < = 100) 

    Mais c'est plutôt dense, vous feriez mieux de lister explicitement les options.


    Maintenant que vous avez donné une meilleure idée de ce que vous faites, j'écrirais le second comme suit:

      int getRow(int num) { return (num - 1) / 10; } if (getRow(num) % 2 == 0) { } 

    C'est la même logique, mais en utilisant la fonction, nous avons une idée plus claire de ce que cela signifie.

    si (num est un multiple de 10) {do this}

     if (num % 10 == 0) { // Do something } 

    si (num est compris entre 11-20, 31-40, 51-60, 71-80, 91-100) {faites ceci}

    L’astuce consiste ici à rechercher des points communs entre les gammes. Bien sûr, vous pouvez toujours utiliser la méthode “force brute”:

     if ((num > 10 && num < = 20) || (num > 30 && num < = 40) || (num > 50 && num < = 60) || (num > 70 && num < = 80) || (num > 90 && num < = 100)) { // Do something } 

    Mais vous remarquerez peut-être que si vous soustrayez 1 de num , vous aurez les plages suivantes:

     10-19, 30-39, 50-59, 70-79, 90-99 

    En d'autres termes, tous les nombres à deux chiffres dont le premier chiffre est impair. Ensuite, vous devez trouver une formule qui exprime cela. Vous pouvez obtenir le premier chiffre en le divisant par 10, et vous pouvez vérifier qu'il est étrange en vérifiant le rest de 1 lorsque vous divisez par 2. Le tout:

     if ((num > 0) && (num < = 100) && (((num - 1) / 10) % 2 == 1)) { // Do something } 

    Compte tenu du compromis entre un code plus long mais maintenable et un code "intelligent" plus court, je choisirais chaque fois plus longtemps et plus clairement. À tout le moins, si vous essayez d'être intelligent, veuillez inclure un commentaire qui explique exactement ce que vous essayez d'accomplir.

    Il est utile de supposer que le prochain développeur à travailler sur le code est armé et sait où vous habitez. 🙂

    Si vous utilisez GCC ou tout autre compilateur qui prend en charge les plages de valeurs, vous pouvez le faire, mais votre code ne sera pas portable.

     switch(num) { case 11 ... 20: case 31 ... 40: case 51 ... 60: case 71 ... 80: case 91 ... 100: // do something break; default: // do something else break; } 

    C’est pour les futurs visiteurs plus qu’un débutant. Pour une solution plus générale, semblable à un algorithme, vous pouvez prendre une liste de valeurs de début et de fin et vérifier si une valeur transmise est comprise dans l’une d’entre elles:

     template bool in_any_interval(It first, It last, const Elem &val) { return std::any_of(first, last, [&val](const auto &p) { return p.first < = val && val <= p.second; }); } 

    Pour simplifier, j'ai utilisé un lambda polymorphe (C ++ 14) au lieu d'un argument de pair explicite. Cela devrait probablement aussi utiliser < et == pour être cohérent avec les algorithmes standard, mais cela fonctionne aussi longtemps que Elem a < = défini pour cela. De toute façon, il peut être utilisé comme ceci:

     std::pair intervals[]{ {11, 20}, {31, 40}, {51, 60}, {71, 80}, {91, 100} }; const int num = 15; std::cout < < in_any_interval(std::begin(intervals), std::end(intervals), num); 

    Il y a un exemple en direct ici .

    Le premier est simple, il vous suffit d’appliquer l’opérateur modulo à votre valeur num:

     if ( ( num % 10 ) == 0) 

    Si c ++ évalue chaque nombre qui n’est pas 0, vous pouvez également écrire:

     if ( ! ( num % 10 ) ) //does not have a residue when devided by 10 

    Pour la seconde, je pense que c’est plus propre à comprendre:

    Le motif se répète tous les 20, vous pouvez donc calculer modulo 20. Tous les éléments que vous voulez seront alignés sauf ceux qui peuvent être divisés par 20.

    Pour les obtenir aussi, utilisez simplement num-1 ou mieux num + 19 pour éviter de traiter des nombres négatifs.

     if ( ( ( num + 19 ) % 20 ) > 9 ) 

    Cela suppose que le motif se répète pour toujours, alors pour 111-120, il s’appliquerait à nouveau, et ainsi de suite. Sinon, vous devez limiter les nombres à 100:

     if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num < = 100 ) ) 

    Avec quelques bons commentaires dans le code, il peut être écrit de manière assez concise et lisible.

     // Check if it's a multiple of 10 if (num % 10 == 0) { ... } // Check for whether tens digit is zero or even (1-10, 21-30, ...) if ((num / 10) % 2 == 0) { ... } else { ... } 

    Vous avez expliqué la réponse vous-même mais voici le code juste au cas où.

     if((x % 10) == 0) { //do this } if((x > 10 && x < 21) || (x > 30 && x < 41) || (x > 50 && x < 61) || (x > 70 && x < 81) || (x > 90 && x < 101)) { //do this } 

    Vous pensez peut-être cela.

     if (x % 10) { .. code for 1..9 .. } else { .. code for 0, 10, 20 etc. } 

    La première ligne if (x % 10) fonctionne parce que (a) une valeur qui est un multiple de 10 se calcule en ‘0’, les autres résultent en leur rest, (b) une valeur de 0 dans un if est considérée false , toute une autre valeur est true .

    Modifier:

    Pour basculer dans les années 20, utilisez le même tour. Cette fois, le chiffre pivot est 10 :

     if (((x-1)/10) & 1) { .. code for 10, 30, .. } else { .. code for 20, 40, etc. } 

    x/10 renvoie un nombre compris entre 0 et 9, 0 , 10 et 19, et ainsi de suite. Test sur pair ou impair – le & 1 – vous indique si c’est pair ou impair. Puisque vos plages sont en fait “11 à 20”, soustrayez 1 avant de tester.

    Un plaidoyer pour la lisibilité

    Bien que vous ayez déjà de bonnes réponses, je voudrais vous recommander une technique de programmation qui rendra votre code plus lisible pour certains futurs lecteurs – cela peut être vous en six mois, un collègue invité à effectuer une révision du code, votre successeur, .. .

    Cela consiste à envelopper des instructions “intelligentes” dans une fonction qui montre exactement (avec son nom) ce qu’elle fait. Bien qu’il y ait un impact minime sur les performances (à partir de “l’appel de fonction overhead”), c’est vraiment négligeable dans une situation de jeu comme celle-ci.

    En chemin, vous pouvez assainir vos entrées – par exemple, tester les valeurs “illégales”. Ainsi, vous pourriez vous retrouver avec du code comme celui-ci – voyez à quel point il est plus lisible? Les “fonctions auxiliaires” peuvent être cachées quelque part (il n’est pas nécessaire d’être dans le module principal: leur nom indique clairement ce qu’elles font):

     #include  enum {NO, YES, WINNER}; enum {OUT_OF_RANGE=-1, ODD, EVEN}; int notInRange(int square) { return(square < 1 || square > 100)?YES:NO; } int isEndOfRow(int square) { if (notInRange(square)) return OUT_OF_RANGE; if (square == 100) return WINNER; // I am making this up... return (square % 10 == 0)? YES:NO; } int rowType(unsigned int square) { // return 1 if square is in odd row (going to the right) // and 0 if square is in even row (going to the left) if (notInRange(square)) return OUT_OF_RANGE; // trap this error int rowNum = (square - 1) / 10; return (rowNum % 2 == 0) ? ODD:EVEN; // return 0 (ODD) for 1-10, 21-30 etc. // and 1 (EVEN) for 11-20, 31-40, ... } int main(void) { int a = 12; int rt; rt = rowType(a); // this replaces your obscure if statement // and here is how you handle the possible return values: switch(rt) { case ODD: printf("It is an odd row\n"); break; case EVEN: printf("It is an even row\n"); break; case OUT_OF_RANGE: printf("It is out of range\n"); break; default: printf("Unexpected return value from rowType!\n"); } if(isEndOfRow(10)==YES) printf("10 is at the end of a row\n"); if(isEndOfRow(100)==WINNER) printf("We have a winner!\n"); } 

    Pour le premier:

     if (x % 10 == 0) 

    s’appliquera à:

     10, 20, 30, .. 100 .. 1000 ... 

    Pour le second:

     if (((x-1) / 10) % 2 == 1) 

    demandera pour:

     11-20, 31-40, 51-60, .. 

    Nous faisons d’abord d’abord x-1 pour obtenir:

     10-19, 30-39, 50-59, .. 

    Ensuite, nous les divisons par 10 pour obtenir:

     1, 3, 5, .. 

    Nous vérifions donc si ce résultat est impair.

    Vous pouvez essayer ce qui suit:

      // multiple of 10 if ((num % 10) == 0) { // Do something } else if (((num / 10) % 2) != 0) { //11-20, 31-40, 51-60, 71-80, 91-100 } else { //other case } 

    Comme d’autres l’ont fait remarquer, rendre les conditions plus concises n’accélérera pas la compilation ni l’exécution, et ne consortingbuera pas nécessairement à la lisibilité.

    Où il peut aider est de rendre votre programme plus flexible, au cas où vous décidez plus tard que vous voulez une version du jeu du tout-petit sur une carte 6 x 6, ou une version avancée (que vous pouvez jouer toute la nuit) sur un 40 x 50 tableau.

    Donc, je coderais comme suit:

     // What is the size of the game board? #define ROWS 10 #define COLUMNS 10 // The numbers of the squares go from 1 (bottom-left) to (ROWS * COLUMNS) // (top-left if ROWS is even, or top-right if ROWS is odd) #define firstSquare 1 #define lastSquare (ROWS * COLUMNS) // We haven't started until we roll the die and move onto the first square, // so there is an imaginary 'square zero' #define notStarted(num) (num == 0) // and we only win when we land exactly on the last square #define finished(num) (num == lastSquare) #define overShot(num) (num > lastSquare) // We will number our rows from 1 to ROWS, and our columns from 1 to COLUMNS // (apologies to C fanatics who believe the world should be zero-based, which would // have simplified these expressions) #define getRow(num) (((num - 1) / COLUMNS) + 1) #define getCol(num) (((num - 1) % COLUMNS) + 1) // What direction are we moving in? // On rows 1, 3, 5, etc. we go from left to right #define isLeftToRightRow(num) ((getRow(num) % 2) == 1) // On rows 2, 4, 6, etc. we go from right to left #define isRightToLeftRow(num) ((getRow(num) % 2) == 0) // Are we on the last square in the row? #define isLastInRow(num) (getCol(num) == COLUMNS) // And finally we can get onto the code if (notStarted(mySquare)) { // Some code for when we haven't got our piece on the board yet } else { if (isLastInRow(mySquare)) { // Some code for when we're on the last square in a row } if (isRightToLeftRow(mySquare)) { // Some code for when we're travelling from right to left } else { // Some code for when we're travelling from left to right } } 

    Oui, c’est verbeux, mais cela montre clairement ce qui se passe sur le plateau de jeu.

    Si je développais ce jeu pour l’afficher sur un téléphone ou une tablette, je créerais des variables ROWS et COLUMNS au lieu de constantes, afin qu’elles puissent être définies dynamicment (au début d’un jeu) pour correspondre à la taille de l’écran et à son orientation. Je permettrais également de changer l’orientation de l’écran à tout moment, en cours de partie – il suffit de changer les valeurs de ROWS et COLUMNS, tout en laissant tout le rest (le numéro de carrés début / fin de tous les serpents et échelles) inchangés. Ensuite, il suffit de dessiner le tableau et d’écrire du code pour vos animations (je suppose que c’était le but de vos instructions if ) …

    Je sais que cette question a tellement de réponses, mais je jetterai la mienne ici de toute façon … Extrait du Code Complete 2nd Edition de Steve McConnell: “Stair-Step Access Tables:
    Un autre type d’access à la table est la méthode par étapes. Cette méthode d’access n’est pas aussi directe qu’une structure d’index, mais elle ne gaspille pas autant d’espace de données. L’idée générale des structures en escalier, illustrée à la figure 18-5, est que les entrées d’un tableau sont valides pour des plages de données plutôt que pour des points de données distincts. entrer la description de l'image ici

    Figure 18-5 L’approche en escalier classe chaque entrée en déterminant le niveau auquel elle atteint un «escalier». L’étape qu’elle atteint détermine sa catégorie.

    Par exemple, si vous écrivez un programme de notation, la plage de saisie «B» peut aller de 75% à 90%. Voici une gamme de notes que vous pourriez avoir à programmer un jour: entrer la description de l'image ici

    Pour utiliser la méthode en escalier, placez l’extrémité supérieure de chaque plage dans un tableau, puis écrivez une boucle pour vérifier un score par rapport à l’extrémité supérieure de chaque plage. Lorsque vous trouvez le point où le score dépasse le sumt d’une plage, vous savez quelle est la note. Avec la technique en escalier, vous devez veiller à bien gérer les extrémités des plages. Voici le code de Visual Basic qui assigne des notes à un groupe d’étudiants basé sur cet exemple:

    entrer la description de l'image ici

    Bien que ce soit un exemple simple, vous pouvez facilement le généraliser pour gérer plusieurs étudiants, plusieurs schémas de notation (par exemple, différentes notes pour différents niveaux de point sur différentes affectations) et des modifications du schéma de notation. ”

    Code Complete 2nd Edition pages 426 – 428 (Chapitre 18). J’espère que cela vous aidera et que je regrette de ne pas avoir converti le code en C ++, mais vous connaissez le vieil adage chinois: “Ne donnez pas de poisson à un mendiant, donnez-lui une canne à pêche!” 🙂

    Si vous n’avez jamais utilisé de langage de programmation orientée object (OOP), vous constaterez que la POO vous simplifie la vie.

    La réponse OOP de votre code est ici:

    (J’espère que vous écrirez vos codes orientés object l’année prochaine)

    entrer la description de l'image ici

     #include  #include  #include  using namespace std; class checker { public: checker(void) : m_num(0) { // Nothing. } ~checker(void) { // Nothing. } inline void set_num(int num) { if (num < 0) { throw invalid_argument("Invalid argument: num."); } m_num = num; return; } inline int get_num(void) const { return m_num; } protected: int m_num; }; /**********************************************************/ class multiple_checker : public checker { public: static const int MULTIPLE_OF = 10; multiple_checker(void) { // Nothing. } ~multiple_checker(void) { // Nothing. } virtual void do_this_for_multiple_checker(void) = 0; void check_multiple_of(void) { #if defined _DEBUG if (MULTIPLE_OF == 0) { throw exception("MULTIPLE_OF should not be zero."); } #endif if (m_num % MULTIPLE_OF == 0) { do_this_for_multiple_checker(); } return; } }; /**********************************************************/ class range_checker : public checker { public: range_checker(void) { // Nothing. } ~range_checker(void) { // Nothing. } virtual void do_this_1_for_range_checker(void) = 0; virtual void do_this_2_for_range_checker(void) = 0; void check_in_range(void) { return; } void check_range(void) { if (is_in_range()) { do_this_1_for_range_checker(); } else { do_this_2_for_range_checker(); } } private: bool is_in_range(void) const { if ( (m_num > 10 && m_num < 21) || (m_num > 30 && m_num < 41) || (m_num > 50 && m_num < 61) || (m_num > 70 && m_num < 81) || (m_num > 90 && m_num < 101) ) { return true; } else { return false; } } }; /**********************************************************/ class game : public multiple_checker, public range_checker { public: game(void) { // Nothing. } ~game(void) { // Nothing. } virtual void do_this_for_multiple_checker(void) { cout << "Number is a multiple of " << MULTIPLE_OF << "." << endl; } virtual void do_this_1_for_range_checker(void) { cout << "Number is in range." << endl; } virtual void do_this_2_for_range_checker(void) { cout << "Number is not in range." << endl; } }; /**********************************************************/ int main(int argc, char* argv[]) { game* g = new game(); g->multiple_checker::set_num(50); g->range_checker::set_num(13); g->check_multiple_of(); g->check_range(); delete g; g = NULL; return 0; }