Determining if a number is either a multiple of ten or within a particular set of ranges

34,734

Solution 1

For the first one, to check if a number is a multiple of use:

if (num % 10 == 0) // It's divisible by 10

For the second one:

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

But that's rather dense, and you might be better off just listing the options explicitly.


Now that you've given a better idea of what you are doing, I'd write the second one as:
   int getRow(int num) {
      return (num - 1) / 10;
   }

   if (getRow(num) % 2 == 0) {
   }

It's the same logic, but by using the function we get a clearer idea of what it means.

Solution 2

if (num is a multiple of 10) { do this }

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

if (num is within 11-20, 31-40, 51-60, 71-80, 91-100) { do this }

The trick here is to look for some sort of commonality among the ranges. Of course, you can always use the "brute force" method:

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

But you might notice that, if you subtract 1 from num, you'll have the ranges:

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

In other words, all two-digit numbers whose first digit is odd. Next, you need to come up with a formula that expresses this. You can get the first digit by dividing by 10, and you can test that it's odd by checking for a remainder of 1 when you divide by 2. Putting that all together:

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

Given the trade-off between longer but maintainable code and shorter "clever" code, I'd pick longer and clearer every time. At the very least, if you try to be clever, please, please include a comment that explains exactly what you're trying to accomplish.

It helps to assume the next developer to work on the code is armed and knows where you live. :-)

Solution 3

If you are using GCC or any compiler that supports case ranges you can do this, but your code will not be 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;
}

Solution 4

This is for future visitors more so than a beginner. For a more general, algorithm-like solution, you can take a list of starting and ending values and check if a passed value is within one of them:

template<typename It, typename Elem>
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;
    });
}

For simplicity, I used a polymorphic lambda (C++14) instead of an explicit pair argument. This should also probably stick to using < and == to be consistent with the standard algorithms, but it works like this as long as Elem has <= defined for it. Anyway, it can be used like this:

std::pair<int, int> 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);

There's a live example here.

Solution 5

The first one is easy. You just need to apply the modulo operator to your num value:

if ( ( num % 10 ) == 0)

Since C++ is evaluating every number that is not 0 as true, you could also write:

if ( ! ( num % 10 ) )  // Does not have a residue when divided by 10

For the second one, I think this is cleaner to understand:

The pattern repeats every 20, so you can calculate modulo 20. All elements you want will be in a row except the ones that are dividable by 20.

To get those too, just use num-1 or better num+19 to avoid dealing with negative numbers.

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

This is assuming the pattern repeats forever, so for 111-120 it would apply again, and so on. Otherwise you need to limit the numbers to 100:

if ( ( ( ( num + 19 ) % 20 ) > 9 ) && ( num <= 100 ) )
Share:
34,734

Related videos on Youtube

user3419168
Author by

user3419168

Updated on August 20, 2020

