|
I found this:
http://latest-technology-guide.blogspot.nl/2013/03/c-language-example-36-find-date.html
(relatively recent, maybe it was inspired by this article)
Could be useful when you want to avoid macro evaluation side effects.
I tested it with Tiny C Compiler, code gives the same results as Excel's DATEDIF() .
#include <stdio.h>
#include <conio.h>
void main()
{
int d1, m1, y1, d2, m2, y2, m, temp, sum=0, month[]={31,28,31,30,31,30,31,31,30,31,30,31};
printf("Enter Date 1 : (DD-MM-YYYY) :");
scanf("%d %d %d", &d1, &m1, &y1);
printf("Enter Date 2 : (DD-MM-YYYY) :");
scanf("%d %d %d", &d2, &m2, &y2);
temp=d1;
for(m=m1; m<m2+(y2-y1)*12; m++)
{
if(m>12)
{
m=1;
y1++;
}
if(m==2)
{
if(y1%4==0 && (y1%100!=0 || y1%400==0))
month[m-1]=29;
else
month[m-1]=28;
}
sum=sum+(month[m-1]-temp);
temp=0;
}
sum=sum+d2-temp;
printf("\n Total Number of Days are : %5d", sum);
}
|
|
|
|
|
The weakest speed point in the current implementation are the modulo functions, if you do (Year&0x0003 == 0) instead of (Year%4 == 0) you will save one of those operations with
the exception of year 0.
|
|
|
|
|
I forgot to mention that 0x0003 was the uint16 case, for uint32 it would be 0x00000003.
|
|
|
|
|
Hello Rafa,
It has been a long time since I looked at this algorithm. When I wrote the algorithm, I should have remembered the optimizations involved with division/multiplications by powers of 2. Naturally, your suggestion would also apply to the case of (y-1)/4 as (y-1)>>2.
template <class t=""> IsLeapYear(const T& y)
{ return (y>0) && !(y&0x00000003) && ( (y%100) || !(y%400) ); }
template <class t=""> CountLeaps(const T& y)
{ return ((y-1)>>2) - (y-1)/100 + (y-1)/400; }
Thank you very much for catching that.
Ted N.
|
|
|
|
|
while(year >= 100 && year % 100 == 0)
{
year = year / 100;
}
IsLeap = (year % 4 == 0 && month == 2);
Codeideal...
|
|
|
|
|
It is always interesting to analyze alternative algorithms. I kept looking through your algorithm for the purpose of the while() loop.
It seems to me that the only purpose for the while() loop is to eliminate the (y%400) part of the IsLeapYear() macro in my article. The year is repatedly divided by 100 so that multiples of 400 can be treated as multiples of 4. That is an interesting alternative for (y%400); but I think a single modulo operation is much faster than a while() loop and a division operation.
|
|
|
|
|
Yes, i agree with u, about the efficiency. it just a different idea. so i used y%400 in the program.
public static bool IsDateA(int year, int month, int day)
{
if (month < 1 || month > 12 || day < 1 || year < 1
{
return false;
}
int leap = (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))?-1:-2;
leap = (month == 2)?leap ;
return ((30 + leap + (((month > 7)?month++ ) % 2)) >= day);
}
Codeideal...
|
|
|
|
|
It looks like your COUNT_YEARS macro might not work when we get to a point in time where there are more than 4 years worth of leap days as determined by the COUNT_LEAPS() macro. It's because you get an initial guess at the number of years with D/4 and then use that value to find the number of leap days in that number of years. When this situation occurrs, the D/4 will return a value that is 4 years greater than the true number of years. When you then COUNT_LEAPS on this, you'll get 1 extra leap day.
Luckily this won't occur till year 6888.
|
|
|
|
|
Thank you for finding the limit of the COUNT_YEARS algorithm. As you can see in the article, I took a little shortcut that proved to be numerically accurate for some time in the future. I never bothered analyzing the algorithm to find where it would break down. The shortcut assumed that a leap year occurs every four years; which is not always the case or there would not be a need for these macros in the first place. I should have mentioned that in the article.
I thought of updating the macro to account for this extra day; but that could make the macro uglier and less efficient. As you said, good thing this does not occur for a while. I would be very surprised and proud if this code runs in a computer that still operates in the year 6888.
Thanks for the fine analysis. It demonstrates the usefulness of a peer-review web site like CodeProject.
Sincerely,
Ted N.
|
|
|
|
|
Thanks for going to the trouble and effort of writing down those four algorithms. Crisp, clear logic that is universally applicable across languages and applications but wasn't at hand when I needed it. Thanks for saving me time and improving the efficiency of my code.
|
|
|
|
|
Hold on...
This article (and the code) was written to provide a "fast" way to compute dates and leap year? I mean, I DIDN'T KNOW there was any other REASONABLE ways. Now that someone tells me that some algorithm use LOOPS to implement that, and not only in one place but in several algorithms found on the net, that is telling me that there are heaps of f****** idiots coders on this planet. No wonder why most software seems bloated and slow as of today...
Apart from the macro (which can yield to totaly wrong results as mentionned in above thread, and that has nothing to do with semantics), it is indeed a "fast" way to compute dates and leap years. However, the very slight overhead of using functions, class, whatever, over macros (which are fast but wwong) is very VERY small. On a modern computer, this will add an overhaad of perhaps 1 microsecond, on a piece of code that did take 1 microsecond to compute. That's simply an order of magnitude, not a real-life empirical value. Therefore, you will be able to compute 500 000 dates per second instead of 1 million. So unless you have to compute 1 millions dates every seconds, that won't make much difference
Nevertheless, that is good work for anybody who is not very mathematicaly inclined and just want to compute dates!
Manu
|
|
|
|
|
Thanks for reading the article and taking time to comment on it. Did I mention that the project involved a browser on an embedded processor? The browser ran on a digital cable box that had a 175MHz RISC CPU and a dedicated MPEG-2 decoder. In addition to handling the broadcast stream, the processor also has to display a fully functional web browser. After the docsis stack, the TCP stack, and the overlay graphics, the browser had about 10-15% of CPU load to parse a page and display its content.
What challenge is there to write slow, bloated code for a "modern" computer? I find it more interesting to squeeze every bit of performance out of very limited processors. The difference in performance was not a matter of computing 1 million dates or 500,000 dates per second. The problem was being able to validate dozens (or hundreds) of cookies and still leave enough CPU cycles for other browser parsing tasks. The goal was to deliver a smooth UI experience on a platform with limited resources.
If you had worked on an embedded project, you would appreciate the difference between something that takes 99 cycles instead of 100 cycles. Your comment reminds me of the "Columbus Egg" story (http://www.lasco.com.au/egg/egg.htm). Here is an excerpt from that page: "The Columbus Egg is a story that is used to represent how a difficult problem can be solved with an extremely simple solution - hard to find, but once it is known, looks obvious."
As I mentioned at the beginning of the article, other people may have used similar algorithms. I did not find any when I searched for it. I thought I would share what I have developed to spare other developers the time and trouble of searching or developing something similar.
Ted N.
|
|
|
|
|
I may not be an experienced coder on embedded systems, but I did have to code very fast routines in the past, and I ended up coding them in ASM, and tuning them to squeeze every CPU cycle out of it, even using tools such as VTune a few years ago. So I have to admit that with limited resources, fast and "hardcoded-style" code is a must!
|
|
|
|
|
and thanks for sharing it. Macros are certainly frowned upon now a days for implementing code, as other alternatives are available such as a inline functions. But when kept simple, such as yours, they are a benefit that should not be cast away just cause they are macros.
Chris Meech
I am Canadian. [heard in a local bar]
I think people should be required to have an operator's permit to use the internet. John Simmons
|
|
|
|
|
a) as corollary for the previous comment:
There is no need for macros here, you can achieve all you want with inline functions (yes, this includes constant value evaluation).
b) While the subtracting algorithm is a little bit on the stupid side, one must ask: how many cycles are really spent?
The counter runs for less than 90 years, and consider that a division takes (at least on older processors) many more cycles than a subtraction.
Your algorithms are likely faster, esp. on a modern platform, but the performance gains is notable only if you need that calculation in a tight loop (which is rare)
we are here to help each other get through this thing, whatever it is Vonnegut jr.
sighist || Agile Programming | doxygen
|
|
|
|
|
They may work, and they may even perform a good deed, but generally, macros are NOT to be regarded as legitimate substitute for a language.
I would prefer anyday, to debug a program written in a legitimate language, than try and decipher (not to mention debug) the inner workings of macro statements.
My personal feeling is, if you want to get creative, get creative with the language, NOT in the way you use macros. If by way of the language, someone is not getting the best result, then seek a better way by improving the way the person is using the language, NOT by setting the language aside and then turn to macros for the solution.
Why is it that all the masters of C++ advise against the use of macros (all of them, Stroustrup, Meyers, Sutter, Lippman, Koenig, Dewhurst, [etc.], ... all of them)? They explicitly state that macros should NOT be treated as extensions of the language.
If the idea of turning to macros for solution start becoming a viable alternative, sooner or later you're going to find that it's especially no fun debugging (and maintaining) programs that relies on them for solutions. All of a sudden, you'll start becoming very defensive when your boss starts asking about that project you've been working on for the past two weeks that should have taken two days to complete.
William
Fortes in fide et opere!
|
|
|
|
|
So why not using macros ? And what about delegation, namespaces and so ? Just a leap year algorithm with some divide and modulo ?
You have trouble debuging macros ? Me too ! But don't try to convert complex algorithms into a macro... Macro are unrolled during compilation into full code. Not optimal in code size, but surely into speed (no sub function branch)... That's what Ted Nguyen was looking for !
From time to time, I like your enlighted comment, dear WREY, but sometimes, you miss the point. Ted don't wanted to be ultra-creative by using macro, and generaly, using macro is not to be creative, just to solve a problem. The purpose met the solution !
And why prevent the use of a language possibility (macro), because "the masters of C++ advise against the use of macros" ? Nishant S asked me why I'm fond of pointers here : http://www.codeproject.com/string/CPathSplit.asp?df=100&forumid=16567&exp=0&app=50&select=588025#xx588025xx ! But why should it be a problem, is it forbidden to use pointers ? Matter of taste...
Kochise
In Code we trust !
|
|
|
|
|
Some C++ books suggest to avoid the usage of the "C" macro; inline haves more or less the same performance.
in the sample:
#define IS_LEAP_YEAR(Y) ( ((Y)>0) && !((Y)%4) && ( ((Y)%100) || !((Y)%400) ) )
if you code:
int y=1996;
BOOL bLeap = IS_LEAP_YEAR(y++);
you will be full of unexpected behaviors. That’s why.
int y=1996;
BOOL bLeap = ( ((y++)>0) && !((y++)%4) && ( ((y++)%100) || !((y++)%400) ) );
Better to write:
bool IsLeapYear(int Y) { return (((y)>0) && !((y)%4) && ( ((y)%100) || !((y)%400) ) ) }
So the small sample above will work as we will hope.
Anyway the author was classifying his article as "C" (not C++) for embedded systems, and honestly I find his job a great one
I don't find pure "C" so antique... Programming Language diffusion[^]
|
|
|
|
|
Hello William,
Thank you for reading the article. The focus of the article is about developing a set of formulas for dealing with leap years. I present these formulas in the simplest form possible. A macro is the closest representation of a formula. A novice reader would not have to read through a function header to understand the inner-working of these formulas.
These macros are arithmetic expressions. By putting them all in one line as a macro, I let the compiler choose the best optimization possible. If I broke up a formula into multiple expressions that on multiple lines, it would certainly make it easier to debug. A less robust compiler would not be able to optimize it as well.
Once you understand how these formulas work, you are welcome to implement them in any language and any style that you want. You can write inline functions, template functions, or even a class hierarchy to handle leap year conversions. Going too much into language semantics in this article would distract the reader from the real discussion.
Again, thank you for your feedback.
Ted N.
|
|
|
|
|
Right on. In this day and age it seems that if there are people that haven't figured out a macro is a basic text substitution and that there are appropriate and inappropriate uses (as with *any* tool), they aren't going to be programming in C in the first place. Let them rewrite it into whatever scripting language they want (if they can figure out all the big complicated operation symbols), and maybe they'll come to understand just that little bit more than they did before.
-caedisius
|
|
|
|
|
Ted Nguyen wrote:
Once you understand how these formulas work, you are welcome to implement them in any language and any style that you want. You can write inline functions, template functions, or even a class hierarchy to handle leap year conversions. Going too much into language semantics in this article would distract the reader from the real discussion.
I for one don't program in C++. I've wasted many hours scouring the internet for some good date functions, and these are the best I have come across. I'm happy to report I needed minimal clipping to adapt them to another language, because, macros ARE very close to algorithmic notation, and its pretty obvious how to implement them in another language.
These functions are fantastic, I wrote a (very very very slow) failsafe control function to compare results against (like difference in days). No errors for dates before about 7000 (yes I read about it breaking down at 6888 or something).
I've managed to make a function also which adds ro subtracts a number of days to a date which is pretty nippy. It uses 3 of the macros.
|
|
|
|
|