Determining if a number is either a multiple of ten or within a particular set of ranges
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 ) )
Related videos on Youtube
user3419168
Updated on August 20, 2020Comments
-
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 about 10 yearsGenerally, 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 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 almost 10 yearsThe 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 almost 10 yearsI 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 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 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 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 almost 10 yearsI 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 almost 10 yearsThis 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 almost 10 years@floris ... and where you draw the line in Snakes and Ladders is of the utmost importance >;-)
-
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 about 10 years
if((num - 1) / 10) % 2 == 1 && num < 100)
- I'd cry if I saw that. -
Winston Ewert about 10 years@DanielKamilKozar, as you should.
-
101010 about 10 yearsCorrect
x < 41 x > 50
and put parentheses. -
Anonymous about 10 yearsOne more thing: Sorry for nitpicking here, but it should be
num <= 100
to include 100 (or however it would be written in c++). -
user3419168 about 10 yearsThanks! 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 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 about 10 years@40two, Technically,
operator&&
has a higher precedence thanoperator||
, so it's fine, but I'm pretty sure GCC warns about it anyway. -
Jongware about 10 yearsIt 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 about 10 yearsNeat solution. I would probably have used a single array, since you can format it with 2 numbers per line to represent pairs.
-
WernerCD about 10 yearsIt 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 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 about 10 yearsI'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 about 10 yearsConsider representing the inequality
10 < x < 21
as10 < x && x < 21
rather thanx > 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 almost 10 yearsCan you please tell me why this code is not portable ?
-
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 almost 10 yearsThis code is fairly unreadable and says little about actual logic. I dislike this answer.
-
smirkingman almost 10 yearsThis 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 almost 10 yearsChris, 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 almost 10 yearsThis is a much better approach. So much easier to understand than the 'clever code' and the performance difference is probably negligible.
-
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 almost 10 yearsThe first comment is unneeded. Any programmer with a little experience will know that
num % 10 == 0
is the same thing asnum
is a multiple of 10. -
La-comadreja almost 10 yearsyes 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 almost 10 yearsI am downvoting this because you answered exactly what the OP did.
-
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 almost 10 yearsDon'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 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 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 almost 10 yearsCouldn't you just use
x & 1
instead ofx % 2 == 1
? -
Laurence Renshaw almost 10 yearsI'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 almost 10 yearsyou should use inline function instead of
#define
-
higuaro almost 10 yearsReally nice stl approach! Love it!
-
rmobis almost 10 yearsIsn't it trying to push it too far with
YES
andNO
? -
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 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
, ortrue
? 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 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 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 almost 10 yearsIn 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 almost 10 yearswhy 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 almost 10 yearsSurely 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 almost 10 years@AmadeusDrZaius Why would you include
(num % 20) <= 20
? This is true for all values ofnum
. You actually wanted to writenum % 20 == 0 || num % 20 >= 11
, but in my opinion, a good alternative is(num - 1) % 20 >= 10
-
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 almost 10 yearsPlease 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 almost 10 yearsIt'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, thenfinished(a & b)
expands into(a & b == lastSquare)
which is almost certainly not what you want. -
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 almost 10 yearsNo, 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 about 8 yearsThe
% 2 == 1
became% 2 == 0
after the rewriting; you may want to fix it. :) -
Preston L. Bannister over 7 yearsMinor addition - a function for the second condition would be slightly clearer.
bool oddRow(int num) { return 1 & getRow(num); }