The Museum of HP Calculators

HP Forum Archive 19

[ Return to Index | Top of Index ]

Days between dates challenge for 11c and 34c
Message #1 Posted by Don Shepherd on 9 Aug 2009, 9:56 a.m.

Katie Wasserman and I have been extolling the virtues of the HP-11c via emails recently, and we decided to implement the days between dates algorithm found in the "Formulas Used" Appendix of the HP-12c manual. Each of us developed an RPN program on the 11-c for this algorithm, and then we shared them so we could benefit from the other's ideas. Katie thought this would be a good challenge for this community, and I agree. So here are the rules.

The goal is to develop an RPN program on either the HP-11c or HP-34c that conserves the scarce resources on these calculators as much as possible. To this end, these are the evaluation criteria to determine the "best" program. Like golf, the lowest score wins.

Evaluation criteria:

  1. One point for each line of code.
  2. Seven points for each register used (not including the stack and lastx).
  3. Two points for each label used.

You must implement the delta-DYS (actual day basis) algorithm in the Formulas Used Appendix of the HP-12c manual. Katie and I discovered that this algorithm, as listed, does not work correctly if the date range includes century years that are not divisible by 400, such as 1800, 1900, 2100, etc. (although the 12-c does work correctly for these years, so the actual implemented algorithm is different than the printed algorithm). Nevertheless, implement the algorithm as printed in the manual.

Let's see who comes up with the lowest (best) score. I have to admit, Katie is a master at this and I will be surprized if anyone can top her effort. To the winner goes the honor of being identified as the winner in this thread!

      
Re: Days between dates challenge for 11c and 34c
Message #2 Posted by Katie Wasserman on 9 Aug 2009, 11:50 a.m.,
in response to message #1 by Don Shepherd

FYI, here's the formula that's to be implemented, taken from the 12C appendix:

Actual Day Basis
delta-days = f(DT2) – f(DT1)

where: f(DT) = 365 (yyyy) + 31 (mm – 1) + dd + INTG (z/4) – x

and for mm <= 2 x = 0 z = (yyyy) – 1

for mm > 2 x = INTG (0.4mm + 2.3) z = (yyyy)

INTG = Integer portion.

Edited: 9 Aug 2009, 11:53 a.m.

            
Re: Days between dates challenge for 11c and 34c
Message #3 Posted by Mark Edmonds on 9 Aug 2009, 1:46 p.m.,
in response to message #2 by Katie Wasserman

Just one question on the scoring - with these calcs, is one line of code always the same size irrespective of what that line of code is? Although I am a big fan of the 11C, I don't program it much if at all and coming from a UserRPL perspective, I am used to variable command sizes, often with surprising results.

Mark

                  
Re: Days between dates challenge for 11c and 34c
Message #4 Posted by Mark Edmonds on 9 Aug 2009, 1:51 p.m.,
in response to message #3 by Mark Edmonds

And another point just thinking this through - us Europeans are going to produce a different program I suspect to those Stateside due to the different date formats.

You'll need to define the date format before people start coding on DD.MMYYYY.

Mark

                        
Re: Days between dates challenge for 11c and 34c
Message #5 Posted by Don Shepherd on 9 Aug 2009, 1:56 p.m.,
in response to message #4 by Mark Edmonds

You're right. Let's use the US standard, mm.ddyyyy. It would be interesting, however, if dd.mmyyyy might result in more efficient code. :)

                  
Re: Days between dates challenge for 11c and 34c
Message #6 Posted by Don Shepherd on 9 Aug 2009, 1:53 p.m.,
in response to message #3 by Mark Edmonds

Mark, I'm pretty sure the answer is "yes." A line of code might be "4", or it might be ".", or it might be "x>y". I think they are all one byte long.

                        
Re: Days between dates challenge for 11c and 34c
Message #7 Posted by Mark Edmonds on 9 Aug 2009, 2:05 p.m.,
in response to message #6 by Don Shepherd

