HHC 2018 Programming Contests
10-03-2018, 03:46 PM
Post: #61
 Didier Lachieze Senior Member Posts: 1,524 Joined: Dec 2013
RE: HHC 2018 Programming Contests
Nice way of rounding the result. You can also save a few steps with:
Code:
▸LBL 14  MOD  LASTx  /  0  ACOS  ×  4  ×  SIN  200  ×  ENTER  SIGN  +  2  ÷  IP  RTN
10-04-2018, 05:55 AM
Post: #62
 Werner Senior Member Posts: 737 Joined: Dec 2013
RE: HHC 2018 Programming Contests
And I was so proud of my 3.6 \->HR find!
But this is of course a lot better, thanks Didier!

Werner
10-04-2018, 02:48 PM (This post was last modified: 10-04-2018 05:14 PM by 3298.)
Post: #63
 3298 Member Posts: 182 Joined: Oct 2014
RE: HHC 2018 Programming Contests
Some optimization applied to my previous solution:
- Instead of this 1. \<< MIN \>> DOLIST trick to get the lowest member of the list (which also needed a big enough initial number on the stack above the list), SORT HEAD does the same slightly more elegantly (and without needing the big number). As a performance-oriented SysRPL coder SORT was simply not on my radar (all that sorting of elements that get dropped by HEAD anyway, what a waste of CPU cycles!), so thanks to Gerson W. Barbosa for bringing it to my attention via his program.
- I did use automatic list-based parallel processing already, but there was another DOLIST I could drop by resorting to simple parallel processing: the one calculating and tagging the function values at the end.
- The even distribution of E's extrema allowed for further optimization by halving the modulo of each function pair involving E (i.e. P+E and E+I) and dropping two of the four extrema out of their corresponding lists. The remaining function pair had no potential for such an optimization though. Thanks to Werner for pointing that out; the even distribution was obvious, but I failed to realize how I could use it for the program until I read his comment.
- The smallest number out of the smallest numbers of three lists is simply the smallest number of the concatenated lists, so the remaining DOLIST no longer reduces its lists to single numbers; instead these lists get flattened into one after DOLIST finishes (EVAL + +), and only then the smallest member is picked out via SORT HEAD.

The only remaining DOLIST could unfortunately not be optimized away, because UserRPL's automatic parallel processing when lists are encountered is not recursive. As you can clearly see in the code, I have a list containing three sublists where I apply certain operations to all members of the sublists - automatic parallel processing does not cut it, I have to use DOLIST for explicit parallel processing.
I did shorten the subprogram passed to DOLIST a bit though, in addition to the shortening mentioned in the "smallest number out of the smallest numbers" paragraph above - instead of passing the age in via a local variable, it's passed in via an additional list that contains three copies of it, one per run of the subprogram. That and removing the last DOLIST meant I don't need the local variable at all, so I just keep that copy needed for calculating the function values on the stack instead.

