# While..Do

## Contents

## While (*test*) Do *body*

**While** evaluates «body» repeatedly as long as «test» *<> 0*.

In order for While to terminate, «body» must produce a side-effect on a local variable that is used by «test», causing «test» eventually to equal 0. If «test» never becomes *false*, While continues to loop indefinitely. If you suspect that might be happening, type *Control+Break* or *Control+.* (*Control+period*) to interrupt evaluation.

While returns the final value found in the last iteration of «body», or Null if no iterations occur.

«Test» must evaluate to an atomic (non-array) value; therefore, it is a good idea to force any local variable used in «test» to be atomic valued. While is one of the few constructs in Analytica that does not generalize completely to handle arrays. But, there are ways to ensure that variables and functions using While support Intelligent Arrays and probabilistic evaluation.

## Examples

`Var n := 1;`

`While n < 1000 do n := 2*n`

`n → 1024`

`Var x := 1;`

`Var prev := 0;`

`while Abs(x - prev) > 1e-6 do (`

`prev := x ;`

`x := 1 + 1/(1 + x)`

`)`

`x → 1.414214`

## Array Abstraction with While

The While construct is one of a few constructs in Analytica that does not fully array abstract. The limitation arises from the fact that «test» must be a scalar value, i.e., it cannot be array valued. Consider, for example, the following expression:

`Var n := start;`

`Var steps := 0;`

`While n > 1 do (`

`n := If Mod(n, 2) = 0 then n/2 else 3*n + 1;`

`steps := steps + 1`

`)`

If `start = 20`

when this is evaluated, this returns `7`

(*n* steps through values of `20, 10, 5, 16, 8, 4, 2, 1`

). If `start = 22`

, it returns `15`

, and for `start = 27`

it returns `111`

. One of the key features of an Analytica model is the ability to easily add a dimension to an input without having to change the model's internals. So what we'd like is that when `start`

is set to the list `[20, 22, 27]`

, the expression would array-abstract and return the result array `[7, 15, 111]`

. However, the above expression will result in an error, complaining that «test» is not a scalar.

While disallows «test» to be an array, because otherwise the criteria for termination is ambiguous. It may be that for certain elements, the loop should be terminated, while for others it should not.

These problems can be addressed by declaring the dimensionality of all parameters that influence «test». We can do this simply in this example by listing the dimensions of *n* when it is declared -- in this case listing zero dimensions, hence there are no index identifiers between the brackets in its declaration:

`Var n[ ] := start;`

`Var steps := 0;`

`While n > 1 do (`

`n := If Mod(n, 2) = 0 then n/2 else 3*n + 1;`

`steps := steps + 1`

`)`

When this is evaluated and `start`

is array-valued, Analytica sees that *n* must be scalar in the expression that uses *n*. To accomplish that, Analytica will iterate as necessary, setting *n* to a single scalar value each time. Without the brackets, *n* is passed down as an array.

The **While..Do** construct is used most often from within User-Defined Functions. In this case, the dimensionality declaration should be placed on the Function Parameter Qualifiers. In this case, we would declare the parameter `start`

to be atomic:

`Function Num3nSteps(start: atomic)`

`Definition:`

`Var n := start;`

`Var steps := 0;`

`While n > 1 do (`

`n := If Mod(n, 2) = 0 then n/2 else 3*n + 1;`

`steps := steps + 1`

`)`

## While Any *cond* Do

When the condition evaluates to an array, the keyword **Any** can be specified to indicate that the while loop is to continue as long as any of the elements of the array is non-zero. Example:

`Var steps := 0;`

`Var x := start;`

`While Any x > 1 Do (`

`steps := If x > 1 Then steps + 1 Else steps;`

`x := If x < 2 Then x`

`Else If Mod(x, 2) = 0 Then x/2`

`Else 3*x + 1;`

`);`

`steps`

In general, **Any** iterates most elements more times than necessary in order to handle extra dimensions.

Enable comment auto-refresher