Thanks Don. I'm pretty certain it is 1:1 now myself having just reacquainted myself with the 11C program model. In fact, as soon as I did this, I realised what a daft question it was!!

Will use US date format.... but as you say, doing it the European way would be interesting for comparison.

Mark

                              
Re: Days between dates challenge for 11c and 34c
Message #8 Posted by Mark Edmonds on 9 Aug 2009, 2:12 p.m.,
in response to message #7 by Mark Edmonds

And another question as this might make a difference. What is the stack order, DT1 in y, DT2 in x or the other way round?

Also, are we assuming the program pointer is at 000 for running the program or do we need to define a starting label?

Mark

                                    
Re: Days between dates challenge for 11c and 34c
Message #9 Posted by Don Shepherd on 9 Aug 2009, 2:55 p.m.,
in response to message #8 by Mark Edmonds

DT1 and DT2 order in the stack, your choice, although Katie and I assumed that you would enter DT1 first, so it would be in Y. We also had LBL A as the first instruction, although you could omit that and assume you are at 00 when you R/S, I suppose, to gain 2 points on one fewer label.

                                          
Re: Days between dates challenge for 11c and 34c
Message #10 Posted by Mark Edmonds on 9 Aug 2009, 4:00 p.m.,
in response to message #9 by Don Shepherd

Me again!

Please can you post some official results so we can check our programs against them - ideally, these results should include an example where the algorithm fails as detailed above.

Thanks :)

Mark

                                                
Re: Days between dates challenge for 11c and 34c
Message #11 Posted by Don Shepherd on 9 Aug 2009, 5:03 p.m.,
in response to message #10 by Mark Edmonds

Sure, Mark, here are a couple:

8.141950
8.092009
--> 21545 (my age in days)

7.121960 12.042008 --> 17677

2.281900 3.011900 --> 2 using this algorithm (incorrect) --> 1 on a real 12c (correct, because 1900 is not a leap year)

                                                      
Re: Days between dates challenge for 11c and 34c
Message #12 Posted by Mark Edmonds on 9 Aug 2009, 5:20 p.m.,
in response to message #11 by Don Shepherd

Thanks Don :)

My first draft has weighed in with a hefty score of 103 (written on an 11C). Not sure I can reduce that by much unless I change the main algorithm.

Mark

      
Re: Days between dates challenge for 11c and 34c
Message #13 Posted by hugh steers on 9 Aug 2009, 6:06 p.m.,
in response to message #1 by Don Shepherd

01 LBL A
02 GSB 02
03 X<>Y
04 GSB 02
05 -
06 RTN
07>LBL 02
08 1
09 +
10 STO 00
11 IP
12 STO 01
13 STO- 00
14 100
15 STO× 00
16 RCL 00
17 IP
18 STO 02
19 STO- 00
20 R^
21 1E4
22 STO× 00
23 RCL 01
24 4
25 X<=Y?
26 GTO 01
27 R^
28 12
29 STO+ 01
30 1
31 STO- 00
32 ENTER
33>LBL 01
34 R^
35 RCL 01
36 30.6
37 ×
38 IP
39 STO+ 02
40 Rv
41 RCL 00
42 365
43 ×
44 RCL 00
45 4
46 ÷
47 IP
48 +
49 RCL+ 02
50 RTN

notes:

numbers wont be single lines as shown. Rv = roll down, R^ = roll up. havent tested on a real 11c. this was a free42 program. i just changed LBL A and GSB for the 11c. I cant remember whether the 11c has functions im using missing?

:-)

            
Re: Days between dates challenge for 11c and 34c
Message #14 Posted by hugh steers on 9 Aug 2009, 6:19 p.m.,
in response to message #13 by hugh steers

ok, i tried it on my 15c.

lines = 60 regs = 3 labels = 3 (including main one)

= 60 + 21 + 6 87

also, tidied, register and label names to be more 11c ish.