Code:
\<<   DATE DDAYS                        (convert birthdate into age in days)   1. +                              (calculate everything based on tomorrow to avoid getting today's date back)   { 322. 759. 462. }                (modulo for each function pair)   {     { 63. 259. }                    (common extrema for P+E)     { 190. 305. 454. 569. }         (common extrema for P+I)     { 91. 371. }                    (common extrema for E+I)   }   PICK3 3. NDUPN \->LIST            (create a list containing multiple copies of the age so it is available inside DOLIST)   3.                                (DOLIST gets 3 lists)   \<<     -                               (subtracting the age from the extrema tells us how far away the common extrema still are)     SWAP MOD                        (no matter how many times we passed a certain common extremum already, we want the nearest occurrence that's not in the past)   \>> DOLIST                        (perform the calculation for each of the function pairs)   EVAL + +                          (flatten the list-of-three-lists returned by DOLIST to a simple list)   SORT HEAD                         (which of the common extrema is the closest one?)   DATE OVER 1. + DATE+              (convert the days-from-tomorrow number back into an absolute date, while leaving a copy of the number there, ...)   "Next extrema date" \->TAG UNROT  (... then tag it appropriately and file it away behind age and 'distance' to the next extrema date)   +                                 (add the age and the days to the next extrema date together, both based on tomorrow)   RCLF SWAP RAD                     (save the angle mode and switch to radians)   { 23. 28. 33. }                   (for each function cycle length: ...)   / 2. \pi * * SIN 100. *           (... calculate the exact function value from age and cycle length, ...)   0. RND                            (... round it to the nearest integer, ...)   { "P" "E" "I" } \->TAG            (... and tag it with the function name)   SWAP STOF                         (finally, restore the angle mode) \>>
366.5 bytes, #7024h.
In terms of performance, this completes in a fraction of a second Edit: just barely under a second on a real 50g (I developed it on x49gp, which on this system is faster than I expected, as it achieved results in the neighborhood of 0.1 seconds, when I thought it was just a little bit faster than the real device). In fact, the only loop is the sub-program passed to DOLIST, everything else is executed once from start to finish.
If one wanted to accelerate or shrink it even further, the optimization of baking the first 1. + into the list of extrema distances from day 0 by decrementing them by one (which I mentioned in the notes for my first version already; though I forgot to mention that the other 1. + has to be moved a bit for results to stay correct) is still possible but not used in the name of readability ~= elegance. The tagging parts could be removed (making the output less pretty), and the replacement to SORT HEAD could be undone (this one is actually a tradeoff between size and speed, because SORT HEAD is shorter than what it replaced). If one doesn't care about preserving the user's angle mode, there are four more commands that could be removed by not saving and restoring it. All in all, I could get it down to 301.5 bytes without sacrificing correctness. Not sure if it's possible to get it even smaller.
10-04-2018, 03:47 PM (This post was last modified: 10-05-2018 07:20 PM by Gerson W. Barbosa.)
Post: #64
 Gerson W. Barbosa Senior Member Posts: 1,473 Joined: Dec 2013
RE: HHC 2018 Programming Contests
Code:
 %%HP: T(3)A(D)F(.); \<< RCLF RAD { 190. 305. 454. 569. 949. } { 91. 371. 553. 833. 1015. } { 63. 259. 385. 581. 707. } 5. ROLL DUP DATE DUP UNROT DDAYS 3. NDUPN \->LIST { 644. 924. 759. } MOD { } 1. 3.   FOR i SWAP DUP i GET 5. NDUPN \->LIST 6. ROLL SWAP - DUP 0. > *     WHILE DUP HEAD NOT     REPEAT TAIL     END 1. GET ROT +   NEXT SWAP DROP SORT OBJ\-> DROP DROP2 DATE+ DUP UNROT DDAYS DUP + \pi * DUPDUP \->V3 AXL { 23. 28. 33. } / SIN ROT STOF \>>
439 bytes, CK = #552Dh, 0.8 seconds. It works for all examples I've tried. Nicer output still missing :-)

(04-Oct-2018, 16:41) P.S.: The output has been improved by a little bit at the cost of a few bytes. No tagging, but the order is { P E I } :

Code:
 %%HP: T(3)A(R)F(.); \<< RCLF RAD { 190. 305. 454. 569. 949. } { 91. 371. 553. 833. 1015. } { 63. 259. 385. 581. 707. } 5. ROLL DUP DATE DUP UNROT DDAYS 3. NDUPN \->LIST { 644. 924. 759. } MOD { } 1. 3.   FOR i SWAP DUP i GET 5. NDUPN \->LIST 6. ROLL SWAP - DUP 0. > *     WHILE DUP HEAD NOT     REPEAT TAIL     END 1. GET ROT +   NEXT SWAP DROP SORT OBJ\-> DROP DROP2 DATE+ DUP UNROT DDAYS DUPDUP 3. \->LIST { .273181969877 .224399475256 .190399554763 } * SIN 100. * 0. RND ROT STOF \>>

