Variables Assigned at Run Time (Units: A Unit Conversion Program and Scientific Calculator)

### 5.7 Variables Assigned at Run Time ¶

Unit definitions are fixed once `units` has finished reading the units data file(s), but at run time you can assign unit expressions to variables whose names begin with an underscore, using the syntax

    _name = <unit expression>

This can help manage a long calculation by saving intermediate quantities as variables that you can use later. For example, to determine the shot-noise-limited signal-to-noise ratio (SNR) of an imaging system using a helium–neon laser, you could do

    You have: _lambda = 632.8 nm            # laser wavelength
    You have: _nu = c / _lambda             # optical frequency
    You have: _photon_energy = h * _nu
    You have: _power = 550 uW
    You have: _photon_count = _power * 500 ns / _photon_energy
    You have: _snr = sqrt(_photon_count)
    You have: _snr
    You want:
            Definition: sqrt(_photon_count) = 29597.922

Except for beginning with an underscore, runtime variables follow the same naming rules as units. Because names beginning with ‘`_`’ are reserved for these variables and unit names cannot begin with ‘`_`’, runtime variables can never hide unit definitions. Runtime variables are undefined until you make an assignment to them, so if you give a name beginning with an underscore and no assignment has been made, you get an error message.

When you assign a unit expression to a runtime variable, `units` checks the expression to determine whether it is valid, but the resulting definition is stored as a text string that is not reduced to primitive units. The text will be processed anew each time you use the variable in a conversion or calculation; this means that if your definition depends on other runtime variables (or the special variable ‘`_`’), the result of calculating with your variable will change if any of those variables change. A dependence need not be direct.

Continuing the example of the laser above, suppose you have done the calculation as shown. You now wonder what happens if you switch to an argon laser:

    You have: _lambda = 454.6 nm
    You have: _snr
    You want:
            Definition: sqrt(_photon_count) = 25086.651

If you then change the power:

    You have: _power = 1 mW
    You have: _snr
    You want:
            Definition: sqrt(_photon_count) = 33826.834

Instead of having to reenter or edit a lengthy expression when you perform another calculation, you need only enter values that change; in this respect, runtime variables are similar to a spreadsheet.

The more times a variable appears in an expression that depends on it, the greater the benefit of having a calculation using that expression reflect changes to that variable. For example, the length of daylight—the time the Sun is above the horizon—at a given latitude and declination of the Sun is given by

L = 2 \cos^{-1} \left ( { \sin h - \sin \phi \sin \delta } \over { \cos \phi \cos \delta } \right )

where \({L}\) is the day length, \({h}\) is the Sun’s altitude (elevation angle), \({\phi}\) is the location’s latitude, and \({\delta}\) is the Sun’s declination (angle with the equatorial plane). The result above is in sidereal time; the length in solar time is obtained by multiplying by

    siderealday / day

By convention, the Sun’s altitude at rise or set is \({-50^\prime}\) to allow for atmospheric refraction and the semidiameter of its disk. At the summer solstice in the northern hemisphere, the Sun’s declination is approximately \({23.44^\circ}\) ; to find the length of the longest day of the year for a latitude of \({55^\circ}\) , you could do

    You have: _alt = -50 arcmin
    You have: _lat = 55 deg
    You have: _decl = 23.44 deg
    You have: _num = sin(_alt) - sin(_lat) sin(_decl)
    You have: _denom = cos(_lat) cos(_decl)
    You have: _sday = 2 (acos(_num / _denom) / circle) 24 hr
    You have: _day = _sday siderealday / day
    You have: _day
    You want: hms
            17 hr + 19 min + 34.895151 sec

At the winter solstice, the Sun’s declination is approximately \({-23.44^\circ}\) , so you could calculate the length of the shortest day of the year using:

    You have: _decl = -23.44 deg
    You have: _day
    You want: hms
            7 hr + 8 min + 40.981084 sec

Latitude and declination each appear twice in the expression for `_day`; the result in the examples above is updated by changing only the value of the declination.

It may seem easier—and less subject to error—to simply specify the new value of `_decl` as the negative of the current value (e.g., ‘`_decl = -_decl`’). This doesn’t work; when you make an assignment with the ‘`=`’ operator, the definition is stored as entered, including possible dependencies on variables. But if you attempt an assignment that is ultimately self-referential, the current definition is retained, and you get an error message. For example,

    You have: _decl = 23.44 deg
    You have: _decl = -_decl
    Circular unit definition

You can overcome this by using the ‘`:=`’ operator, which reduces the right hand side to primitive units before making the assignment, eliminating any dependencies on variables. Returning to the example above,

    You have: _decl = 23.44 deg
    You have: _decl = -_decl
    Circular unit definition
    You have: _decl := -_decl
    You have: _decl
    You want: deg
            * -23.44
            / -0.042662116

This works to much the same effect as if the assignment had been entered literally, e.g.,

    You have: _decl = -23.44 deg

but the actual definition is in primitive units—in this case, radians:

    You have: _decl = 23.44 deg
    You have: _decl := -_decl
    You have: _decl
    You want:
            Definition: -0.40910517666747087 radian = -0.40910518 radian

Definitions are text strings, and a redefinition using ‘`:=`’ is given with enough digits maintain the full precision of the current definition when converted back to a number; because it is a string, all digits are displayed when showing the definition, regardless of the numerical display precision, so you may see more digits than expected.

A runtime variable must be assigned before it can be used in an assignment; in the first of the three examples above, giving the general equation before the values for `_alt`, `_lat`, and `_decl` had been assigned would result in an error message.

You can display a list of runtime variables you have assigned by typing `search _`.