home *** CD-ROM | disk | FTP | other *** search
- From decwrl!sun-barr!cs.utexas.edu!uunet!allbery Sat Oct 28 16:26:05 PDT 1989
- Article 1145 of comp.sources.misc:
- Path: decwrl!sun-barr!cs.utexas.edu!uunet!allbery
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Newsgroups: comp.sources.misc
- Subject: v08i098: Interval Arithmetic in C++
- Message-ID: <70936@uunet.UU.NET>
- Date: 28 Oct 89 18:14:26 GMT
- Sender: allbery@uunet.UU.NET
- Reply-To: @uunet.uu.net:Dan.McCue%newcastle.ac.uk@nsfnet-relay.ac.uk
- Lines: 413
- Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 8, Issue 98
- Submitted-by: @uunet.uu.net:Dan.McCue%newcastle.ac.uk@nsfnet-relay.ac.uk
- Archive-name: interval.c++
-
- Enclosed is a shar archive for a simple interval
- arithmetic package written in C++. There is no
- restriction on use or re-distribution. Comments and
- improvements may be addressed to:
- From U.K.: Dan.McCue@uk.ac.newcastle
- Elsewhere: Dan.McCue@newcastle.ac.uk
- ------------------------ cut here ----------------------------
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # Makefile
- # README
- # Tinterval.c
- # interval.c
- # interval.h
- # This archive created: Thu Aug 24 13:13:29 1989
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'Makefile'" '(715 characters)'
- if test -f 'Makefile'
- then
- echo shar: "will not over-write existing file 'Makefile'"
- else
- cat << \SHAR_EOF > 'Makefile'
- HDRS = interval.h
- CC = CC
- LINKER = CC
- MAKEFILE = Makefile
- OBJS = Tinterval.o \
- interval.o
- PRINT = pr
- PROGRAM = Tinterval
- SRCS = Tinterval.c \
- interval.c
-
- all: $(PROGRAM)
-
- $(PROGRAM): $(OBJS) $(LIBS)
- @echo -n "Linking $(PROGRAM) ... "
- @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
- @echo "done"
-
- clean:; @rm -f $(OBJS) core a.out
-
- depend:; @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
-
- index:; @ctags -wx $(HDRS) $(SRCS)
-
- print:; @$(PRINT) $(HDRS) $(SRCS)
-
- tags: $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
-
- ###
- Tinterval.o: /usr/include/CC/stdio.h /usr/include/CC/string.h interval.h
- interval.o: /usr/include/CC/stdio.h interval.h
- SHAR_EOF
- if test 715 -ne "`wc -c < 'Makefile'`"
- then
- echo shar: "error transmitting 'Makefile'" '(should have been 715 characters)'
- fi
- fi
- echo shar: "extracting 'README'" '(498 characters)'
- if test -f 'README'
- then
- echo shar: "will not over-write existing file 'README'"
- else
- cat << \SHAR_EOF > 'README'
- This is a simple implementation of an interval
- arithmetic package I wrote while trying to learn C++.
- The accuracy is dubious (since proper attention has not
- been paid to rounding) and there is no attempt to recover
- from errors. The result is not too robust, but fun, useful
- and (in my case), instructive.
- Be sure to modify the makefile to use your c++ compiler.
- You may also need to change the pathnames of include files
- (e.g., <CC/stdio.h>) in interval.c and Tinterval.c for your
- system.
- SHAR_EOF
- if test 498 -ne "`wc -c < 'README'`"
- then
- echo shar: "error transmitting 'README'" '(should have been 498 characters)'
- fi
- fi
- echo shar: "extracting 'Tinterval.c'" '(1020 characters)'
- if test -f 'Tinterval.c'
- then
- echo shar: "will not over-write existing file 'Tinterval.c'"
- else
- cat << \SHAR_EOF > 'Tinterval.c'
- // A simple test program for the interval class
-
- #include <CC/stdio.h>
- #include <CC/string.h>
- #include "interval.h"
-
- void Usage(char *name)
- {
- fprintf(stderr, "usage: %s real real +|-|*|/ real real\n", name);
- }
-
- main(int argc, char **argv)
- {
- float a,b,c,d;
-
- if (argc != 6) {
- Usage(argv[0]);
- exit(1);
- }
-
- a = atof(argv[1]);
- b = atof(argv[2]);
- c = atof(argv[4]);
- d = atof(argv[5]);
- {
- interval I1(a,b);
- interval I2(c,d);
- interval Result, Result2;
-
- switch (argv[3][0]) {
- case '+': Result = I1 + I2; break;
- case '-': Result = I1 - I2; break;
- case '*': Result = I1 * I2; break;
- case '/': Result = I1 / I2; break;
- default:
- Usage(argv[0]);
- exit(2);
- }
-
- printf("[%f, %f] %s [%f, %f] == [%f, %f]\n",
- I1.lo(), I1.hi(), argv[3], I2.lo(), I2.hi(),
- Result.lo(), Result.hi());
-
- // Now check out += and integer-to-interval conversion
- Result2 = Result;
- Result2 += 4;
- printf("[%f, %f] + 4 == [%f, %f]\n",
- Result.lo(), Result.hi(), Result2.lo(), Result2.hi());
- }
- }
- SHAR_EOF
- if test 1020 -ne "`wc -c < 'Tinterval.c'`"
- then
- echo shar: "error transmitting 'Tinterval.c'" '(should have been 1020 characters)'
- fi
- fi
- echo shar: "extracting 'interval.c'" '(4825 characters)'
- if test -f 'interval.c'
- then
- echo shar: "will not over-write existing file 'interval.c'"
- else
- cat << \SHAR_EOF > 'interval.c'
- // This software is in the public domain.
- // Permission is granted to use this software for any
- // purpose commercial or non-commercial.
- // The implementer/distributer assume no liability for
- // any damages, incidental, consequential or otherwise,
- // arising from the use of this software.
-
- // Implementation of class interval
- //
- // Most operators are trivial and could be inlined.
- //
- // Multiply is more interesting. The complicated testing
- // may be more time consuming than the floating-point
- // operations it attempts to avoid.
- // How could this testing be streamlined?
- //
- // Note that divide blurts out error/warning messages using fprintf :-(
- // Strictly speaking, division is undefined if the divisor interval
- // contains zero. This code is sloppy in allowing it, but it warns.
- //
- // No attempt is made to control rounding so accuracy is dubious.
- //
- // No attempt is made to detect/recover from overflow or underflow.
- // This is a serious deficiency. Is there a 'portable' around it?
-
- #include <CC/stdio.h>
- #include "interval.h"
-
- interval interval::operator+(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp += I;
- }
-
- interval interval::operator-(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp -= I;
- }
-
- interval interval::operator*(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp *= I;
- }
-
- interval interval::operator/(interval I)
- {
- interval temp(lo_bound, hi_bound);
- return temp /= I;
- }
-
- interval &interval::operator+=(interval I)
- {
- lo_bound += I.lo_bound;
- hi_bound += I.hi_bound;
- return *this;
- }
-
- interval &interval::operator-=(interval I)
- {
- lo_bound -= I.lo_bound;
- hi_bound -= I.hi_bound;
- return *this;
- }
-
- // Multiply is a bit complicated.
- // A naive version simply takes the minimum of all combinations
- // as the new lo_bound and the maximum as the new hi_bound.
- // But this involves four double precision floating multiples.
- // A quick examination of the signs of the intervals reveals
- // that there are nine possible cases of which only one
- // requires all four multiplications. The other cases only
- // require two multiplications. We assume that it is faster to
- // compute and dispatch to the right case than to perform
- // the extra multiplies. If not, use the naive scheme.
- //
- // The cases can be described as follows:
- // Each interval is either non-negative (lo bound >= 0),
- // non-positive (hi bound <= 0), or crosses(includes) zero,
- // including some numbers on either side.
- // If we label the intervals, A and B, corresponding to
- // "this" and "I", we get the following matrix:
- //
- // Bcross Bnonneg Bnonpos
- //
- // Across
- //
- // Anonneg
- //
- // Anonpos
-
- interval &interval::operator*=(interval I)
- {
- enum possibility {
- AcrossBcross, AcrossBnn, AcrossBnp,
- AnnBcross, AnnBnn, AnnBnp,
- AnpBcross, AnpBnn, AnpBnp
- } choice;
-
- if (lo_bound >= 0.0) choice = AnnBcross;
- else if (hi_bound <= 0.0) choice = AnpBcross;
- else choice = AcrossBcross;
-
- if (I.lo_bound >= 0.0) choice += 1;
- else if (I.hi_bound <= 0.0) choice += 2;
-
- switch (choice)
- {
- case AcrossBcross: {
- double HL = hi_bound*I.lo_bound,
- HH = hi_bound*I.hi_bound,
- LL = lo_bound*I.lo_bound,
- LH = lo_bound*I.hi_bound;
- lo_bound = HL<LH?HL:LH;
- hi_bound = LL>HH?LL:HH;
- }
- break;
-
- case AcrossBnn:
- lo_bound *= I.hi_bound;
- hi_bound *= I.hi_bound;
- break;
-
- case AcrossBnp: {
- double new_hi_bound = lo_bound * I.lo_bound;
-
- lo_bound = hi_bound*I.lo_bound;
- hi_bound = new_hi_bound;
- }
- break;
-
- case AnnBcross:
- lo_bound = hi_bound*I.lo_bound;
- hi_bound *= I.hi_bound;
- break;
-
- case AnnBnn:
- lo_bound *= I.lo_bound;
- hi_bound *= I.hi_bound;
- break;
-
- case AnnBnp: {
- double new_hi_bound = lo_bound * I.hi_bound;
-
- lo_bound = hi_bound*I.lo_bound;
- hi_bound = new_hi_bound;
- }
- break;
-
- case AnpBcross:
- hi_bound = lo_bound*I.lo_bound;
- lo_bound *= I.hi_bound;
- break;
-
- case AnpBnn:
- lo_bound *= I.hi_bound;
- hi_bound *= I.lo_bound;
- break;
-
- case AnpBnp: {
- double new_hi_bound = lo_bound * I.lo_bound;
-
- lo_bound = hi_bound*I.hi_bound;
- hi_bound = new_hi_bound;
- }
- break;
-
- default:
- fprintf(stderr,
- "Bad interval (low bound > hi bound) [%f, %f] * [%f, %f]\n",
- lo_bound, hi_bound, I.lo_bound, I.hi_bound);
- lo_bound = hi_bound = 0.0;
- break;
- }
-
- return *this;
- }
-
- interval &interval::operator/=(interval I)
- {
- if (I.lo_bound == 0.0 && I.hi_bound == 0)
- fprintf(stderr, "Error: Division by zero attempted - [%f,%f]/[f,%f]\n",
- lo_bound, hi_bound, I.lo_bound, I.hi_bound);
- else {
- if (I.lo_bound < 0 && I.hi_bound > 0)
- fprintf(stderr, "Warning: Division by zero possible - [%f,%f]/[%f,%f]\n",
- lo_bound, hi_bound, I.lo_bound, I.hi_bound);
- interval inv(1.0/I.lo_bound, 1.0/I.hi_bound);
- return inv *= *this;
- }
- }
- SHAR_EOF
- if test 4825 -ne "`wc -c < 'interval.c'`"
- then
- echo shar: "error transmitting 'interval.c'" '(should have been 4825 characters)'
- fi
- fi
- echo shar: "extracting 'interval.h'" '(1684 characters)'
- if test -f 'interval.h'
- then
- echo shar: "will not over-write existing file 'interval.h'"
- else
- cat << \SHAR_EOF > 'interval.h'
- // Class interval
- // A definition of intervals for interval arithmetic.
- //
- // The representation of the interval is two doubles
- // but conversion operators are defined for int and float.
- //
- // Error handling is weak. In an IEEE compliant implementation,
- // quiet NANs could be used to indicate bounds that were
- // invalid. Otherwise, more state (and checking) would
- // need to be added.
-
- // To get the definition of MAXDOUBLE
- #include <values.h>
-
- class interval {
- double lo_bound, hi_bound;
- public:
- double lo(void) { return lo_bound; }
- double hi(void) { return hi_bound; }
- double width(void) { return hi_bound - lo_bound; }
- interval() { lo_bound = -MAXDOUBLE; hi_bound = MAXDOUBLE; }
- interval(double l, double h){ lo_bound = l<h?l:h; hi_bound = l<h?h:l; }
- interval(double f) { lo_bound = f; hi_bound = f; }
- interval(float l, float h) { lo_bound = l<h?l:h; hi_bound = l<h?h:l; }
- interval(float f) { lo_bound = f; hi_bound = f; }
- interval(int l, int h) { lo_bound = l<h?l:h; hi_bound = l<h?h:l; }
- interval(int i) { lo_bound = i; hi_bound = i; }
- interval operator+(interval I);
- interval operator-(interval I);
- interval operator*(interval I);
- interval operator/(interval I);
- interval &operator+=(interval I);
- interval &operator-=(interval I);
- interval &operator*=(interval I);
- interval &operator/=(interval I);
- int contains(interval I) { return lo_bound <= I.lo_bound &&
- hi_bound >= I.hi_bound; }
- int overlaps(interval I) { return lo_bound <= I.hi_bound &&
- hi_bound >= I.lo_bound; }
- int equal(interval I) { return lo_bound == I.lo_bound &&
- hi_bound == I.hi_bound; }
- };
- SHAR_EOF
- if test 1684 -ne "`wc -c < 'interval.h'`"
- then
- echo shar: "error transmitting 'interval.h'" '(should have been 1684 characters)'
- fi
- fi
- exit 0
- # End of shell archive
- #
- #
- #
-
-
-