444 bytes, CK = # 99F8h

22.021950 ->             30.012019
{-100. 100. 0.}

P.P.S.: 1 GET is less elegant than HEAD, but takes a nibble less. Also, on the HP-50g NIP is shorter than SWAP DROP:

Code:
 %%HP: T(3)A(D)F(.); \<< RCLF RAD { 190. 305. 454. 569. 949. } { 91. 371. 553. 833. 1015. } { 63. 259. 385. 581. 707. } 5. ROLL DUP DATE DUP UNROT DDAYS 3. NDUPN \->LIST { 644. 924. 759. } MOD { } 1. 3.   FOR i SWAP DUP i GET 5. NDUPN \->LIST 6. ROLL SWAP - DUP 0. > *     WHILE DUP 1. GET NOT     REPEAT TAIL     END 1. GET ROT +   NEXT NIP SORT OBJ\-> DROP DROP2 DATE+ DUP UNROT DDAYS DUPDUP 3. \->LIST { .273181969877 .224399475256 .190399554763 } * SIN 100. * 0. RND ROT STOF \>>

441 bytes, CK = # DD4Dh
10-04-2018, 06:09 PM
Post: #65
 Namir Senior Member Posts: 837 Joined: Dec 2013
RE: HHC 2018 Programming Contests
(10-02-2018 04:33 PM)Joe Horn Wrote:  Namir Shammas submitted this contest entry. Its elegance was unmatched (thankfully), and it gave me a good laugh.

The serious contest entries will be posted Real Soon Now.

Thanks Joe for posting it as you had promised me.

Namir
10-05-2018, 12:00 AM
Post: #66
 Joe Horn Senior Member Posts: 1,892 Joined: Dec 2013
RE: HHC 2018 Programming Contests

• Program name: "ELEGANT". Clever.
• Built-in instructions. Very nice!
• Uses MOD algorithm (earns two "elegance" points).
• Nicely formatted outputs.
• Unfortunately gets wrong answers. Input 8/19/1955, outputs 12/07/2018, should be 10/22/2018.

<0|ɸ|0>
-Joe-
10-05-2018, 12:11 AM
Post: #67
 Joe Horn Senior Member Posts: 1,892 Joined: Dec 2013
RE: HHC 2018 Programming Contests

• Displays some small biorhythms in scientific notation.
• Some biorhythm outputs scroll off the left end of the display.
• Ponderously slow, even though submitted on a 41CL. Some inputs take many minutes to find the next Extrema Date.
• All three above points are exemplified by an input of 1/23/1921.

<0|ɸ|0>
-Joe-
10-05-2018, 12:36 AM (This post was last modified: 10-05-2018 12:37 AM by Joe Horn.)
Post: #68
 Joe Horn Senior Member Posts: 1,892 Joined: Dec 2013
RE: HHC 2018 Programming Contests

My observations about Roger's RPN entry:
• Uses a MOD algorithm (two "elegance" points)
• Outputs Extrema Date but not the biorhythms for that date.
• Roger told me that he understood the biorhythm function to be a smooth sine curve, not a step function, so his program does not calculate the biorhythm only at 24-hour increments, but also takes parts of days into account. For example, if you were born early in a day, a 100 or -100 could occur late in another day, and so on, thereby getting different Extrema Dates than if only exact 24-hour steps are considered. Although this certainly is an "elegant" approach, and arguably better than standard biorhythm calculations, I had to disqualify it due to outputs which are "incorrect" according to "Biorhythm Theory", which only calculates by whole number of days.
Roger also submitted an RPL entry which used the same logic and got the same outputs as his RPN entry (though much faster of course). This misunderstanding was indeed unfortunate, but Roger was a good sport about it... which I think deserves at least two additional "elegance" points for Roger.

<0|ɸ|0>
-Joe-
10-05-2018, 05:07 AM (This post was last modified: 10-05-2018 05:08 AM by Didier Lachieze.)
Post: #69
 Didier Lachieze Senior Member Posts: 1,524 Joined: Dec 2013
