05-16-2018, 06:12 PM
DUPN and NDUPN are very useful RPL commands that also happen to be very fast ways of replicating objects on the stack. DUPN makes a single copy of the number of objects specified:
1 2 3 3 DUPN => 1 2 3 1 2 3
...and NDUPN makes a single object with the specified number of copies, followed by the number of copies:
7 8 9 3 NDUPN => 7 8 9 9 9 3.
Another similar scenario that can be useful has no single command, though. Specifically, replicating a group of objects a set number of times. The following SysRPL program can be used to perform this function:
Compile the above and give it a suitable name (I use NMDUP). To use it, place two numbers on the stack which represent the following:
2: N (the number of elements in the stack to replicate/group size)
1: M (the number copies of the elements to make)
Note that M represents the total quantity of duplicates, not the additional ones. So a quantity of 0 is the same as dropping N elements, a quantity of 1 does nothing, etc. Likewise, an N of 0 will have no affect on the rest of the stack, as there are no stack items identified for replication.
Examples:
1 2 3 3 0 NMDUP => <nothing>
1 2 3 3 1 NMDUP => 1 2 3
1 2 3 3 2 NMDUP => 1 2 3 1 2 3
1 2 3 2 5 NMDUP => 1 2 3 2 3 2 3 2 3 2 3
1 2 3 0 5 NMDUP => 1 2 3
1 2 3 3 DUPN => 1 2 3 1 2 3
...and NDUPN makes a single object with the specified number of copies, followed by the number of copies:
7 8 9 3 NDUPN => 7 8 9 9 9 3.
Another similar scenario that can be useful has no single command, though. Specifically, replicating a group of objects a set number of times. The following SysRPL program can be used to perform this function:
Code:
::
( stack on entry:
n: anything
...
2: group count [integer]
1: repeat factor [integer]
)
CK2NOLASTWD ( stack must contain at least 2 objects )
CK&DISPATCH1
BINT17 ( ..., real, real ) :: ( SL1/2 must contain numbers )
COERCE2 ( convert to BINTs )
OVER #3+ ( check stack depth )
DEPTH #> case SETSTACKERR ( error if stack not deep enough )
( special cases )
DUP#0=case :: DROP NDROP ; ( repeat factor of 0 )
DUP#1= casedrop DROP ( repeat factor of 1 )
OVER#0= casedrop DROP ( group count of 0 )
( otherwise )
SWAP 1LAMBIND ( save group count in NULLLAM )
ONE_DO (DO) ( loop [repfactor - 1] times )
1GETLAM NDUP ( NDUP the current group )
LOOP
ABND ( abandon NULLLAM )
;
;
Compile the above and give it a suitable name (I use NMDUP). To use it, place two numbers on the stack which represent the following:
2: N (the number of elements in the stack to replicate/group size)
1: M (the number copies of the elements to make)
Note that M represents the total quantity of duplicates, not the additional ones. So a quantity of 0 is the same as dropping N elements, a quantity of 1 does nothing, etc. Likewise, an N of 0 will have no affect on the rest of the stack, as there are no stack items identified for replication.
Examples:
1 2 3 3 0 NMDUP => <nothing>
1 2 3 3 1 NMDUP => 1 2 3
1 2 3 3 2 NMDUP => 1 2 3 1 2 3
1 2 3 2 5 NMDUP => 1 2 3 2 3 2 3 2 3 2 3
1 2 3 0 5 NMDUP => 1 2 3