Ranges (GNU Octave (version 11.1.0))

### 4.2 Ranges ¶

A range is a convenient way to write a row vector with evenly spaced elements. A range expression is defined by the value of the first element in the range, an optional value for the increment between elements, and a maximum value which the elements of the range will not exceed. The base, increment, and limit are separated by colons (the ‘`:`’ character) and may contain any arithmetic expressions and function calls. If the increment is omitted, it is assumed to be 1. For example, the range

    1 : 5

defines the set of values `[ 1, 2, 3, 4, 5 ]`, and the range

    1 : 3 : 5

defines the set of values `[ 1, 4 ]`.

Although a range constant specifies a row vector, Octave does not normally convert range constants to vectors unless it is necessary to do so. This allows you to write a constant like `1 : 10000` without using 80,000 bytes of storage on a typical workstation.

A common example of when it does become necessary to convert ranges into vectors occurs when they appear within a vector (i.e., inside square brackets). For instance, whereas

    x = 0 : 0.1 : 1;

defines x to be a variable of type `double_range` and occupies 24 bytes of memory, the expression

    y = [ 0 : 0.1 : 1];

defines y to be of type `matrix` and occupies 88 bytes of memory.

This space saving optimization may be disabled using the function `optimize_range`.

`val =` optimize_range `()` ¶
`old_val =` optimize_range `(new_val)` ¶
`old_val =` optimize_range `(new_val, "local")` ¶

  Query or set whether a special space-efficient format is used for storing ranges.

  The default value is true. If this option is set to false, Octave will store ranges as full matrices.

  When called from inside a function with the `"local"` option, the setting is changed locally for the function and any subroutines it calls. The original setting is restored when exiting the function.

  See also: optimize_diagonal_matrix, optimize_permutation_matrix.

Note that the upper (or lower, if the increment is negative) bound on the range is not always included in the set of values. This can be useful in some contexts. For example:

    ## x is some predefined range or vector or matrix or array
    x(1:2:end) += 1;   # increment all  odd-numbered elements
    x(2:2:end) -= 1;   # decrement all even-numbered elements

The above code works correctly whether x has an odd number of elements or not: there is no need to treat the two cases differently.

Octave uses floating point arithmetic to compute the values in the range. As a result, defining ranges with floating-point values can result in pitfalls like these:

    a = -2
    b = (0.3 - 0.2 - 0.1)
    x = a : b

Due to floating point rounding, b may or may not equal zero exactly, and if it does not, it may be above zero or below zero, hence the final range x may or may not include zero as its final value. Similarly:

    x = 1.80 : 0.05 : 1.90
    y = 1.85 : 0.05 : 1.90

is not as predictable as it looks. As of Octave 8.3, the results obtained are that x has three elements (1.80, 1.85, and 1.90), and y has only one element (1.85 but not 1.90). Thus, when using floating points in ranges, changing the start of the range can easily affect the end of the range even though the ending value was not touched in the above example.

To avoid such pitfalls with floating-points in ranges, you can use one of the following patterns. This change to the previous code:

    x = (0:2) * 0.05 + 1.80
    y = (0:1) * 0.05 + 1.85

use integers to construct the range and then converts to floating point making the overall expression safe and repeatable across platforms, compilers, and compiler settings. If you know the number of elements, you can use the `linspace` function (see Special Utility Matrices), which will include the endpoints of a range. You can also make judicious use of `round`, `floor`, `ceil`, `fix`, etc. to set the limits and the increment without getting interference from floating-point rounding. For example, the earlier example can be made safer with one of the following:

    a = -2
    b = round ((0.3 - 0.2 - 0.1) * 1e12) / 1e12   # rounds to 12 digits
    c = floor (0.3 - 0.2 - 0.1)                   # floors as integer
    d = floor ((0.3 - 0.2 - 0.1) * 1e12) / 1e12   # floors at 12 digits
    x = a : b
    y = a : c
    z = a : d

If the result of the range expression is empty then Octave returns an empty `matrix`, not an empty `double_range`. Similarly, if there is just a single element in the range then Octave returns a `scalar`, not a `double_range` with one element.