RE: HHC 2018 Programming Contests
(10-05-2018 12:00 AM)Joe Horn Wrote:
• Unfortunately gets wrong answers. Input 8/19/1955, outputs 12/07/2018, should be 10/22/2018.

If I'm not wrong, 10/22/2018 is not an answer as the physical extrema (100) happens during 10/21/2018 (day 23074.75) and the intellectual extrema (100) during 10/22/2018 (day 23075.25), while the emotional value is at 62.

For 8/19/1955 my PPL program returns 4/12/2019 as the next extrema Date.
10-05-2018, 06:22 AM
Post: #70
 Joe Horn Senior Member Posts: 1,892 Joined: Dec 2013
RE: HHC 2018 Programming Contests
(10-05-2018 05:07 AM)Didier Lachieze Wrote:
(10-05-2018 12:00 AM)Joe Horn Wrote:
• Unfortunately gets wrong answers. Input 8/19/1955, outputs 12/07/2018, should be 10/22/2018.

If I'm not wrong, 10/22/2018 is not an answer as the physical extrema (100) happens during 10/21/2018 (day 23074.75) and the intellectual extrema (100) during 10/22/2018 (day 23075.25), while the emotional value is at 62.

For 8/19/1955 my PPL program returns 4/12/2019 as the next extrema Date.

Biorhythm values are calculated only on a whole number of days since birth (not fractions of days) and are then rounded to the nearest integer. On day 23075, both the Physical and Intellectual biorhythm is 100, so it is a Maxima Day.

<0|ɸ|0>
-Joe-
10-05-2018, 07:45 AM
Post: #71
 Didier Lachieze Senior Member Posts: 1,524 Joined: Dec 2013
RE: HHC 2018 Programming Contests
OK, so this makes my PPL program a little bit simpler:
Code:
EXPORT EXTREMA(BD) BEGIN   // Find Next Extrema date   N:=DDAYS(BD,Date);   A:=IP(2*N/23-1/2);   B:=IP(2*N/28-1/2);   C:=IP(2*N/33-1/2);   L1:=MAKELIST(ROUND(23/2*(1/2+I),0),I,A+1,A+33);   L2:=MAKELIST(28/2*(1/2+I),I,B+1,B+33);   L3:=MAKELIST(ROUND(33/2*(1/2+I),0),I,C+1,C+33);   D:=MIN(head(INTERSECT(L1,L2)),head(INTERSECT(L2,L3)),head(INTERSECT(L1,L3))​);   E:=DATEADD(BD,D);   // Display results using the Function App: first text, then a graphic view centered on the next extrema   STARTAPP("Function");   F1:='100*SIN(4*ACOS(0)*(X MOD 23)/23)';   F2:='100*SIN(4*ACOS(0)*(X MOD 28)/28)';   F3:='100*SIN(4*ACOS(0)*(X MOD 33)/33)';   Xmin:=D-40; Xmax:=D+40; Ymin:=-110; Ymax:=110;  Xtick:=5; Ytick:=10;   PRINT("Birthday : "+STRING(BD,2,4));   PRINT("Next Extrema Date: "+STRING(E,2,4));   PRINT("Physical: "+ROUND(F1(D),0));   PRINT("Emotional: "+ROUND(F2(D),0));   PRINT("Intellectual: "+ROUND(F3(D),0));   CHECK({1,2,3});UNCHECK({0,4,5,6,7,8,9});   STARTVIEW(1);   RETURN E; END;

Do you have a list of test dates and results to check?
Here are some results from the program above:
Code:
Birthday : 1955.0819 Next Extrema Date: 2018.1022 Physical: 100 Emotional: 62 Intellectual: 100 Birthday : 2018.0928 Next Extrema Date: 2018.1130 Physical: −100 Emotional: 100 Intellectual: −54 Birthday : 1963.0227 Next Extrema Date: 2018.1114 Physical: −100 Emotional: −100 Intellectual: −76 Birthday : 1905.0101 Next Extrema Date: 2018.1010 Physical: −100 Emotional: 62 Intellectual: 100
10-05-2018, 12:26 PM (This post was last modified: 10-05-2018 01:19 PM by Joe Horn.)
Post: #72
 Joe Horn Senior Member Posts: 1,892 Joined: Dec 2013
RE: HHC 2018 Programming Contests
(10-05-2018 07:45 AM)Didier Lachieze Wrote:  Do you have a list of test dates and results to check?
Here are some results from the program above...

Your results are all correct. Here are some of the inputs & expected outputs that were used to test the contest entries on 30 Sept 2018. All dates below are shown in MM/DD/YYYY format.

Input Date --> Next Extrema Date { P E I }
05/18/1975 --> 04/14/2019 { 100 -100 -19 }
05/19/1975 --> 10/01/2018 { -100 -100 19 }
02/12/2007 --> 10/01/2018 { -100 -100 -100 }
10/29/1989 --> 02/03/2019 { -100 -100 -54 }
03/02/1969 --> 03/31/2019 { 100 100 99 }
05/09/1968 --> 10/11/2018 { -100 -100 54 }
01/23/1921 --> 02/03/2019 { -100 -100 0 }
08/07/1921 --> 03/31/2019 { -82 -100 -100 } ***
09/19/1920 --> 11/27/2018 { 100 -90 -100 }

*** That's the only input which I've found which your program gets a different result for (after changing "Date" in your program to "2018.0930" of course).
EDIT: Oh, now I see why. Your program starts looking for the "next" Maxima Date TODAY. The contest specified "not including today". That's an easy program adjustment.

<0|ɸ|0>
-Joe-
10-05-2018, 02:25 PM
Post: #73
 David Hayden Senior Member Posts: 411 Joined: Dec 2013
RE: HHC 2018 Programming Contests
After the conference and before checking the forum, I worked on an RPL solution using the MOD tricks that others have also found. Recognizing that the maximum days of the E cycle (days 7 and 14) are the same as a 14 days cycle with maximum on day 7 and using the ICHINREM command on the 50g, I found that the extreme days occur on:
[ 91 371 ] MOD 462
[ 190 305 454 569 ] MOD 759
[ 63 259 ] MOD 322

My contribution to the thread is in how, given a number that's less than the modulus, I find the first value in the array after the number. For example, given 100, I want to find 371 in the first list, or 190 in the second, or 259 in the third. You can almost find the next value in the array with:
Code:
@ Level 2 is array @ Level 1 is search number « \-> X   « 1 DO GETI UNTIL X > END     @ level 1 now points one past the value you want. Level 2 is the array     1 - GET   » »

There are two problems with this code. First, if you find the last value then GETI will go back to 1, so the final "1 - GET" won't work. I solve this by adding an extra dummy number at the end of the list.

Second, what if the value you're looking for is larger than the largest value? For example, with [ 91 371 ] MOD 462, what if you're looking for 400? In that case, you need to find the value that's 91 MOD 462 in the next cycle (553).

So the trick is to feed this code with an array that contains (1) the first number in the next cycle, and (2) an extra dummy entry at the end:
For modulus 462, search [ 91 371 553 0]
For modulus 759, search [ 190 305 454 569 949 0]
For modulus 322, search [ 63 259 385 0]

My code (again, not my conference entry, but developed before looking at the forum) runs in about .87 seconds on a 50g, including pretty tagging of the results. I can probably shorten that using some of the list processing techniques that others have used. I'll post the full code when I'm done.

Dave
10-05-2018, 07:23 PM
Post: #74
 Gerson W. Barbosa Senior Member Posts: 1,473 Joined: Dec 2013
RE: HHC 2018 Programming Contests
HP-48G/GX version:

Code:
 %%HP: T(3)A(R)F(.); \<< RCLF RAD { 190. 305. 454. 569. 949. } { 91. 371. 553. 833. 1015. } { 63. 259. 385. 581. 707. } 5. ROLL DUP DATE DUP ROT ROT DDAYS 1. 2.   START DUP   NEXT 3. \->LIST { 644. 924. 759. } MOD { } 1. 3.   FOR i SWAP DUP i GET 1. 4.     START DUP     NEXT 5. \->LIST 6. ROLL SWAP - DUP 0. > *     WHILE DUP HEAD NOT     REPEAT TAIL     END 1. GET ROT +   NEXT SWAP DROP SORT OBJ\-> DROP DROP2 DATE+ DUP ROT ROT DDAYS \pi * DUP DUP 3. \->LIST { 11.5 14. 16.5 } / SIN 100. * 0. RND ROT STOF \>>

476.5 bytes, # 7FDEh
10-05-2018, 08:26 PM
Post: #75
 3298 Member Posts: 182 Joined: Oct 2014
RE: HHC 2018 Programming Contests
Gerson, I just stepped through your code to get a feeling of how it works; I couldn't help but notice some less-than-optimal pieces in there.
- In the condition part of your WHILE loop, you use HEAD. That's the optimal solution.
- Right after the END of the WHILE loop, you use 1. GET. Same thing, but slower, bulkier, and most likely less elegant.
- In the long final line of code, you use OBJ\-> DROP DROP2 on a three-element list. Again, the same result, but also slower, bulkier, and most likely less elegant than the dedicated command.

In the 50g version you also used 3. NDUPN \->LIST in one place and DUPDUP \->V3 AXL in another for the same purpose. (The first one is shorter, by the way. Concerning elegance, it's probably a wash, but the lack of consistence doesn't quite sit right with me. I'm not the judge though.) In the 48GX version they became more similar, 1. 2. START DUP NEXT 3. \->LIST for the first one and DUP DUP 3. \->LIST for the second one. (I'd prefer the second one there.)
The 48GX version has another instance of START DUP NEXT, but with four iterations this time. I realize that it's part of a simple replacement for NDUPN, but just writing DUP DUP DUP DUP would shorten it by 2.5 bytes without a significant impact on readability ≃ elegance. (Erm, wait a minute. Tilde as dead key followed by = on Linux produces the "approximately equal" symbol? Awesome! Didn't even know it was mapped on the keyboard.)
10-05-2018, 09:32 PM
Post: #76
 Joe Horn Senior Member Posts: 1,892 Joined: Dec 2013
RE: HHC 2018 Programming Contests
Here is Eddie Shore's winning PPL entry:

Code:
sub1(); // elegant background screen EXPORT BIOXTR() BEGIN STARTAPP("Function"); Xmin:=−6*π;Xmax:=6*π; Ymin:=−1.1;Ymax:=1.1; sub1(); TEXTOUT("BIORYTHM",−2*π,0,5); TEXTOUT("by Edward Shore",−2*π,−.5,5); TEXTOUT("Find your fate.",−2*π,−2,5); WAIT(1); // enter birthdate LOCAL b,b1,b2,b3; INPUT({b1,b2,b3}, "When were you born?", {"Month: ","Day: ","Year: "}); b:=b3+b1/100+b2/10000; // calculation LOCAL d,L0,L1,t,m,p; d:=DDAYS(b,Date); L0:={CEILING((d-5.75)/11.5), CEILING((d-7)/14), CEILING((d-8.25)/16.5)}; L1:={ROUND(11.5*L0(1)+5.75,0), ROUND(14*L0(2)+7,0), ROUND(16.5*L0(3)+8.25,0)}; // loop WHILE L1(1)≠L1(2) AND L1(1)≠L1(3) AND L1(2)≠L1(3) DO m:=POS(L1,MIN(L1)); L0(m):=L0(m)+1; L1:={ROUND(11.5*L0(1)+5.75,0), ROUND(14*L0(2)+7,0), ROUND(16.5*L0(3)+8.25,0)}; END; // an elegant way to extract the date IF L1(2)==L1(3) THEN t:=L1(2); ELSE t:=L1(1); END; d:=DATEADD(b,t); // results screen LOCAL str1; LOCAL L2:= {{"Physical: ",23}, {"Emotional: ",28}, {"Intellectual: ",33}}; sub1(); TEXTOUT("Your next extreme day is on...",−5*π,1,5); WAIT(0.5); str1:=STRING(IP(FP(d)*100))+" / " +STRING(FP(d*100)*100)+" / " +STRING(IP(d)); TEXTOUT(str1,−5*π,.6,5); FOR m FROM 1 TO 3 DO str1:=L2(m,1)+ STRING(ROUND(100*SIN(2*π*t/L2(m,2)),0)); TEXTOUT(str1,−5*π,.6-.2*m,5); END; WAIT(0); STARTVIEW(−1); END; // screen subroutine sub1() BEGIN RECT();  LOCAL t; HAngle:=0; FOR t FROM −6*π TO 6*π STEP 12*π/720 DO PIXON(t,SIN(2*π*t/23),#008000h); PIXON(t,SIN(2*π*t/28),#FF0000h); PIXON(t,SIN(2*π*t/33),#0000FFh); END; END;

