Post Reply 
HHC 2018 Programming Contests
10-04-2018, 02:48 PM (This post was last modified: 10-04-2018 05:14 PM by 3298.)
Post: #63
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.
Find all posts by this user
Quote this message in a reply
Post Reply 


Messages In This Thread
HHC 2018 Programming Contests - Joe Horn - 09-13-2018, 02:17 PM
RE: HHC 2018 Programming Contests - pier4r - 09-13-2018, 06:29 PM
RE: HHC 2018 Programming Contests - Zaphod - 09-13-2018, 10:10 PM
RE: HHC 2018 Programming Contests - Gene - 09-13-2018, 10:56 PM
RE: HHC 2018 Programming Contests - Gene - 09-14-2018, 12:06 AM
RE: HHC 2018 Programming Contests - Jlouis - 09-19-2018, 07:00 PM
RE: HHC 2018 Programming Contests - sasa - 09-19-2018, 11:17 AM
RE: HHC 2018 Programming Contests - pier4r - 09-29-2018, 07:41 PM
RE: HHC 2018 Programming Contests - 3298 - 09-30-2018, 05:32 PM
RE: HHC 2018 Programming Contests - 3298 - 09-30-2018, 08:47 PM
RE: HHC 2018 Programming Contests - Gene - 09-29-2018, 07:22 PM
RE: HHC 2018 Programming Contests - Gene - 10-01-2018, 02:55 AM
RE: HHC 2018 Programming Contests - sasa - 10-01-2018, 05:31 AM
RE: HHC 2018 Programming Contests - sasa - 10-01-2018, 09:54 AM
RE: HHC 2018 Programming Contests - 3298 - 10-01-2018, 06:37 AM
RE: HHC 2018 Programming Contests - Werner - 10-01-2018, 01:42 PM
RE: HHC 2018 Programming Contests - Werner - 10-02-2018, 06:10 AM
RE: HHC 2018 Programming Contests - Namir - 10-04-2018, 06:09 PM
RE: HHC 2018 Programming Contests - Werner - 10-03-2018, 02:03 PM
RE: HHC 2018 Programming Contests - Werner - 10-04-2018, 05:55 AM
RE: HHC 2018 Programming Contests - 3298 - 10-04-2018 02:48 PM
RE: HHC 2018 Programming Contests - 3298 - 10-05-2018, 08:26 PM
RE: HHC 2018 Programming Contests - 3298 - 10-06-2018, 12:07 PM
RE: HHC 2018 Programming Contests - 3298 - 10-06-2018, 04:21 PM



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