▼
Posts: 1,392
Threads: 142
Joined: Jun 2007
Katie Wasserman and I have been extolling the virtues of the HP11c via emails recently, and we decided to implement the days between dates algorithm found in the "Formulas Used" Appendix of the HP12c manual. Each of us developed an RPN program on the 11c 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 HP11c or HP34c 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:
 One point for each line of code.
 Seven points for each register used (not including the stack and lastx).
 Two points for each label used.
You must implement the deltaDYS (actual day basis) algorithm in the Formulas Used Appendix of the HP12c 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 12c 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!
▼
Posts: 1,477
Threads: 71
Joined: Jan 2005
FYI, here's the formula that's to be implemented, taken from the 12C appendix:
Actual Day Basis
deltadays = 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.
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
▼
Posts: 1,392
Threads: 142
Joined: Jun 2007
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. :)
Posts: 1,392
Threads: 142
Joined: Jun 2007
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.
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
▼
Posts: 1,392
Threads: 142
Joined: Jun 2007
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.
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
▼
Posts: 1,392
Threads: 142
Joined: Jun 2007
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)
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
Posts: 536
Threads: 56
Joined: Jul 2005
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?
:)
▼
Posts: 536
Threads: 56
Joined: Jul 2005
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
Posts: 1,477
Threads: 71
Joined: Jan 2005
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.
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
▼
Posts: 1,477
Threads: 71
Joined: Jan 2005
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!
▼
Posts: 536
Threads: 56
Joined: Jul 2005
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.
▼
Posts: 1,477
Threads: 71
Joined: Jan 2005
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!
Posts: 1,477
Threads: 71
Joined: Jan 2005
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  reuse of this label
065 RCL 0
066 RTN
▼
Posts: 283
Threads: 33
Joined: Jul 2008
Can we keep this open a little longer please? I have a problem with my code  when you steprun it or do it manually, it appears to work OK but when you run it properly, it fails. There is a stacklift 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
▼
Posts: 1,477
Threads: 71
Joined: Jan 2005
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 rolldown 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 4level 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.
Posts: 104
Threads: 0
Joined: Dec 2007
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  reuse of this label
062 RCL 0
063 RTN
▼
Posts: 1,392
Threads: 142
Joined: Jun 2007
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!
▼
Posts: 104
Threads: 0
Joined: Dec 2007
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.
▼
Posts: 1,392
Threads: 142
Joined: Jun 2007
Quote: It saves two lines
Actually, one, right?
0
STO 0
vs.
CLR REG
▼
Posts: 104
Threads: 0
Joined: Dec 2007
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?
▼
Posts: 1,392
Threads: 142
Joined: Jun 2007
Oh, I see what you are saying now, Steve. You're right.
Re Katie, I agree. I'm not even in the same league!
Posts: 104
Threads: 0
Joined: Dec 2007
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)
▼
Posts: 1,477
Threads: 71
Joined: Jan 2005
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
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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 stacklift 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 repointing 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.
▼
Posts: 1,477
Threads: 71
Joined: Jan 2005
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
▼
Posts: 283
Threads: 33
Joined: Jul 2008
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