When run, it shows this splash screen:

The code seems to indicate that Eddie intended this screen to also say "Find your fate", but the position specified for that text is off the screen... a minor cosmetic bug. Eddie, where did you intend those three lines of text to appear?

The program then uses an input form to get the user's birthdate, with proper prompts:

It then outputs the next Extrema Date in elegant fashion:

Congrats to Eddie!

<0|ɸ|0>
-Joe-
10-05-2018, 09:51 PM
Post: #77
 Gerson W. Barbosa Senior Member Posts: 1,473 Joined: Dec 2013
RE: HHC 2018 Programming Contests
(10-05-2018 08:26 PM)3298 Wrote:  - In the condition part of your WHILE loop, you use HEAD. That's the optimal solution.
- Right after the END of the WHILE loop, you use 1. GET. Same thing, but slower, bulkier, and most likely less elegant.
- In the long final line of code, you use OBJ\-> DROP DROP2 on a three-element list. Again, the same result, but also slower, bulkier, and most likely less elegant than the dedicated command.

In the 50g version you also used 3. NDUPN \->LIST in one place and DUPDUP \->V3 AXL in another for the same purpose. (The first one is shorter, by the way. Concerning elegance, it's probably a wash, but the lack of consistence doesn't quite sit right with me. I'm not the judge though.) In the 48GX version they became more similar, 1. 2. START DUP NEXT 3. \->LIST for the first one and DUP DUP 3. \->LIST for the second one. (I'd prefer the second one there.)
The 48GX version has another instance of START DUP NEXT, but with four iterations this time. I realize that it's part of a simple replacement for NDUPN, but just writing DUP DUP DUP DUP would shorten it by 2.5 bytes without a significant impact on readability ≃ elegance.

Points taken. “1 n-1 START DUP NEXT n” as a replacement for NDUPN was done mechanically when I realized the HP-48 lacked it. Your advice not to use that for small n is correct. By replacing those with DUP DUP sequences I’ve manage to save ten bytes. HEAD takes one additional nibble when compared to “1 GET”, but I didn’t know the former was more efficient as I haven’t timed both options.
Yes, there are really some inconsistencies here and there, mainly because sometimes I am after smaller code and sometimes I want to be more clear.

At this point I am glad my program works. Optimizations and improvements should be the next step, but I tend to stick with my first ideas, even though when are better ones around, so mine will not evolve much from here.
10-06-2018, 10:14 AM (This post was last modified: 10-06-2018 10:21 AM by Thomas Klemm.)
Post: #78
 Thomas Klemm Senior Member Posts: 1,804 Joined: Dec 2013