01 LBL A
02 GSB 2
03 X<>Y
04 GSB 2
05 -
06 RTN
07>LBL 2
08 1
09 +
10 STO 0
11 INT
12 STO 1
13 STO- 0
14 100
15 STO× 0
16 RCL 0
17 INT
18 STO 2
19 STO- 0
20 R^
21 1E4
22 STO× 0
23 RCL 1
24 4
25 X<=Y?
26 GTO 1
27 R^
28 12
29 STO+ 1
30 1
31 STO- 0
32 ENTER
33>LBL 1
34 R^
35 RCL 1
36 30.6
37 ×
38 INT
39 STO+ 2
40 Rv  -- roll down
41 RCL 0
42 365
43 ×
44 RCL 0
45 4
46 ÷
47 INT
48 +
49 RCL+ 2
50 RTN
            
Re: Days between dates challenge for 11c and 34c
Message #15 Posted by Katie Wasserman on 9 Aug 2009, 6:30 p.m.,
in response to message #13 by hugh steers

I haven't test it either, on an 11c the score would be: 58 lines (expanding numbers as needed) + 3 x 2 points/label + 3 x 7 points/register = 85. This would be a good score, but it doens't implement the formula as presented. My best score so far is a bit less than this: 66 lines + 1 label (it's reused) + 2 registers = 82. You could save 4 points by label reuse too since all your branches are forward.

Edited: 9 Aug 2009, 6:32 p.m.

                  
Re: Days between dates challenge for 11c and 34c
Message #16 Posted by Mark Edmonds on 9 Aug 2009, 7:08 p.m.,
in response to message #15 by Katie Wasserman

Also, it uses recall arithmetic which the 11C doesn't have unfortunately.

I think I can see a way of reducing mine a bit which might enable me to remove a register and save a few lines. Also, if I implement Katie's label trick, I can save one label - but I am not going to do that as I didn't know that trick existed so would be cheating!

Mark

                        
Re: Days between dates challenge for 11c and 34c
Message #17 Posted by Katie Wasserman on 9 Aug 2009, 7:20 p.m.,
in response to message #16 by Mark Edmonds

Right, the 11C and the 34c don't have RCL arithmetic.

Aside form the integrate and solve functions I think that the 11c and 34c are 100% program code compatible and have the same memory size.

Label reuse isn't a trick, it's suggested in the 11C manual!

                              
Re: Days between dates challenge for 11c and 34c
Message #18 Posted by hugh steers on 9 Aug 2009, 7:41 p.m.,
in response to message #17 by Katie Wasserman

Sure it implements the formula presented :-) i just rearranged some of the calculation to be an equivalent form. it should get the exact same answers.

i didn't know about the rcl arithmetic. strange that's missing on the 11c really, when it's there on the 15.

                                    
Re: Days between dates challenge for 11c and 34c
Message #19 Posted by Katie Wasserman on 9 Aug 2009, 8:45 p.m.,
in response to message #18 by hugh steers

Quote:
Sure it implements the formula presented :-) i just rearranged some of the calculation to be an equivalent form. it should get the exact same answers.

You sure confused me on this. Some program commentary might help convince me that these are the same algorithms. Anyway, the final RCL+2 is easily adjusted for the 11C and I end up 59 lines (I change 100 --> EEX 2 and 1EEX4 --> EEX 4), 3 registers and you can get away with 1 label I think (even though you used 3). So your score is potentially 81, wow!

      
Re: Days between dates challenge for 11c and 34c
Message #20 Posted by Katie Wasserman on 9 Aug 2009, 8:48 p.m.,
in response to message #1 by Don Shepherd

Here's my entry.

Assumes dates are in the format mm.ddyyyy with starting date in Y and ending date in X. GSB A will return the days between them per the 12c manual appendix function description.

LBL A is used 3 times, this is fine as long as the program is not starting in the middle (like with a GTO .005) followed by a GSB A.

Registers I and 0 are used and will and not be restored, no other register is touched.

No flags are used and any output format is ok.

score= 82 (66 lines, 2 registers, 1 label)

