allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (10/29/89)
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 # # #