RE: HHC 2018 Programming Contests
(10-05-2018 07:23 PM)Gerson W. Barbosa Wrote:  “1 n-1 START DUP NEXT n” as a replacement for NDUPN was done mechanically when I realized the HP-48 lacked it.

You don't even need that since lists can handle that:
Code:
\<< RCLF RAD   { 190 305 454 569 949 }   { 91 371 553 833 1015 }   { 63 259 385 581 707 }   5 ROLL DUP DATE DUP ROT ROT DDAYS   { 644 924 759 } MOD   { } 1 3   FOR i SWAP DUP i GET     6 ROLL SWAP - DUP 0 > *     WHILE DUP HEAD NOT     REPEAT TAIL     END 1 GET ROT +   NEXT SWAP DROP SORT OBJ\-> DROP DROP2 DATE+ DUP ROT ROT DDAYS \PI *   { 11.5 14 16.5 } / SIN 100 * 0 RND ROT STOF \>>

Cheers
Thomas

Just noticed that:
Code:
SORT OBJ\-> DROP DROP2
could be replaced by:
Code:
SORT HEAD
10-06-2018, 11:42 AM
Post: #79
 Gerson W. Barbosa Senior Member Posts: 1,473 Joined: Dec 2013
RE: HHC 2018 Programming Contests
(10-06-2018 10:14 AM)Thomas Klemm Wrote:
(10-05-2018 07:23 PM)Gerson W. Barbosa Wrote:  “1 n-1 START DUP NEXT n” as a replacement for NDUPN was done mechanically when I realized the HP-48 lacked it.

You don't even need that since lists can handle that:
Code:
\<< RCLF RAD   { 190 305 454 569 949 }   { 91 371 553 833 1015 }   { 63 259 385 581 707 }   5 ROLL DUP DATE DUP ROT ROT DDAYS   { 644 924 759 } MOD   { } 1 3   FOR i SWAP DUP i GET     6 ROLL SWAP - DUP 0 > *     WHILE DUP HEAD NOT     REPEAT TAIL     END 1 GET ROT +   NEXT SWAP DROP SORT OBJ\-> DROP DROP2 DATE+ DUP ROT ROT DDAYS \PI *   { 11.5 14 16.5 } / SIN 100 * 0 RND ROT STOF \>>

Cheers
Thomas

Just noticed that:
Code:
SORT OBJ\-> DROP DROP2
could be replaced by:
Code:
SORT HEAD

This saves 47 bytes overall. 429.5 bytes on the 48G/GX and 422 bytes on the 50g (using UNROT for ROT ROT and NIP for SWAP DROP).

Thank you very much!

Gerson.
10-06-2018, 12:07 PM
Post: #80
 3298 Member Posts: 182 Joined: Oct 2014
RE: HHC 2018 Programming Contests
Further improvement: DUP DATE DUP ROT ROT DDAYS can be DATE DUP2 DDAYS instead. Also applies to the 50g version where the new UNROT was used in place of ROT ROT.
Later in the program there's DUP ROT ROT which can be SWAP OVER. In SysRPL there's a command that is named both DUPUNROT and SWAPOVER because these operations are equivalent, but since UNROT is not a thing in the 48 version of UserRPL, the latter translates to a shorter UserRPL command sequence. On the 50g it's irrelevant of course.
(10-05-2018 09:51 PM)Gerson W. Barbosa Wrote:  HEAD takes one additional nibble when compared to “1 GET”, but I didn’t know the former was more efficient as I haven’t timed both options.
Wait, HEAD is a romptr? HP, why!?
I didn't actually check the length because I just assumed that such a basic command would be part of the command set which are merely simple pointers. Now I did, and you're right. HEAD is indeed a romptr, which makes it bigger than the more flexible (as in: can be changed to use other indices) 1 GET. At least on my 50g it's still slightly faster, so there's that (even though romptrs take a few milliseconds to resolve; I guess GET spends that time converting the real number to a system binary integer).
 « Next Oldest | Next Newest »

User(s) browsing this thread: 1 Guest(s)