001 LBL A -- expects Y=starting date (mm.ddyyyy), X=ending date (mm.ddyyyy) 002 0 003 STO 0 -- zero the days accumulator 004 Rv 005 GSB A -- get the negative number of days for the ending date in register 0 006 CHS -- flip the sign of register 0 007 STO 0 008 R^ -- get the starting date -- and process the same way -- the final RTN will end the program 009 LBL A -- reuse of 'A' expects X=mm.ddyyyy and subtracts the day count from register 0 (it also preserves Y in T) 010 STO I 011 INT 012 X<>I -- I now contains 'mm' 013 FRAC 014 EEX 015 2 016 x 017 INT 018 STO - 0 -- subtract 'dd' 019 Rv -- needed just to preserve the starting date 020 3 021 6 022 5 023 LASTx 024 FRAC 025 EEX 026 4 027 x 028 x 029 STO - 0 -- subtract 365 x 'yyyy' 030 Rv -- needed just to preserve the starting date 031 LASTx -- get back 'yyyy' 032 X<>I -- swap places with 'mm' 033 3 034 X > Y -- if 'mm'<=2 then 035 DSE -- 'yyyy' - 1 036 Rv -- get 'mm' back into I 037 X<>I get 'z' into X 038 4 039 / 040 INT 041 STO - 0 -- subtract INT(z/4) 042 Rv -- needed just to preserve the starting date 043 RCL I -- get 'mm' 044 1 045 - 046 3 047 1 048 x 049 STO - 0 subtract ('mm' - 1) * 31 050 Rv -- needed just to preserve the starting date 051 2 052 RCL I 053 X<=Y -- if 'mm'<=2 no need to add anything 054 GTO A -- this is a forward branch to the next 'LBL A' 055 . 056 4 057 x 058 2 059 . 060 3 061 + 062 INT 063 STO + 0 -- add INT('mm' x .4 + 2.3) 064 LBL A -- re-use of this label 065 RCL 0 066 RTN

            
Re: Days between dates challenge for 11c and 34c
Message #21 Posted by Mark Edmonds on 11 Aug 2009, 9:20 a.m.,
in response to message #20 by Katie Wasserman

Can we keep this open a little longer please? I have a problem with my code - when you step-run it or do it manually, it appears to work OK but when you run it properly, it fails. There is a stack-lift problem in it somewhere which is proving to be a real bloody nuisance to track down. I remember getting caught like this with an HP32S program but I wasn't using all 4 stack levels in that one so an extra enter didn't cause a problem.

I can't remember the exact code size because it is riddled with R/S commands at the moment but I think it was 66 or 67 with 1 label and 2 registers. I really want to get this fixed before we start discussing our solutions.

Thanks,

Mark

                  
Re: Days between dates challenge for 11c and 34c
Message #22 Posted by Katie Wasserman on 11 Aug 2009, 9:44 a.m.,
in response to message #21 by Mark Edmonds

Stack problems are the worst, especially since there's variation among HP calculations models in the way they handle stack lift. A good rule of thumb to help avoid bumping stuff you need off the top of the stack is to use a roll-down before after storing a number before you start a new calculation that doens't immediately need the stored result. It's amazing what you can do with a 4-level stack with careful planning, but it's often a challenge to figure it out a a basic RPN machine -- the 41C and 42S make stack manipulation far too easy.

            
Re: Days between dates challenge for 11c and 34c
Message #23 Posted by Steve Perkins on 11 Aug 2009, 1:20 p.m.,
in response to message #20 by Katie Wasserman

I guess I do better at improving others marvelous efforts. I'm not so good at programming from scratch.

I improved Katie's efforts just a little. The first trick was to just clear the registers instead of storing 0 to reg 0. Not what one usually does in a program since it destroys what you might really want saved, but it is two instructions shorter.

Then I used division by 2.5 instead of multiplication by .4 so I could just test with 2.5 instead of 2. That saved just one step.

Here's my small improvement. It wouldn't exist without Katie, so she gets the credit:

001 LBL A --  expects Y=starting date (mm.ddyyyy), X=ending date (mm.ddyyyy)
002 CLEAR REG
003 GSB A --  get the negative number of days for the ending date in register 0
004 CHS  --  flip the sign of register 0
005 STO 0
006 R^ --  get the starting date -- and process the same way -- the final RTN will end the program
007 LBL A -- reuse of 'A' expects X=mm.ddyyyy and subtracts the day count from register 0 (it also preserves Y in T)
008 STO I
009 INT
010 X<>I --  I now contains 'mm'
011 FRAC
012 EEX
013 2
014 x
015 INT
016 STO - 0 --  subtract 'dd'
017 Rv --  needed just to preserve the starting date
018 3
019 6
020 5
021 LASTx
022 FRAC
023 EEX
024 4
025 x
026 x
027 STO - 0 --  subtract 365 x 'yyyy'
028 Rv --  needed just to preserve the starting date
029 LASTx --  get back 'yyyy'
030 X<>I --  swap places with 'mm'
031 3
032 X > Y --  if 'mm'<=2 then
033 DSE --  'yyyy' - 1
034 Rv --  get 'mm' back into I
035 X<>I get 'z' into X
036 4
037 /
038 INT
039 STO - 0 --  subtract INT(z/4)
040 Rv --  needed just to preserve the starting date
041 RCL I --  get 'mm'
042 1
043 -
044 3
045 1
046 x
047 STO - 0 subtract ('mm' - 1) * 31
048 X<>I -- get 'mm' while preserving starting date
049 2 -- constant for test, and also possible division later
050 .
051 5
052 X > Y -- if 'mm'<=2 don't need adjustment
053 GTO A -- this is a forward branch to the next 'LBL A'
054 / -- dividing by 2.5 is the same as multiplying by 0.4
055 2
056 .
057 3
058 +
059 INT
060 STO + 0 --  add  INT('mm' x .4 + 2.3)
061 LBL A -- re-use of this label
062 RCL 0
063 RTN
                  
Re: Days between dates challenge for 11c and 34c
Message #24 Posted by Don Shepherd on 11 Aug 2009, 2:05 p.m.,
in response to message #23 by Steve Perkins

Hey Steve, I'll let Katie speak for herself, but I too thought of CLR REG to save one instruction, but I'm sure Katie's point is to not alter any registers other than the two she is using, and CLR REG certainly does that!

                        
Re: Days between dates challenge for 11c and 34c
Message #25 Posted by Steve Perkins on 11 Aug 2009, 2:58 p.m.,
in response to message #24 by Don Shepherd

I agree. It's not the prefered method at all for a real routine. One that might be used in other contexts and with a surrounding application.

It saves two lines, but it could be argued that it "uses" all the registers and thus the point penalty is extreme.

                              
Re: Days between dates challenge for 11c and 34c
Message #26 Posted by Don Shepherd on 11 Aug 2009, 3:14 p.m.,
in response to message #25 by Steve Perkins

Quote:
It saves two lines
Actually, one, right?

0

STO 0

vs.

CLR REG

                                    
Re: Days between dates challenge for 11c and 34c
Message #27 Posted by Steve Perkins on 11 Aug 2009, 5:58 p.m.,
in response to message #26 by Don Shepherd

That one line replaces

002 0
003 STO 0 --  zero the days accumulator
004 Rv

But Katie interprets it as "using" 19 additional registers, so I withdraw it.

My tricks now only save two lines in her wonderful code. It's sure great to have nice code to start with, right?

                                          
Re: Days between dates challenge for 11c and 34c
Message #28 Posted by Don Shepherd on 11 Aug 2009, 6:12 p.m.,
in response to message #27 by Steve Perkins

Oh, I see what you are saying now, Steve. You're right.

Re Katie, I agree. I'm not even in the same league!

                  
Re: Days between dates challenge for 11c and 34c
Message #29 Posted by Steve Perkins on 11 Aug 2009, 3:10 p.m.,
in response to message #23 by Steve Perkins

