Between nephews
- You look worried!
- I have a good reason to be worried.
- What’s up?
- I am trying to get a list of all my nephews who has birthday between November and March.
- I know how you feel. I have also a large family.
- If November is 11 and March is 3 which numbers are between 11 and 3?
- That is easy. 3, 4, 5, 6, 7, 8, 9, 10, and 11 are all between 11 and 3 in the included sense.
- That is the problem! The answer is 11, 12, 1, 2, and 3.
- I see what you mean.
- So how do I write this down as a condition my computer can understand?
- Do you have a Mac or a PC?

December 14th, 2009 at 12:12 am
In Excel or OOo Calc you can use the following formula (where A1 is the cell):
OR(MONTH(A1)10)
December 14th, 2009 at 12:13 am
Well, that would have been the right answer except that WordPress ate a part of it. Paraphrasing:
OR(MONTH(A1) is less than 4;MONTH(A1)>10)
but use a real “less than” sign.
December 14th, 2009 at 12:21 am
Fine, but what about the general problem: condition for all months between M1 and M2 where M1 comes chronologically before M2. M1 and M2 are not wider than a year apart.
For M1=11 and M2=3 your solution works, but not if M1=11 and M2=12.
December 14th, 2009 at 2:19 am
Using something resembling c code, substituting .ge. for => :
function boolean InMonth (nFromMonth, nToMonth, nTestMonth)
{ // return true if and only if nTestMonth is on or after nFromMonth and on or before nToMonth
if (nFromMonth .gt. nToMonth)
// nFromMonth is after nToMonth on calendar. nTestMonth has to be big enough or small enough
return ((nFromMonth .le. nTestMonth) || (nToMonth .ge. nTestMonth));
else
// nFromMonth is on or before nToMonth on calendar. nTestMonth has to be big enough and small enough
return ((nFromMonth .ge. nTestMonth) && (nToMonth .le. nTestMonth));
}
December 14th, 2009 at 6:37 am
Suppose we have a function which returns -1 if greater than, 0 if equal, and 1 if less than.
int DateComp(nMonth1, nMonth2)
{
if nMonth1==nmonth2 return 0
else if nMonth1 .lt. nMonth2 return 1
else if nMonth1 .gt. nMonth2 return -1
else head for the hills, tricotomy failed
}
(That last line might not be K&R c)
Then
nTestValue
= DateComp (nTestMonth, nFromMonth)
* DateComp (nTestMonth, nToMonth)
* DateComp (nFromMonth, nToMonth)
= -1 if and only if the test date falls outside the acceptable range.
December 14th, 2009 at 9:39 am
The simplest approach is usually best. In this case I’d just do this:
if birthmonth = 11 then…
Anything else requires more code which in turn makes it (1) confusing to read and (2) inefficient.
A common approach I’ve also used in the past is if month2-month1 < 0, month2 = month2 + 12, then proceed as normal. It really depends on how flexible you need the app to be.
December 14th, 2009 at 9:50 am
Hmm… my if then line in my post has a weird glitch in it. I typed O R (as one word, no space) and everything after it was skipped.
In pseudocode it should read like this: If birthmonth is less than or equal to 3 or is greater than or equal to 11 then…
December 14th, 2009 at 10:39 pm
If Mo ge M1 then let Adjmo=Mo else let Adjmo=Mo+12
If M2 ge M1 then let Adjm2=M2 else let Adjm2=M2+12
If Adjmo ge M1 and Adjmo le Adjm2 then true
December 14th, 2009 at 11:58 pm
I just realized that the first half of my final condition is superfluous and probably ridiculous; fixed below.
I wish I had a more intuitive answer though, that doesn’t seem contrived. What makes it hard for me is that this problem isn’t about who was born first or later on a timeline.
If Mo ge M1 then let Adjmo=Mo else let Adjmo=Mo+12
If M2 ge M1 then let Adjm2=M2 else let Adjm2=M2+12
If Adjmo le Adjm2 then true
December 15th, 2009 at 11:18 am
I’ll grant that pseudo code can be harder to read than a clean Excel formula. And we’re not VLSI chip designers. But if we were, my approach would be incredibly efficient.
First, note that bitwise XOR is a fast low level function. A XOR B = 1 if A and B are different. So 1100 XOR 0110 = 1010. Also, note that a 5 bit positive binary number goes from 0 to 31; 11111 = 31; 16+8+4+2+1. A 5 bit two’s complement number ranges from -16 to 15; the first bit is considered to be negative; 11111 = -1; -16+8+4+2+1.
So let’s see if January is between November and March.
* nTestMonth – nFromMonth = 1 – 11 = -10. The first bit is 1.
* nTestMonth – nToMonth = 1 – 3 = -2. The first bit is 1.
* nFromMonth – nToMonth = 11 – 3 = 8. The first bit is 0.
nTestMonth is between the other two months if and only if an even number of first bits are 1.
Having a computer perform those three subtractions is fast. Having a computer XOR the three differences is fast. Testing the result for the value of the first bit is fast. Actually, all of these operations are very fast. Much faster than the time it took to write this.