odometer <- setodometer([lower:L,] upper:U [,ndigits:M, ] [,place:N]), L and U integer scalars or vectors, integer M > 0, N >= 0 odometer <- setodometer(odometer, place:N), odometer a structure with integer components 'digits', 'lower', 'upper', 'place' odometer <- setodometer(odometer [,step:n]), integer n, default 1 |

Description of an odometer Function setodometer() is used to create or modify an "odometer". An odometer is a structure of the form structure(digits:D, lower:L, upper:U, place:N) where D is a vector of M integers and L and U are integer vectors of length M or scalars. D, L and U satisfy L[i] <= D[i] <= U[i], where L and U are interpreted as rep(L, M) and rep(U, M) when they are scalars. See topics 'scalars', 'vectors' and 'structures' for information on these types of variables. See below for how to use setodometer() to create, set and advance an odometer. In the following, when L and/or U are scalars, L[i] and U[i] should be interpreted as L and/or U (rep(L,M)[i] and/or rep(U,M)[i]). Note: L[i] = U[i] is permitted. An odometer is modeled on the distance display in an automobile, with the M elements of D corresponding to the digits in the display. It differs in that D[i] runs from L[i] to U[i] instead of from 0 to 9, and the digits are in reverse order (D[1] is the least significant, D[M] is the most significant). N corresponds to the distance traveled. When N = 0, D = vector(L[1], L[2], ..., L[M]) (rep(L,M) when L is a scalar). Let I = D - L and let R = U - L + 1 (rep(U - L + 1, M) when U and L are scalars) and define Size = prod(R). When 0 <= N < Size, the elements of I are the 'digits' of N in a mixed radix representation with radices R[i], in reverse order. For example, when M = 3, N = I[1] + I[2]*R[1] + I[3]*R[1]*R[2]. When L = 0 and U = m-1 are scalars, the elements of I are the base m digits of N, in order from least to most significant. When N < 0 or N >= Size, the elements of I are the digits of N modulo Size (N - Size*floor(N/Size)). Creating an odometer O <- setodometer(lower:L, upper:U, ndigits:M) creates an odometer O. M > 0 must be an integer, and L and U must be integer scalars or vectors of length M, with a scalar L or U interpreted as rep(U,M) or rep(L,M). L and U must satisfy L[i] <= U[i], R[i] = U[i] - L[i] + 1 < 2^31, and Size = prod(R) < 2^52. These limits may be different on some computer systems. Component 'digits' is initialized to L (or rep(L,M) when L is a scalar). Components 'lower' and 'upper' are initialized to L and U, respectively, and component 'place' is initialized to 0. O <- setodometer(lower:L, upper:U), without 'ndigits:M', is equivalent to O <- setodometer(lower:L,upper:U,ndigits:max(length(L),length(U))). O <- setodometer(upper:U [,ndigits:M]) is equivalent to O <- setodometer(lower:0, upper:U [,ndigits:M]); that is, the default value for 'lower' is 0. O <- setodometer([lower:L,] upper:U [,ndigits:M], place:N) does the same, except O$place is set to N and O$digits is set to L + mixed radix digits of N. N must satisfy 0 <= N < Size = prod(U-L+1). Setting and advancing an odometer O1 <- setodometer(O, place:N) is equivalent to O1 <- odometer(lower:O$lower,upper:O$upper,ndigits:length(O$digits), place:N); that is, it creates an odometer O1 with the same L and U as O, but at place N. O1 <- setodometer(O, step:n), where O is an odometer and n is an integer, creates an odometer O1 with O1$place = O$place + n. O1$digits is computed by stepping O$digits forward n steps when n >= 0, or backward by -n steps when n < 0. n must satisfy abs(n) < Size = prod(U-L+1). When abs(n) is large, this may take some time since it is computed as a sequence of single forward or backward steps. O1 <- setodometer(O) is equivalent to O1 <- setodometer(O, step:1); that is the odometer is advanced by 1. When 0 <= O$place + n < Size, setodometer(O, step:n) is equivalent to setodometer(O, place:O$place + n), except that setodometer(O, step:n) can be much slower when abs(n) is large. Examples: Step through the various factor combinations of a 2^k design: Cmd> counter <- setodometer(upper:1,ndigits:k) #lower is 0 Cmd> for(i,run(2^k)){ levels <- counter$digits # do something with levels counter <- setodometer(counter);; # step by 1 } Find hexadecimal representation Cmd> N <- 9 + 3*16 + 11*16^2 + 15*16^3; N (1) 64313 Cmd> O <- setodometer(upper:15,ndigits:8,place:N); O # lower is 0 component: digits (1) 9 3 11 15 0 (6) 0 0 0 component: lower (1) 0 component: upper (1) 15 component: place (1) 64313 Cmd> letters <- vector("0","1","2","3","4","5","6","7","8","9",\ "A","B","C","D","E","F") Cmd> paste(letters[reverse(O$digits)+1],sep:"") (1) "0000FB39" Cmd> O <- setodometer(lower:1,upper:16,ndigits:8,place:N); O #lower 1 component: digits (1) 10 4 12 16 1 (6) 1 1 1 component: lower (1) 1 component: upper (1) 16 component: place (1) 64313 Cmd> paste(letters[reverse(O$digits)],sep:"") # +1 not needed now (1) "0000FB39" Macro to find binary bits of integer from most to least significant Cmd> bits <- macro("@N <- argvalue($1,\"N\",\"pos int scalar\") @ndigits <- ceiling(log(@N+1)/log(2)) reverse(setodometer(upper:1,ndigits:@ndigits,place:@N)$digits)") Cmd> bits(N) (1) 1 1 1 1 1 (6) 0 1 1 0 0 (11) 1 1 1 0 0 (16) 1 See also paste(), prod(), reverse(), max(), macro(), 'macros', 'macro_syntax'.

Gary Oehlert 2003-01-15