Actually, it seems that my line 40 can be deleted too. The starting date is still preserved in the top stack register where it's expected after the first call to the date numbering subroutine. With that refinement we have:

score= 78 (62 lines, 2 registers, 1 label)

                        
Re: Days between dates challenge for 11c and 34c
Message #30 Posted by Katie Wasserman on 11 Aug 2009, 5:18 p.m.,
in response to message #29 by Steve Perkins

Steve,

Refinements of my code are most welcome and appreciated. Combining clever ideas of many of the people here can result in some amazing code.

Yes, I avoided Clear REG for the obvious reason that would count as using another 19 registers :(

Your use of 2.5 / instead of .4 * is brilliant!

I had concluded that I needed the Rv at line 40, but that may have been in a earlier version of my code and I left it in place unnecessarily.

Thanks for the improvements!

-Katie

                              
Re: Days between dates challenge for 11c and 34c
Message #31 Posted by Mark Edmonds on 12 Aug 2009, 6:57 a.m.,
in response to message #30 by Katie Wasserman

Here is my version. I haven't looked at anyone elses' code so I don't know how it compares. This was a useful exercise for me and a lot of fun as I don't normally do any programming outside RPL. The 4 line stack and stack-lift problems caught me out a couple of times but here is the result:

64 lines, 1 label, 2 registers.

x SWAP I
Rdown
GSB A
x SWAP I
GSB A
RCL I
-
RTN

LBL A INT LASTx FRAC EEX 2 * INT STO 0 LASTx FRAC EEX 4 * 3 6 5 x SWAP y * STO+ 0 LASTx Rup ENTER SF 0 1 - 3 1 * STO+ 0 x SWAP y 3 X>Y GTO A Rdown CF 0 . 4 * 2 . 3 + INT STO- 0 LBL A Rup F? 0 1 F? 0 - 4 / INT RCL 0 +

You will notice that I didn't include an opening label and I took advantage of the implied RTN at the last step. I consider both these omissions legit. It was agreed at the start that an opening label wasn't necessary and my program returns to 000 after each run so no manual re-pointing is necessary. Concerning the implied RTN, HP document this in the manuals so quite happy to use it!

However, this might give me a 2 line advantage so I'll let the adjudicators decide on that one :)

Written on 11C and thanks for the fun challenge!

Mark

PS: Living in a dd.mm.yyyy part of the world, working with mm.dd.yyyy is unbelievably confusing! It's like have to learn left is right!!

Edited: 12 Aug 2009, 7:01 a.m.

                                    
Re: Days between dates challenge for 11c and 34c
Message #32 Posted by Katie Wasserman on 12 Aug 2009, 11:18 a.m.,
in response to message #31 by Mark Edmonds

Mark,

Very nice code!

The way you use I register and the 0 flag is a great idea, much more obvious than my convoluted program.

Dropping the fist LBL and last RTN, well it's ok if nothing else is in memory, not so good if there's other code in there but Don's the contest judge....

-Katie

                                          
Re: Days between dates challenge for 11c and 34c
Message #33 Posted by Mark Edmonds on 12 Aug 2009, 3:46 p.m.,
in response to message #32 by Katie Wasserman

Thanks for the feedback Katie :) To be perfectly honest, I don't think my code is especially elegant and would be a pain to maintain if a functional change is needed.

In comparison, I thought your code was much easier to understand and works using the same resources, even less actually and as such, I consider it to be a neater solution.

I liked the clever use of DSE and the way you run into the sub on the second pass so the sub's RTN acts as the end. I thought of doing that myself but it wasn't possible the way I set things up.

Looking at your code made me realise another method of calculating the date difference by negating the actual DT1 value before passing to the sub. You wouldn't need to negate the return value and everything would be simple addition (but the month test would be more difficult).

Mark


[ Return to Index | Top of Index ]

Go back to the main exhibit hall