[REBOL] cycling
From: joel:neely:fedex at: 5-Jul-2001 12:58
Given a set of M "index" values, what's the simplest way to
cycle through them, both forward and backward?
In the two commonest cases, the M values might occupy either
the range 0 thru M - 1 or the range 1 thru M.
Let N0F, N0B, N1F, and N1B hold the current counters for all
combinations of ranges and directions.
------ range of ------
direction 0 .. m - 1 1 .. m
--------- ---------- --------
forward n0f n1f
backward n0b n1b
The simplest possibilities I've found for putting these
variables through their paces are:
Pure Arithmetic:
n0f: (n0f + 1) // m
n0b: (n0b + m - 1) // m
n1f: (n1f // m) + 1
n1b: (n1b + m - 2) // m + 1
Expressional:
n0f: either m - 1 = n0f [0] [n0f + 1]
n0b: either 0 = n0b [m - 1] [n0b - 1]
n1f: either m = n1f [1] [n1f + 1]
n1b: either 1 = n1b [m] [n1b - 1]
Imperative:
n0f: n0f + 1 if n0f = m [n0f: 0]
if n0b = 0 [n0b: m] n0b: n0b - 1
n1f: n1f + 1 if n1f > m [n1f: 1]
n1b: n1b - 1 if n1b = 0 [n1b: m]
For example, using the pure arithmetic version:
>> n0f: n0b: n1f: n1b: 1
== 1
>> m: 5
== 5
>> loop 15 [
[ print [n0f n0b n1f n1b]
[ set [n0f n0b n1f n1b] reduce [
[ (n0f + 1) // m (n0b + m - 1) // m
[ (n1f // m) + 1 (n1b + m - 2) // m + 1
[ ]
[ ]
1 1 1 1
2 0 2 5
3 4 3 4
4 3 4 3
0 2 5 2
1 1 1 1
2 0 2 5
3 4 3 4
4 3 4 3
0 2 5 2
1 1 1 1
2 0 2 5
3 4 3 4
4 3 4 3
0 2 5 2
= [1 1 1 1]
A comparison of these options, along with relative timings
based on a 3,000,000 cycle benchmark, includes the following
observations:
Option Time Pro Con
--------------- ---- ---------------- ------------------
Pure Arithmetic 1.00 * Fastest * Least obvious to
* Most compact casual reader
Expressional 1.31 * Most obvious * Slowest
Imperative 1.15 * Somewhat obvious * Can't be used as
subexpressions
Other observations or alternative calculations are welcomed.
-jn-
--
------------------------------------------------------------
Programming languages: compact, powerful, simple ...
Pick any two!
joel'dot'neely'at'fedex'dot'com