Days between dates challenge for 11c and 34c



#34

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!


#35

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.


#36

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


#37

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


#38

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. :)

#39

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.


#40

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


#41

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


#42

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.


#43

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


#44

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)


#45

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

#46

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?

:-)


#47

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
#48

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.


#49

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


#50

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!


#51

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.


#52

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!

#53

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


#54

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


#55

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.

#56

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

#57

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!


#58

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.


#59

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

0

STO 0

vs.

CLR REG


#60

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?


#61

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

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

#62

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)


#63

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


#64

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.


#65

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


#66

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


Possibly Related Threads...
Thread Author Replies Views Last Post
  HP50G early days vs Prime early days? Mike Powell 7 981 10-09-2013, 11:17 AM
Last Post: Eric Rechlin
  HP-34C Draining battery quickly Bill Crowell 2 626 09-08-2013, 08:30 AM
Last Post: aj04062
  HP-34C Curiosity Matt Agajanian 7 1,126 08-23-2013, 06:02 PM
Last Post: Stephan Matthys
  hp 17bii+ dates calculation... JoePaul 6 1,059 07-14-2013, 11:32 AM
Last Post: Katie Wasserman
  Casio fx-CP400 emulator (90 days trial) Mic 2 889 05-16-2013, 01:07 PM
Last Post: critor
  HP-34C Emulator BShoring 8 1,204 03-30-2013, 05:04 PM
Last Post: BShoring
  Looking for PRNG for HP-34C Dave Boyd 3 659 09-22-2012, 07:10 PM
Last Post: Mike T.
  Introduction and discontinuation dates for HP Calculators Harald 9 1,145 07-30-2012, 04:43 PM
Last Post: Jake Schwartz
  HHC 2012 dates Palmer O. Hanson, Jr. 2 480 06-19-2012, 12:03 PM
Last Post: Namir
  A longstanding HP-34C mystery Matt Agajanian 11 1,473 05-03-2012, 02:29 AM
Last Post: Alexander Oestert

Forum Jump: