C H A P T E R  1

Using the Interval Arithmetic Library


1.1 What Is Interval Arithmetic?

Interval arithmetic is a system for computing with intervals of numbers. Because interval arithmetic always produces intervals that contain the set of all possible result values, interval algorithms have been developed to perform surprisingly difficult computations. For more information on interval applications, see the Interval Arithmetic Readme.


1.2 C++ Interval Support Goal: Implementation Quality

The goal of interval support in C++ is to stimulate development of commercial interval solver libraries and applications by providing program developers with:

Support and features are components of implementation quality. Not all possible quality of implementation features have been implemented. Throughout this book, various unimplemented quality of implementation opportunities are described. Additional suggestions from users are welcome.

1.2.1 Quality Interval Code

As a consequence of evaluating any interval expression, a valid interval-supporting compiler must produce an interval that contains the set of all possible results. The set of all possible results is called the containment set (cset) of the given expression. The requirement to enclose an expression's cset is the containment constraint of interval arithmetic. The failure to satisfy the containment constraint is a containment failure. A silent containment failure (with no warning or documentation) is a fatal error in any interval computing system. By satisfying this single constraint, intervals provide otherwise unprecedented computing quality.

Given the containment constraint is satisfied, implementation quality is determined by the location of a point in the two-dimensional plane whose axes are runtime and interval width. On both axes, small is better. How to trade runtime for interval width depends on the application. Both runtime and interval width are obvious measures of interval-system quality. Because interval width and runtime are always available, measuring the accuracy of both interval algorithms and implementation systems is no more difficult than measuring their speed.

The Sun Studio tools for performance profiling can be used to tune interval programs. However, in C++, no interval-specific tools exist to help isolate where an algorithm may gain unnecessary interval width. Quality of implementation opportunities include adding additional interval-specific code development and debugging tools.

1.2.2 Narrow-Width Interval Results

All the normal language and compiler quality of implementation opportunities exist for intervals, including rapid execution and ease of use.

Valid interval implementation systems include a new additional quality of implementation opportunity: Minimize the width of computed intervals while always satisfying the containment constraint.

If an interval's width is as narrow as possible, it is said to be sharp. For a given floating-point precision, an interval result is sharp if its width is as narrow as possible.

The following statements apply to the width of intervals produced by the interval class:

1.2.3 Rapidly Executing Interval Code

By providing compiler optimization and hardware instruction support, interval operations are not necessarily slower than their floating-point counterparts. The following can be said about the speed of interval operators and mathematical functions:

1.2.4 Easy-to-Use Development Environment

The C++ interval class facilitates interval code development, testing, and execution.

Sun Studio C++ includes the following interval extensions:

For examples and more information on these and other interval functions, see CODE EXAMPLE 2-8 through CODE EXAMPLE 2-10 and Section 2.9.4, Functions That Accept Interval Arguments.

Chapter 2 contains detailed descriptions of these and other interval features.

1.2.5 The C++ Interval Class Compilation Interface

The compilation interface consists of the following:

It is a fatal error if at the end of command line processing -xia is set, and either -fsimple, -fns, or -ftrap is set to any value other than

-fsimple=0
-fns=no
-ftrap=no
-ftrap=%none

To use the C++ interval arithmetic features, add the following header file to the code.

#include <suninterval.h>

An example of compiling code using the -xia command-line option is shown here.


math% CC -o filename -xia filename.cc

The C++ interval library supports the following common C++ compilation modes:

See the C++ Migration Guide and the C++ User's Guide for more information on these modes.

The following sections describe the ways that these compilation modes affect compilation of applications using the interval library.

1.2.5.1 namespace SUNW_interval

In standard mode only, all interval types and symbols are defined within the namespace SUNW_interval. To write applications that compile in both standard mode and compatibility mode, use the following code.


#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif

1.2.5.2 Boolean Return Values

Some interval functions return boolean values. Because compatibility mode does not support boolean types by default, these functions are defined returning a type interval_bool, which is a typedef to an int (compatibility mode) or a bool (standard mode). Client code should use whatever type appropriate for boolean values and rely on the appropriate conversions from interval_bool to the client's boolean type. The library does not support explicit use of -features=bool or -features=no%bool.

1.2.5.3 Input and Output

The interval library requires the I/O mechanisms supplied in one of the three compilation modes listed in Section 1.2.5, The C++ Interval Class Compilation Interface. In particular, the flag -library=iostream must be specified on all compile and link commands if the application is using the standard mode with the traditional iostream library.


1.3 Writing Interval Code for C++

The examples in this section are designed to help new interval programmers to understand the basics and to quickly begin writing useful interval code. Modifying and experimenting with the examples is strongly recommended.

1.3.1 Hello Interval World

CODE EXAMPLE 1-1 is the interval equivalent of "hello world."


CODE EXAMPLE 1-1 Hello Interval World

math% cat ce1-1.cc
#include <suninterval.h>
 
#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif
 
int main() {
 
cout <<"[2,3]+[4,5]="
         << (interval<double>("[2,3]") +
             interval<double>("[4,5]"));
    cout << endl;
}
 
math% CC  -xia -o ce1-1 ce1-1.cc
math% ce1-1
[2,3]+[4,5]=[0.6000000000000000E+001,0.8000000000000000E+001]
 

CODE EXAMPLE 1-1 uses standard output streams to print the labeled sum of the intervals [2, 3] and [4, 5].

1.3.2 interval External Representations

The integer and floating-point numbers that can be represented in computers are referred to as internal machine representable numbers. These numbers are a subset of the entire set of extended (including -infinity and +infinity) real numbers. To make the distinction, machine representable numbers are referred to as internal and any number as external. Let x be an external (decimal) number or an interval endpoint that can be read or written in C++. Such a number can be used to represent either an external interval or an endpoint. There are three displayable forms of an external interval:


A positive or negative infinite interval endpoint is input/output as a case-insensitive string inf or infinity prefixed with a minus sign or an optional plus sign.

The empty interval is input/output as the case-insensitive string empty enclosed in square brackets, [...]. The string, "empty", can be preceded or followed by blank spaces.

See Section 2.4.1, Arithmetic Operators +, -, *, /, for more details.



Note - If an invalid interval such as [2,1] is converted to an internal interval, [-inf, inf] is stored internally.



1.3.3 Interval Declaration and Initialization

The interval declaration statement performs the same functions for interval data items as the double and int declarations do for their respective data items. CODE EXAMPLE 1-2 uses interval variables and initialization to perform the same operation as CODE EXAMPLE 1-1.


CODE EXAMPLE 1-2 Hello Interval World With interval Variables

math% cat ce1-2.cc
 
#include <suninterval.h>
 
#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif
 
int main() {
    interval<double> X("[2,3]");
    interval<double> Y("3");  // interval [2,4] is represented
    cout <<"[2,3]+[2,4]=" << X + Y;
    cout << endl;
}
 
 
math% CC  -xia -o ce1-2 ce1-2.cc
math% ce1-2
[2,3]+[2,4]=[0.4000000000000000E+001,0.7000000000000000E+001]
 

Variables X and Y are declared to be of type interval<double> variables and are initialized to [2, 3] and [2, 4], respectively. The standard output stream is used to print the labeled interval sum of X and Y.



Note - To facilitate code-example readability, all interval variables are shown as uppercase characters. Interval variables can be uppercase or lowercase in code.



1.3.4 interval Input/Output

Full support for reading and writing intervals is provided. Because reading and interactively entering interval data can be tedious, a single-number interval format is introduced. The single-number convention is that any number not contained in brackets is interpreted as an interval whose lower and upper bounds are constructed by subtracting and adding 1 unit to the last displayed digit.

Thus

2.345 = [2.344, 2.346],

2.34500 = [2.34499, 2.34501],

and

23 = [22, 24].

Symbolically,

[2.34499, 2.34501] = 2.34500 + [-1, +1]uld

where [-1, +1]uld means that the interval [-1, +1] is added to the last digit of the preceding number. The subscript, uld, is a mnemonic for "unit in the last digit."

To represent a degenerate interval, a single number can be enclosed in square brackets. For example,

[2.345] = [2.345, 2.345] = 2.345000000000.....

This convention is used both for input and constructing intervals out of an external character string representation. Thus, type [0.1] to indicate the input value is an exact decimal number, even though 0.1 is not machine representable.

During input to a program, [0.1,0.1] = [0.1] represents the point, 0.1, while using single-number input/output, 0.1 represents the interval

0.1 + [-1, +1]uld = [0, 0.2].

The input conversion process constructs a sharp interval that contains the input decimal value. If the value is machine representable, the internal machine approximation is degenerate. If the value is not machine representable, an interval having width of 1-ulp (unit-in-the-last-place of the mantissa) is constructed.



Note - A uld and an ulp are different. A uld is a unit in the last displayed decimal digit of an external number. An ulp is the smallest possible increment or decrement that can be made to an internal machine number.



The simplest way to read and print interval data items is with standard stream input and output.

CODE EXAMPLE 1-3 is a simple tool to help users become familiar with interval arithmetic and single-number interval input/output using streams.



Note - The interval containment constraint requires that directed rounding be used during both input and output. With single-number input followed immediately by single-number output, a decimal digit of accuracy can appear to be lost. In fact, the width of the input interval is increased by at most 1-ulp, when the input value is not machine representable. See Section 1.3.5, Single-Number Input/Output and CODE EXAMPLE 1-6.




CODE EXAMPLE 1-3 Interval Input/Output

math% cat ce1-3.cc
#include <suninterval.h>
 
#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif
 
int main() {
    interval <double> X, Y;
    cout << "Press Control/C to terminate!"<< endl;
    cout <<" X,Y=?";
    cin >>X >>Y;
 
    for (;;){
        cout <<endl <<"For X =" <<X <<endl<<", and Y=" <<Y <<endl;
 
        cout <<"X+Y=" << (X+Y) <<endl;
 
        cout <<"X-Y=" << (X-Y) <<endl;
 
        cout <<"X*Y=" << (X*Y) <<endl;
 
        cout <<"X/Y=" << (X/Y) <<endl;
 
        cout <<"pow(X,Y)=" << pow(X,Y) <<endl;
                            
        cout <<" X,Y=?";
 
        cin >>X>>Y;
    }
}
 
math% CC ce1-3.cc -xia -o ce1-3
math% ce1-3
Press Control/C to terminate!
 X,Y=?[1,2][3,4]
For X =[0.1000000000000000E+001,0.2000000000000000E+001]
, and Y=[0.3000000000000000E+001,0.4000000000000000E+001]
X+Y=[0.4000000000000000E+001,0.6000000000000000E+001]
X-Y=[-.3000000000000000E+001,-.1000000000000000E+001]
X*Y=[0.3000000000000000E+001,0.8000000000000000E+001]
X/Y=[0.2500000000000000E+000,0.6666666666666668E+000]
pow(X,Y)=[0.1000000000000000E+001,0.1600000000000000E+002]
 X,Y=?[1,2] -inf
For X =[0.1000000000000000E+001,0.2000000000000000E+001]
, and Y=[              -Infinity,-.1797693134862315E+309]
X+Y=[              -Infinity,-.1797693134862315E+309]
X-Y=[0.1797693134862315E+309,               Infinity]
X*Y=[              -Infinity,-.1797693134862315E+309]
X/Y=[-.1112536929253602E-307,0.0000000000000000E+000]
pow(X,Y)=[0.0000000000000000E+000,               Infinity]
 X,Y=? ^c
 

1.3.5 Single-Number Input/Output

One of the most frustrating aspects of reading interval output is comparing interval infima and suprema to count the number of digits that agree. For example, CODE EXAMPLE 1-4 and CODE EXAMPLE 1-5 shows the interval output of a program that generates different random-width interval data.



Note - Only program output is shown in CODE EXAMPLE 1-4 and CODE EXAMPLE 1-5. The code that generates the output is included with the code examples located at http://developer.sun.com/prodtech/cc/reference/codesamples/




CODE EXAMPLE 1-4 [inf, sup] Interval Output

math%  a.out
Press Control/C to terminate!
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: 5 4 0
 
5 intervals, output mode [inf,sup], KIND = 4:
[-.22382161E-001,0.88642842E+000]
[-.14125850E+000,0.69100440E+000]
[-.19697744E+000,0.60414422E+000]
[-.35070375E+000,0.29852561E+000]
[-.50582356E+000,0.84647579E+000]
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: 5 8 0
 
5 intervals, output mode [inf,sup], KIND = 8:
[-.2564517726079477E+000,0.9827522631010304E+000]
[-.2525155427945818E+000,0.3510597363485733E+000]
[-.3133963062586074E+000,0.6036160987815685E+000]
[-.4608920508962374E+000,0.9438903393544678E+000]
[-.7237777863955990E-001,0.5919545024378117E+000]
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: 5 16 0
 
5 intervals, output mode [inf,sup], KIND = 16:
[-.7372694179875272420263966037179573E-0001,0.8914952196721550592428684467449785
E+0000]
[-.5003665785136456882479176712464738E+0000,0.9596355623810595147915591951459647
E+0000]
[0.5034039683817009896795857135003379E-0002,0.6697658316807206801968277432024479
E+0000]
[-.2131331913859165562121330770531887E+0000,0.8440084600454227370391890872269869
E+0000]
[-.1771294604939292809903937013979606E+0000,0.9135081692043627299426589161157609
E+0000]
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: ?<Control-C>
 

Compare the output readability in CODE EXAMPLE 1-4 with CODE EXAMPLE 1-5.


CODE EXAMPLE 1-5 Single-Number Output

math%: a.out
Press Control/C to terminate!
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: 5 4 1
 
5 intervals, output mode SINGLE NUMBER, KIND = 4:
[-.2239E-001,0.8865     ]
[-0.1413     ,0.6911     ]
[-0.1970     ,0.6042     ]
[-0.3508     ,0.2986     ]
[-0.5059     ,0.8465     ]
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: 5 8 1
5 intervals, output mode SINGLE NUMBER, KIND = 8:
[-0.25646     ,0.98276     ]
[-0.25252     ,0.35106     ]
[-0.31340     ,0.60362     ]
[-0.46090     ,0.94390     ]
[-.72378E-001,0.59196     ]
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: 5 16 1
 
5 intervals, output mode SINGLE NUMBER, KIND = 16:
[-0.737269418E-001, 0.891495220     ]
[ -0.500366579     , 0.959635563     ]
[ 0.503403968E-002, 0.669765832     ]
[ -0.213133192     , 0.844008461     ]
[ -0.177129461     , 0.913508170     ]
 
Enter number of intervals (less then 10), then 4 - for float,8 - for double, or 
16 - for long double, and then 0 for [inf,sup] output and 1 for single-number 
output: ?<Control-C>
 

In the single-number display format, trailing zeros are significant. See Section 2.8, Input and Output for more information.

Intervals can always be entered and displayed using the traditional [inf, sup] display format. In addition, a single number in square brackets denotes a point. For example, on input, [0.1] is interpreted as the number 1/10. To guarantee containment, directed rounding is used to construct an internal approximation that is known to contain the number 1/10.


CODE EXAMPLE 1-6 Character Input With Internal Data Conversion

math% cat ce1-6.cc
#include <suninterval.h>
 
#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif
 
int main() {
    char BUFFER[128];
    cout << "Press Control/C to terminate!"<< endl;
    cout << "X=?";
    cin >>BUFFER;
    for(;;) {
        interval<double> X(BUFFER);
        cout << endl << "Your input was:" <<BUFFER << endl; 
        cout << "Resulting stored interval is:" << endl << X << endl;
        cout << "Single number interval output is: ";
        single_number_output(X, cout);
        cout <<endl <<"X=?" ; 
        cin >>BUFFER;
    }
}
math% CC -xia ce1-6.cc -o ce1-6
math% ce1-6
Press Control/C to terminate!
X=?1.37
 
Your input was:1.37
Resulting stored interval is:
[0.1359999999999999E+001,0.1380000000000001E+001]
Single number interval output is:               0.13   E+001 
X=?1.444
 
Your input was:1.444
Resulting stored interval is:
[0.1442999999999999E+001,0.1445000000000001E+001]
Single number interval output is:               0.144  E+001 
X=? ^c
 

CODE EXAMPLE 1-6 notes:



Note - The empty interval is supported in the interval class. The empty interval can be entered as [empty]. Infinite interval endpoints are also supported, as described in Section 1.3.2, interval External Representations.



1.3.6 Arithmetic Expressions

Writing arithmetic expressions that contain interval data items is simple and straightforward. Except for interval-specific functions and constructors, interval expressions look like floating-point arithmetic expressions, such as in CODE EXAMPLE 1-7.


CODE EXAMPLE 1-7 Simple interval Expression Example

math% cat ce1-7.cc
#include <suninterval.h>
 
#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif
 
int main() {
    interval <double> X1("[0.1]");
    interval <double> N(3);
    interval <double> A (5.0);
    interval <double> X = X1 * A / N;
    cout << "[0.1]*[A]/[N]=" <<X <<endl;
}
math% CC -xia -o ce1-7 ce1-7.cc
math% ce1-7
[0.1]*[A]/[N]=[0.1666666666666666E+000,0.1666666666666668E+000]
 



Note - Not all mathematically equivalent interval expressions produce intervals having the same width. Additionally, it is often not possible to compute a sharp result by simply evaluating a single interval expression. In general, interval result width depends on the value of interval arguments and the form of the expression.



1.3.7 interval-Specific Functions

A variety of interval-specific functions are provided. See Section 2.9.4, Functions That Accept Interval Arguments. Use CODE EXAMPLE 1-8 to explore how specific interval functions behave.


CODE EXAMPLE 1-8 interval -Specific Functions

math% cat ce1-8.cc
#include <suninterval.h>
 
#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif
 
int main() {
    interval <double> X;
    cout << "Press Control/C to terminate!"<< endl;
    cout <<"X=?";
    cin >>X;
    for(;;){
        cout <<endl << "For X =" <<X << endl;
        cout <<"mid(X)=" << (mid(X)) <<endl;
        cout <<"mig(X)=" << (mig(X)) <<endl;
        cout <<"mag(X)=" << (mag(X)) <<endl;
        cout <<"wid(X)=" << (wid(X)) <<endl;
        cout <<"X=?";
        cin >>X;
    }
}
 
math% CC  -xia -o ce1-8 ce1-8.cc
math% ce1-8
Press Control/C to terminate!
X=? [1.23456,1.234567890]
For X =[0.1234559999999999E+001,0.1234567890000001E+001]
mid(X)=1.23456
mig(X)=1.23456
mag(X)=1.23457
wid(X)=7.89e-06
X=? [1,10]
For X =[0.1000000000000000E+001,0.1000000000000000E+002]
mid(X)=5.5
mig(X)=1
mag(X)=10
wid(X)=9
X=? ^c
 

1.3.8 Interval Versions of Standard Functions

Use CODE EXAMPLE 1-9 to explore how some standard mathematical functions behave.


CODE EXAMPLE 1-9 interval Versions of Mathematical Functions

math% cat ce1-9.cc
#include <suninterval.h>
 
#if __cplusplus >= 199711
using namespace SUNW_interval;
#endif
 
int main() {
    interval <double> X;
    cout << "Press Control/C to terminate!"<< endl;
    cout <<"X=?";
    cin >>X;
 
    for (;;) {
        cout <<endl << "For X =" <<X << endl;
 
        cout <<"abs(X)=" << (fabs(X)) <<endl;
 
        cout <<"log(X)=" << (log(X)) <<endl;
 
        cout <<"sqrt(X)=" << (sqrt(X)) <<endl;
 
        cout <<"sin(X)=" << (sin(X)) <<endl;
 
        cout <<"acos(X)=" << (acos(X)) <<endl;
 
        cout <<"X=?";
        cin >>X;
    }
}
math% CC  -xia -o ce1-9 ce1-9.cc
math% ce1-9
Press Control/C to terminate!
X=? [1.1,1.2]
For X =[0.1099999999999999E+001,0.1200000000000001E+001]
abs(X)=[0.1099999999999999E+001,0.1200000000000001E+001]
log(X)=[0.9531017980432472E-001,0.1823215567939548E+000]
sqrt(X)=[0.1048808848170151E+001,0.1095445115010333E+001]
sin(X)=[0.8912073600614351E+000,0.9320390859672266E+000]
acos(X)=[EMPTY                                          ]
X=? [-0.5,0.5]
For X =[-.5000000000000000E+000,0.5000000000000000E+000]
abs(X)=[0.0000000000000000E+000,0.5000000000000000E+000]
log(X)=[              -Infinity,-.6931471805599452E+000]
sqrt(X)=[0.0000000000000000E+000,0.7071067811865476E+000]
sin(X)=[-.4794255386042031E+000,0.4794255386042031E+000]
acos(X)=[0.1047197551196597E+001,0.2094395102393196E+001]
X=? ^c
 


1.4 Code Development Tools

Information on interval code development tools is available online. See the Interval Arithmetic Readme for a list of interval web sites and other online resources.

To report a suspected interval error, send email to the following address:

sun-dp-comments@Sun.COM

Include the following text in the Subject line of the email message:

FORTEDEV "7.0 mm/dd/yy" Interval

where mm/dd/yy is the month, day, and year of the message.

1.4.1 Debugging Support

In Sun Studio, interval data types are supported by dbx to the following extent:

For additional details on dbx functionality, see Debugging a Program With dbx.