home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume8 / interval.c++ < prev    next >
C/C++ Source or Header  |  1989-10-28  |  11KB  |  421 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v08i098: Interval Arithmetic in C++
  3. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  4. Reply-To: @uunet.uu.net:Dan.McCue%newcastle.ac.uk@nsfnet-relay.ac.uk
  5.  
  6. Posting-number: Volume 8, Issue 98
  7. Submitted-by: @uunet.uu.net:Dan.McCue%newcastle.ac.uk@nsfnet-relay.ac.uk
  8. Archive-name: interval.c++
  9.  
  10.     Enclosed is a shar archive for a simple interval
  11. arithmetic package written in C++.  There is no
  12. restriction on use or re-distribution.  Comments and
  13. improvements may be addressed to:
  14.   From U.K.: Dan.McCue@uk.ac.newcastle
  15.   Elsewhere: Dan.McCue@newcastle.ac.uk
  16. ------------------------ cut here ----------------------------
  17. #! /bin/sh
  18. # This is a shell archive, meaning:
  19. # 1. Remove everything above the #! /bin/sh line.
  20. # 2. Save the resulting text in a file.
  21. # 3. Execute the file with /bin/sh (not csh) to create:
  22. #    Makefile
  23. #    README
  24. #    Tinterval.c
  25. #    interval.c
  26. #    interval.h
  27. # This archive created: Thu Aug 24 13:13:29 1989
  28. export PATH; PATH=/bin:/usr/bin:$PATH
  29. echo shar: "extracting 'Makefile'" '(715 characters)'
  30. if test -f 'Makefile'
  31. then
  32.     echo shar: "will not over-write existing file 'Makefile'"
  33. else
  34. cat << \SHAR_EOF > 'Makefile'
  35. HDRS          = interval.h
  36. CC          = CC
  37. LINKER          = CC
  38. MAKEFILE      = Makefile
  39. OBJS          = Tinterval.o \
  40.         interval.o
  41. PRINT          = pr
  42. PROGRAM          = Tinterval
  43. SRCS          = Tinterval.c \
  44.         interval.c
  45.  
  46. all:        $(PROGRAM)
  47.  
  48. $(PROGRAM):     $(OBJS) $(LIBS)
  49.         @echo -n "Linking $(PROGRAM) ... "
  50.         @$(LINKER) $(LDFLAGS) $(OBJS) $(LIBS) -o $(PROGRAM)
  51.         @echo "done"
  52.  
  53. clean:;        @rm -f $(OBJS) core a.out
  54.  
  55. depend:;    @mkmf -f $(MAKEFILE) PROGRAM=$(PROGRAM) DEST=$(DEST)
  56.  
  57. index:;        @ctags -wx $(HDRS) $(SRCS)
  58.  
  59. print:;        @$(PRINT) $(HDRS) $(SRCS)
  60.  
  61. tags:           $(HDRS) $(SRCS); @ctags $(HDRS) $(SRCS)
  62.  
  63. ###
  64. Tinterval.o: /usr/include/CC/stdio.h /usr/include/CC/string.h interval.h
  65. interval.o: /usr/include/CC/stdio.h interval.h
  66. SHAR_EOF
  67. if test 715 -ne "`wc -c < 'Makefile'`"
  68. then
  69.     echo shar: "error transmitting 'Makefile'" '(should have been 715 characters)'
  70. fi
  71. fi
  72. echo shar: "extracting 'README'" '(498 characters)'
  73. if test -f 'README'
  74. then
  75.     echo shar: "will not over-write existing file 'README'"
  76. else
  77. cat << \SHAR_EOF > 'README'
  78.     This is a simple implementation of an interval
  79. arithmetic package I wrote while trying to learn C++.
  80. The accuracy is dubious (since proper attention has not
  81. been paid to rounding) and there is no attempt to recover
  82. from errors.  The result is not too robust, but fun, useful
  83. and (in my case), instructive.
  84.     Be sure to modify the makefile to use your c++ compiler.
  85. You may also need to change the pathnames of include files
  86. (e.g., <CC/stdio.h>) in interval.c and Tinterval.c for your
  87. system.
  88. SHAR_EOF
  89. if test 498 -ne "`wc -c < 'README'`"
  90. then
  91.     echo shar: "error transmitting 'README'" '(should have been 498 characters)'
  92. fi
  93. fi
  94. echo shar: "extracting 'Tinterval.c'" '(1020 characters)'
  95. if test -f 'Tinterval.c'
  96. then
  97.     echo shar: "will not over-write existing file 'Tinterval.c'"
  98. else
  99. cat << \SHAR_EOF > 'Tinterval.c'
  100. // A simple test program for the interval class
  101.  
  102. #include <CC/stdio.h>
  103. #include <CC/string.h>
  104. #include "interval.h"
  105.  
  106. void Usage(char *name)
  107. {
  108.     fprintf(stderr, "usage: %s real real +|-|*|/ real real\n", name);
  109. }
  110.  
  111. main(int argc, char **argv)
  112. {
  113.     float a,b,c,d;
  114.  
  115.     if (argc != 6) {
  116.     Usage(argv[0]);
  117.     exit(1);
  118.     }
  119.  
  120.     a = atof(argv[1]);
  121.     b = atof(argv[2]);
  122.     c = atof(argv[4]);
  123.     d = atof(argv[5]);
  124.     {
  125.     interval I1(a,b);
  126.     interval I2(c,d);
  127.     interval Result, Result2;
  128.  
  129.     switch (argv[3][0]) {
  130.     case '+': Result = I1 + I2; break;
  131.     case '-': Result = I1 - I2; break;
  132.     case '*': Result = I1 * I2; break;
  133.     case '/': Result = I1 / I2; break;
  134.     default: 
  135.         Usage(argv[0]);
  136.         exit(2);
  137.     }
  138.  
  139.     printf("[%f, %f] %s [%f, %f] == [%f, %f]\n", 
  140.         I1.lo(), I1.hi(), argv[3], I2.lo(), I2.hi(), 
  141.         Result.lo(), Result.hi());
  142.  
  143.     // Now check out += and integer-to-interval conversion
  144.     Result2 = Result;
  145.     Result2 += 4;
  146.     printf("[%f, %f] + 4 == [%f, %f]\n", 
  147.         Result.lo(), Result.hi(), Result2.lo(), Result2.hi());
  148.     }
  149. }
  150. SHAR_EOF
  151. if test 1020 -ne "`wc -c < 'Tinterval.c'`"
  152. then
  153.     echo shar: "error transmitting 'Tinterval.c'" '(should have been 1020 characters)'
  154. fi
  155. fi
  156. echo shar: "extracting 'interval.c'" '(4825 characters)'
  157. if test -f 'interval.c'
  158. then
  159.     echo shar: "will not over-write existing file 'interval.c'"
  160. else
  161. cat << \SHAR_EOF > 'interval.c'
  162. // This software is in the public domain.
  163. // Permission is granted to use this software for any
  164. // purpose commercial or non-commercial.
  165. // The implementer/distributer assume no liability for
  166. // any damages, incidental, consequential or otherwise,
  167. // arising from the use of this software.
  168.  
  169. // Implementation of class interval
  170. //
  171. // Most operators are trivial and could be inlined.
  172. //
  173. // Multiply is more interesting.  The complicated testing
  174. // may be more time consuming than the floating-point
  175. // operations it attempts to avoid.
  176. // How could this testing be streamlined?
  177. //
  178. // Note that divide blurts out error/warning messages using fprintf :-(
  179. // Strictly speaking, division is undefined if the divisor interval
  180. // contains zero.  This code is sloppy in allowing it, but it warns.
  181. //
  182. // No attempt is made to control rounding so accuracy is dubious.
  183. //
  184. // No attempt is made to detect/recover from overflow or underflow.
  185. // This is a serious deficiency.  Is there a 'portable' around it?
  186.  
  187. #include <CC/stdio.h>
  188. #include "interval.h"
  189.  
  190. interval interval::operator+(interval I)
  191. {
  192.     interval temp(lo_bound, hi_bound);
  193.     return temp += I;
  194. }
  195.  
  196. interval interval::operator-(interval I)
  197. {
  198.     interval temp(lo_bound, hi_bound);
  199.     return temp -= I;
  200. }
  201.  
  202. interval interval::operator*(interval I)
  203. {
  204.     interval temp(lo_bound, hi_bound);
  205.     return temp *= I;
  206. }
  207.  
  208. interval interval::operator/(interval I)
  209. {
  210.     interval temp(lo_bound, hi_bound);
  211.     return temp /= I;
  212. }
  213.  
  214. interval &interval::operator+=(interval I)
  215. {
  216.     lo_bound += I.lo_bound;
  217.     hi_bound += I.hi_bound;
  218.     return *this;
  219. }
  220.  
  221. interval &interval::operator-=(interval I)
  222. {
  223.     lo_bound -= I.lo_bound;
  224.     hi_bound -= I.hi_bound;
  225.     return *this;
  226. }
  227.  
  228. // Multiply is a bit complicated.
  229. // A naive version simply takes the minimum of all combinations
  230. // as the new lo_bound and the maximum as the new hi_bound.
  231. // But this involves four double precision floating multiples.
  232. // A quick examination of the signs of the intervals reveals
  233. // that there are nine possible cases of which only one
  234. // requires all four multiplications.  The other cases only
  235. // require two multiplications.  We assume that it is faster to
  236. // compute and dispatch to the right case than to perform
  237. // the extra multiplies.  If not, use the naive scheme.
  238. //
  239. // The cases can be described as follows:
  240. // Each interval is either non-negative (lo bound >= 0),
  241. // non-positive (hi bound <= 0), or crosses(includes) zero,
  242. // including some numbers on either side.
  243. // If we label the intervals, A and B, corresponding to
  244. // "this" and "I", we get the following matrix:
  245. //
  246. //        Bcross        Bnonneg        Bnonpos
  247. //
  248. //    Across
  249. //
  250. //    Anonneg
  251. //
  252. //    Anonpos
  253.  
  254. interval &interval::operator*=(interval I)
  255. {
  256.     enum possibility {
  257.     AcrossBcross, AcrossBnn, AcrossBnp,
  258.     AnnBcross, AnnBnn, AnnBnp,
  259.     AnpBcross, AnpBnn, AnpBnp
  260.     } choice;
  261.  
  262.     if (lo_bound >= 0.0) choice = AnnBcross;
  263.     else if (hi_bound <= 0.0) choice = AnpBcross;
  264.     else choice = AcrossBcross;
  265.  
  266.     if (I.lo_bound >= 0.0) choice += 1;
  267.     else if (I.hi_bound <= 0.0) choice += 2;
  268.  
  269.     switch (choice)
  270.     {
  271.     case AcrossBcross: {
  272.             double  HL = hi_bound*I.lo_bound,
  273.                 HH = hi_bound*I.hi_bound,
  274.                 LL = lo_bound*I.lo_bound,
  275.                 LH = lo_bound*I.hi_bound;
  276.             lo_bound = HL<LH?HL:LH;
  277.             hi_bound = LL>HH?LL:HH;
  278.         }
  279.         break;
  280.  
  281.     case AcrossBnn:
  282.         lo_bound *= I.hi_bound;
  283.         hi_bound *= I.hi_bound;
  284.         break;
  285.  
  286.     case AcrossBnp: {
  287.         double new_hi_bound = lo_bound * I.lo_bound;
  288.  
  289.         lo_bound = hi_bound*I.lo_bound;
  290.         hi_bound = new_hi_bound;
  291.         }
  292.         break;
  293.  
  294.     case AnnBcross:
  295.         lo_bound = hi_bound*I.lo_bound;
  296.         hi_bound *= I.hi_bound;
  297.         break;
  298.  
  299.     case AnnBnn:
  300.         lo_bound *= I.lo_bound;
  301.         hi_bound *= I.hi_bound;
  302.         break;
  303.  
  304.     case AnnBnp: {
  305.         double new_hi_bound = lo_bound * I.hi_bound;
  306.  
  307.         lo_bound = hi_bound*I.lo_bound;
  308.         hi_bound = new_hi_bound;
  309.         }
  310.         break;
  311.  
  312.     case AnpBcross:
  313.         hi_bound = lo_bound*I.lo_bound;
  314.         lo_bound *= I.hi_bound;
  315.         break;
  316.  
  317.     case AnpBnn:
  318.         lo_bound *= I.hi_bound;
  319.         hi_bound *= I.lo_bound;
  320.         break;
  321.  
  322.     case AnpBnp: {
  323.         double new_hi_bound = lo_bound * I.lo_bound;
  324.  
  325.         lo_bound = hi_bound*I.hi_bound;
  326.         hi_bound = new_hi_bound;
  327.         }
  328.         break;
  329.  
  330.     default:
  331.         fprintf(stderr, 
  332.             "Bad interval (low bound > hi bound) [%f, %f] * [%f, %f]\n",
  333.             lo_bound, hi_bound, I.lo_bound, I.hi_bound);
  334.         lo_bound = hi_bound = 0.0;
  335.         break;
  336.     }
  337.  
  338.     return *this;
  339. }
  340.  
  341. interval &interval::operator/=(interval I)
  342. {
  343.     if (I.lo_bound == 0.0 && I.hi_bound == 0)
  344.     fprintf(stderr, "Error: Division by zero attempted - [%f,%f]/[f,%f]\n",
  345.         lo_bound, hi_bound, I.lo_bound, I.hi_bound);
  346.     else {
  347.     if (I.lo_bound < 0 && I.hi_bound > 0)
  348.         fprintf(stderr, "Warning: Division by zero possible - [%f,%f]/[%f,%f]\n",
  349.         lo_bound, hi_bound, I.lo_bound, I.hi_bound);
  350.     interval inv(1.0/I.lo_bound, 1.0/I.hi_bound);
  351.     return inv *= *this;
  352.     }
  353. }
  354. SHAR_EOF
  355. if test 4825 -ne "`wc -c < 'interval.c'`"
  356. then
  357.     echo shar: "error transmitting 'interval.c'" '(should have been 4825 characters)'
  358. fi
  359. fi
  360. echo shar: "extracting 'interval.h'" '(1684 characters)'
  361. if test -f 'interval.h'
  362. then
  363.     echo shar: "will not over-write existing file 'interval.h'"
  364. else
  365. cat << \SHAR_EOF > 'interval.h'
  366. // Class interval
  367. //    A definition of intervals for interval arithmetic.
  368. //
  369. //    The representation of the interval is two doubles
  370. //    but conversion operators are defined for int and float.
  371. //
  372. //    Error handling is weak.  In an IEEE compliant implementation,
  373. //    quiet NANs could be used to indicate bounds that were
  374. //    invalid.  Otherwise, more state (and checking) would
  375. //    need to be added.
  376.  
  377. // To get the definition of MAXDOUBLE
  378. #include <values.h>
  379.  
  380. class interval {
  381.     double lo_bound, hi_bound;
  382. public:
  383.     double lo(void)        { return lo_bound; }
  384.     double hi(void)        { return hi_bound; }
  385.     double width(void)        { return hi_bound - lo_bound; }
  386.     interval()            { lo_bound = -MAXDOUBLE; hi_bound = MAXDOUBLE; }
  387.     interval(double l, double h){ lo_bound = l<h?l:h; hi_bound = l<h?h:l; }
  388.     interval(double f)        { lo_bound = f; hi_bound = f; }
  389.     interval(float l, float h)    { lo_bound = l<h?l:h; hi_bound = l<h?h:l; }
  390.     interval(float f)        { lo_bound = f; hi_bound = f; }
  391.     interval(int l, int h)    { lo_bound = l<h?l:h; hi_bound = l<h?h:l; }
  392.     interval(int i)        { lo_bound = i; hi_bound = i; }
  393.     interval operator+(interval I);
  394.     interval operator-(interval I);
  395.     interval operator*(interval I);
  396.     interval operator/(interval I);
  397.     interval &operator+=(interval I);
  398.     interval &operator-=(interval I);
  399.     interval &operator*=(interval I);
  400.     interval &operator/=(interval I);
  401.     int contains(interval I)    { return lo_bound <= I.lo_bound && 
  402.                      hi_bound >= I.hi_bound; }
  403.     int overlaps(interval I)    { return lo_bound <= I.hi_bound && 
  404.                      hi_bound >= I.lo_bound; }
  405.     int equal(interval I)    { return lo_bound == I.lo_bound && 
  406.                      hi_bound == I.hi_bound; }
  407. };
  408. SHAR_EOF
  409. if test 1684 -ne "`wc -c < 'interval.h'`"
  410. then
  411.     echo shar: "error transmitting 'interval.h'" '(should have been 1684 characters)'
  412. fi
  413. fi
  414. exit 0
  415. #    End of shell archive
  416. #
  417. #
  418. #
  419.  
  420.  
  421.