Comments

  • user3419168
    user3419168 over 3 years

    I have a few loops that I need in my program. I can write out the pseudo code, but I'm not entirely sure how to write them logically.

    I need -

    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
    

    This is for a snakes and ladders board game, if it makes any more sense for my question.

    I imagine the first if statement I'll need to use modulus. Would if (num == 100%10) be correct?

    The second one I have no idea. I can write it out like if (num > 10 && num is < 21 || etc.), but there has to be something smarter than that.

    • luqui
      luqui about 10 years
      Generally, the length of good code is proportional to the length of the english describing what it does. So when your "specification" says 11-20, 31-40, 51-60, 71-80, 91-100, you can expect your code to mention those numbers also. If those numbers come from somewhere or were generated by some reason, see if you can code the reason rather than the numbers.
    • Eric Lippert
      Eric Lippert about 10 years
      @user3419168: The compiler cares not a bit how readable your code is; it will compile it in a fraction of a second. But for the humans reading your code, the choices you make can cause it to be comprehended in seconds, minutes, hours, or never. This imposes a cost; people get paid to read and understand code, so make it easy on them. Always write production code to maximize readability, and remember that concision does not necessarily make code perform better.
    • jscs
      jscs almost 10 years
      The titles on your other two questions are really good titles; they describe precisely what the question is about technically. I've edited this one because it was vague, and more about you than the coding problem.
    • eggyal
      eggyal almost 10 years
      I can't think why, in a standard game of snakes and ladders, it would ever be necessary to discover this information. Could you elaborate on how this code is likely to be used? I only ask because it doesn't strike me as a very object-oriented design and there might be a better way.
    • Floris
      Floris almost 10 years
      @EricLippert your point is extremely valid. I too see people writing "clever" code, oblivious to the fact that the only person who might care about their cleverness (the next person reading the code) will hate them for it, and with no visible performance benefit. Makes you weep.
    • Chris Middleton
      Chris Middleton almost 10 years
      @Floris In those situations I sometimes leave the original, un-optimized code in, but commented out. I think it helps the reader figure out what's going on.
    • Floris
      Floris almost 10 years
      @AmadeusDrZaius - I have VERY RARELY done the same, but only for performance critical sections. The tightest loop that is called 100M times qualifies - the if statement in a game of snakes and ladders does not. Where you draw the line between them is a personal choice.
    • Richard Le Mesurier
      Richard Le Mesurier almost 10 years
      I hate to say it, but having done enough corporate work, with beginners writing real code, I'd have to recommend brute forcing it. Because then the new guys will understand it and will not break it. sad but true - in some cases its smart to be dumb.
    • GaTechThomas
      GaTechThomas almost 10 years
      This is a decent question, and I don't want to take anything away from the poster at all, but this does not deserve 500+ points. This is how we end up with some of the nonsense we do with people with thousands of points appearing to be authorities here. (Feel free to move this comment if it belongs elsewhere.)
    • smirkingman
      smirkingman almost 10 years
      @floris ... and where you draw the line in Snakes and Ladders is of the utmost importance >;-)
    • Dawood ibn Kareem
      Dawood ibn Kareem almost 10 years
      @eggyal It tells you the direction to the next square. 1-10 go left-to-right along the bottom of the board. Then 11 is above 10 and 11-20 go right-to-left along the second row up; and so on. So the OP is trying to work out whether to move the counter upwards (if n is a multiple of 10), to the right (if n is in 1-9, 21-29 etc) or to the left (if n is in 11-19, 31-39 etc).
  • Daniel Kamil Kozar
    Daniel Kamil Kozar about 10 years
    if((num - 1) / 10) % 2 == 1 && num < 100) - I'd cry if I saw that.
  • Winston Ewert
    Winston Ewert about 10 years
    @DanielKamilKozar, as you should.
  • 101010
    101010 about 10 years
    Correct x < 41 x > 50 and put parentheses.
  • Anonymous
    Anonymous about 10 years
    One more thing: Sorry for nitpicking here, but it should be num <= 100 to include 100 (or however it would be written in c++).
  • user3419168
    user3419168 about 10 years
    Thanks! The second solution is clever I think, but why would it be bad practice? I assume it is because of Daniel's response. Because of readability?
  • Winston Ewert
    Winston Ewert about 10 years
    @user3419168, just by itself it leaves one to wonder what in the world it means. It gives no hints as to what in the world its trying to do. That's why in the edit I showed a version that splits the logic into a function which makes it clearer what the calculations are actually doing.
  • chris
    chris about 10 years
    @40two, Technically, operator&& has a higher precedence than operator||, so it's fine, but I'm pretty sure GCC warns about it anyway.
  • Jongware
    Jongware about 10 years
    It may be prudent to also assert num >= 11 as (1) that lower limit is proscribed, and (2) % on a negative number returns a negative number as well. (I must admit using & 1 here is "safer" but also assumes additional knowledge.)
  • Kevin Lam
    Kevin Lam about 10 years
    Neat solution. I would probably have used a single array, since you can format it with 2 numbers per line to represent pairs.
  • WernerCD
    WernerCD about 10 years
    It might also be wise to add the modulo definition and WHY x % 10 == 0 works. No one has felt the need to cover that minor detail.
  • chris
    chris about 10 years
    @HunterGuy2, Very good point. I'm actually going to change it to operate on pairs because I was only thinking about zip iterators for some reason.
  • chris
    chris about 10 years
    I'd still go for the clever code, but turn it into maintainable code by extracting functions. It would be just as readable if that last bit said && isTensDigitOdd(num), perhaps with a comment before the function definition explaining what it does. If such a pattern exists, a comment explaining the reasoning for the pattern is enlightening for maintainability imo.
  • Eric Lippert
    Eric Lippert about 10 years
    Consider representing the inequality 10 < x < 21 as 10 < x && x < 21 rather than x > 10 && x < 21. It's easier to read the inequality when it is in the same order as you'd write it mathematically.
  • M Sharath Hegde
    M Sharath Hegde almost 10 years
    Can you please tell me why this code is not portable ?
  • Bryan Chen
    Bryan Chen almost 10 years
    @MSharathHegde because it require GCC extension, which is not part of standard and some compiler won't support it
  • Dariusz
    Dariusz almost 10 years
    This code is fairly unreadable and says little about actual logic. I dislike this answer.
  • smirkingman
    smirkingman almost 10 years
    This is the right answer, because it's immediately apparent what the intent is. All those 'clever' answers with modulo are a maintenance nightmare, even with comments.
  • Adam Liss
    Adam Liss almost 10 years
    Chris, that's a great strategy when the "cleverness" has a clear advantage: much shorter code (which means less chance of a typo, especially if it changes), or a large improvement in efficiency. There's almost always a tradeoff between brevity, clarity, and efficiency, and finding a good compromise is a great skill to develop. (See stackoverflow.com/a/2151844/29157 for a snicker.)
  • user1477388
    user1477388 almost 10 years
    This is a much better approach. So much easier to understand than the 'clever code' and the performance difference is probably negligible.
  • Mr.Mindor
    Mr.Mindor almost 10 years
    +1 for the Edit, it gets into the why of the list of ranges and presents it in a readable manner. IMO, one step up would be to wrap the getRow(num) % 2 == 0 in a function as well to make it crystal clear what the intent is. bool inEvenRow(int num){ return getRow(num) % 2 ==0;}
  • Justin
    Justin almost 10 years
    The first comment is unneeded. Any programmer with a little experience will know that num % 10 == 0 is the same thing as num is a multiple of 10.
  • La-comadreja
    La-comadreja almost 10 years
    yes but beginners read this site too. I wouldn't normally use that comment in my own code but it does make the answer clearer to the beginners who would benefit from this beginner question.
  • Bruno Ferreira
    Bruno Ferreira almost 10 years
    I am downvoting this because you answered exactly what the OP did.
  • chris
    chris almost 10 years
    @AdamLiss, Yes, my opinion is of little value as I haven't had enough experience to see the repercussions of these decisions. I'm sure I will soon enough, and I'll be sure to get a second opinion if needed.
  • Adam Liss
    Adam Liss almost 10 years
    Don't sell yourself short. Your instincts are very sensible, and you seem eager to keep learning. Every opinion is valuable if there's a good reason behind it ... and sometimes even if there isn't. I'd bet money that you'll go far.
  • Winston Ewert
    Winston Ewert almost 10 years
    @AmadeusDrZaius, while I find that clever, I don't actually find it gives me any more idea of what the calculations mean.
  • Chris Middleton
    Chris Middleton almost 10 years
    @WinstonEwert To me, the difference is that yours consists of two statements, one of which is very complex, whereas this consists of three statements, all of which are simple. Having the three operations -, /, % all together makes my brain hang if I can't make sense of it right away, but maybe that's just me.
  • Cole Tobin
    Cole Tobin almost 10 years
    Couldn't you just use x & 1 instead of x % 2 == 1?
  • Laurence Renshaw
    Laurence Renshaw almost 10 years
    I've also up-voted Floris' answer - a different style of achieving a similar result, that I didn't see before I wrote my answer
  • Bryan Chen
    Bryan Chen almost 10 years
    you should use inline function instead of #define
  • higuaro
    higuaro almost 10 years
    Really nice stl approach! Love it!
  • rmobis
    rmobis almost 10 years
    Isn't it trying to push it too far with YES and NO?
  • Sebastian Mach
    Sebastian Mach almost 10 years
    @user3419168: In some guidelines it is said that clever code, while clever, should be avoided, because it is clever. Think about some constructs in maths, which are clever, but which are unobvious. In programming, obviousness is worth a lot of money when it comes to changes and fixes.
  • Floris
    Floris almost 10 years
    @Raphael_ - it might well be: I was just showing a "for instance". Many people use true/false, obviously. But I can never remember (because different languages use different conventions): is is TRUE, True, or true? And what, if any, header files would I need to include in ordinary C? So I rolled my own. Wonder if that's what got a downvote...
  • Richard Le Mesurier
    Richard Le Mesurier almost 10 years
    @smirkingman Indeed that's what I said in my comment to the main question. It just takes some experience of new coders in a corporate job to realise that the obvious way is often way better than the smart-ninja way.
  • Richard Le Mesurier
    Richard Le Mesurier almost 10 years
    +1 for the brute force - because it can be understood by anyone who comes around, no matter how stressed or tired. Of course this comment really only applies to the corporate world - if its your own code, feel free to use whichever ninja shorthand you enjoy most on the day
  • Serpiton
    Serpiton almost 10 years
    In the OP question the check for the multiple of 10 is not related to the range check, and in the range check 20 need to be on the same range of 11, with your code ((20 / 10) % 2) -> (2 % 2) -> 0
  • lauCosma
    lauCosma almost 10 years
    why do you think that this is the wrong question? just because i didn't provide an example on the OP case does not mean that i answered the wrong question...
  • smirkingman
    smirkingman almost 10 years
    Surely somebody must be able to rewrite this as one-liner, preferably with shift operators and a combination of several pre and post-increments, to ensure that the intent is utterly opaque?
  • Dawood ibn Kareem
    Dawood ibn Kareem almost 10 years
    @AmadeusDrZaius Why would you include (num % 20) <= 20? This is true for all values of num. You actually wanted to write num % 20 == 0 || num % 20 >= 11, but in my opinion, a good alternative is (num - 1) % 20 >= 10
  • Chris Middleton
    Chris Middleton almost 10 years
    @DavidWallace You're right, don't know what I was thinking. Removed it since it was incorrect.
  • Dawood ibn Kareem
    Dawood ibn Kareem almost 10 years
    Please don't ever do this. It actually reduces readability, by slowing down the reader and forcing them to read everything twice. Any programmer who doesn't understand that if (num % 10 == 0) means the same as // Check if it's a multiple of 10 should not be maintaining your code. This is a well-known anti-pattern.
  • Dawood ibn Kareem
    Dawood ibn Kareem almost 10 years
    It's good practice when you use function-like #define instructions, to put parentheses around the arguments, where they appear in the expansion. So instead of #define finished(num) (num == lastSquare) you should write #define finished(num) ((num) == lastSquare). The reason is that if you use such an instruction with an expression containing an operator with a low enough precedence, you won't get the answer you expect. In this case, if you don't use the extra parentheses, then finished(a & b) expands into (a & b == lastSquare) which is almost certainly not what you want.
  • La-comadreja
    La-comadreja almost 10 years
    @DavidWallace see comment above. We can't guarantee that the readers of this post will know this anti-pattern.
  • Dawood ibn Kareem
    Dawood ibn Kareem almost 10 years
    No, I mean that commenting each line to say what it does is an anti-pattern. I don't mean that using % is an anti-pattern; obviously it is not. Really, assuming that many of the readers of this post will be beginners, teaching them this style of writing comments is making a negative contribution to their development as programmers.
  • sidgeon smythe
    sidgeon smythe about 8 years
    The % 2 == 1 became % 2 == 0 after the rewriting; you may want to fix it. :)
  • Preston L. Bannister
    Preston L. Bannister over 7 years
    Minor addition - a function for the second condition would be slightly clearer. bool oddRow(int num) { return 1 & getRow(num); }