メインページ   クラス階層   構成   ファイル一覧   構成メンバ   ファイルメンバ  

Range.cc

解説を見る。
00001 /*
00002 
00003 Copyright (C) 1996, 1997 John W. Eaton
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 2, or (at your option) any
00010 later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, write to the Free
00019 Software Foundation, 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00020 
00021 */
00022 
00023 #if defined (__GNUG__) && defined (USE_PRAGMA_INTERFACE_IMPLEMENTATION)
00024 #pragma implementation
00025 #endif
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030 
00031 #include <cfloat>
00032 #include <climits>
00033 #include <cmath>
00034 
00035 #include <iostream>
00036 
00037 #include "Range.h"
00038 #include "lo-mappers.h"
00039 #include "lo-utils.h"
00040 
00041 bool
00042 Range::all_elements_are_ints (void) const
00043 {
00044   // If the base and increment are ints, the final value in the range
00045   // will also be an integer, even if the limit is not.
00046 
00047   return (! (xisnan (rng_base) || xisnan (rng_inc))
00048           && NINT (rng_base) == rng_base
00049           && NINT (rng_inc) == rng_inc);
00050 }
00051 
00052 Matrix
00053 Range::matrix_value (void) const
00054 {
00055   if (rng_nelem > 0 && cache.rows () == 0)
00056     {
00057       cache.resize (1, rng_nelem);
00058       double b = rng_base;
00059       double increment = rng_inc;
00060       for (int i = 0; i < rng_nelem; i++)
00061         cache(i) = b + i * increment;
00062 
00063       // On some machines (x86 with extended precision floating point
00064       // arithmetic, for example) it is possible that we can overshoot
00065       // the limit by approximately the machine precision even though
00066       // we were very careful in our calculation of the number of
00067       // elements.
00068 
00069       if ((rng_inc > 0 && cache(rng_nelem-1) > rng_limit)
00070           || (rng_inc < 0 && cache(rng_nelem-1) < rng_limit))
00071         cache(rng_nelem-1) = rng_limit;
00072     }
00073 
00074   return cache;
00075 }
00076 
00077 
00078 // NOTE: max and min only return useful values if nelem > 0.
00079 
00080 double
00081 Range::min (void) const
00082 {
00083   double retval = 0.0;
00084   if (rng_nelem > 0)
00085     {
00086       if (rng_inc > 0)
00087         retval = rng_base;
00088       else
00089         {
00090           retval = rng_base + (rng_nelem - 1) * rng_inc;
00091 
00092           // See the note in the matrix_value method above.
00093 
00094           if (retval < rng_limit)
00095             retval = rng_limit;
00096         }
00097 
00098     }
00099   return retval;
00100 }
00101 
00102 double
00103 Range::max (void) const
00104 {
00105   double retval = 0.0;
00106   if (rng_nelem > 0)
00107     {
00108       if (rng_inc > 0)
00109         {
00110           retval = rng_base + (rng_nelem - 1) * rng_inc;
00111 
00112           // See the note in the matrix_value method above.
00113 
00114           if (retval > rng_limit)
00115             retval = rng_limit;
00116         }
00117       else
00118         retval = rng_base;
00119     }
00120   return retval;
00121 }
00122 
00123 void
00124 Range::sort (void)
00125 {
00126   if (rng_base > rng_limit && rng_inc < 0.0)
00127     {
00128       double tmp = rng_base;
00129       rng_base = min ();
00130       rng_limit = tmp;
00131       rng_inc = -rng_inc;
00132       clear_cache ();
00133     }
00134 }
00135 
00136 std::ostream&
00137 operator << (std::ostream& os, const Range& a)
00138 {
00139   double b = a.base ();
00140   double increment = a.inc ();
00141   int num_elem = a.nelem ();
00142 
00143   for (int i = 0; i < num_elem-1; i++)
00144     os << b + i * increment << " ";
00145 
00146   // Prevent overshoot.  See comment in the matrix_value method
00147   // above.
00148 
00149   os << (increment > 0 ? a.max () : a.min ()) << "\n";
00150 
00151   return os;
00152 }
00153 
00154 std::istream&
00155 operator >> (std::istream& is, Range& a)
00156 {
00157   is >> a.rng_base;
00158   if (is)
00159     {
00160       is >> a.rng_limit;
00161       if (is)
00162         {
00163           is >> a.rng_inc;
00164           a.rng_nelem = a.nelem_internal ();
00165         }
00166     }
00167 
00168   return is;
00169 }
00170 
00171 Range
00172 operator - (const Range& r)
00173 {
00174   return Range (-r.base (), -r.limit (), -r.inc ());
00175 }
00176 
00177 // C  See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5.
00178 // C
00179 // C===Tolerant FLOOR function.
00180 // C
00181 // C    X  -  is given as a Double Precision argument to be operated on.
00182 // C          It is assumed that X is represented with M mantissa bits.
00183 // C    CT -  is   given   as   a   Comparison   Tolerance   such   that
00184 // C          0.LT.CT.LE.3-SQRT(5)/2. If the relative difference between
00185 // C          X and A whole number is  less  than  CT,  then  TFLOOR  is
00186 // C          returned   as   this   whole   number.   By  treating  the
00187 // C          floating-point numbers as a finite ordered set  note  that
00188 // C          the  heuristic  EPS=2.**(-(M-1))   and   CT=3*EPS   causes
00189 // C          arguments  of  TFLOOR/TCEIL to be treated as whole numbers
00190 // C          if they are  exactly  whole  numbers  or  are  immediately
00191 // C          adjacent to whole number representations.  Since EPS,  the
00192 // C          "distance"  between  floating-point  numbers  on  the unit
00193 // C          interval, and M, the number of bits in X'S mantissa, exist
00194 // C          on  every  floating-point   computer,   TFLOOR/TCEIL   are
00195 // C          consistently definable on every floating-point computer.
00196 // C
00197 // C          For more information see the following references:
00198 // C    (1) P. E. Hagerty, "More On Fuzzy Floor And Ceiling," APL  QUOTE
00199 // C        QUAD 8(4):20-24, June 1978. Note that TFLOOR=FL5.
00200 // C    (2) L. M. Breed, "Definitions For Fuzzy Floor And Ceiling",  APL
00201 // C        QUOTE QUAD 8(3):16-23, March 1978. This paper cites FL1 through
00202 // C        FL5, the history of five years of evolutionary development of
00203 // C        FL5 - the seven lines of code below - by open collaboration
00204 // C        and corroboration of the mathematical-computing community.
00205 // C
00206 // C  Penn State University Center for Academic Computing
00207 // C  H. D. Knoble - August, 1978.
00208 
00209 static inline double
00210 tfloor (double x, double ct)
00211 {
00212 // C---------FLOOR(X) is the largest integer algebraically less than
00213 // C         or equal to X; that is, the unfuzzy FLOOR function.
00214 
00215 //  DINT (X) = X - DMOD (X, 1.0);
00216 //  FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
00217 
00218 // C---------Hagerty's FL5 function follows...
00219 
00220   double q = 1.0;
00221 
00222   if (x < 0.0)
00223     q = 1.0 - ct;
00224 
00225   double rmax = q / (2.0 - ct);
00226 
00227   double t1 = 1.0 + floor (x);
00228   t1 = (ct / q) * (t1 < 0.0 ? -t1 : t1);
00229   t1 = rmax < t1 ? rmax : t1;
00230   t1 = ct > t1 ? ct : t1;
00231   t1 = floor (x + t1);
00232 
00233   if (x <= 0.0 || (t1 - x) < rmax)
00234     return t1;
00235   else
00236     return t1 - 1.0;
00237 }
00238 
00239 static inline double
00240 tceil (double x, double ct)
00241 {
00242   return -tfloor (-x, ct);
00243 }
00244 
00245 static inline bool
00246 teq (double u, double v, double ct = 3.0 * DBL_EPSILON)
00247 {
00248   double tu = fabs (u);
00249   double tv = fabs (v);
00250 
00251   return fabs (u - v) < ((tu > tv ? tu : tv) * ct);
00252 }
00253 
00254 int
00255 Range::nelem_internal (void) const
00256 {
00257   int retval = -1;
00258 
00259   if (rng_inc == 0
00260       || (rng_limit > rng_base && rng_inc < 0)
00261       || (rng_limit < rng_base && rng_inc > 0))
00262     {
00263       retval = 0;
00264     }
00265   else
00266     {
00267       double ct = 3.0 * DBL_EPSILON;
00268 
00269       double tmp = tfloor ((rng_limit - rng_base + rng_inc) / rng_inc, ct);
00270 
00271       int n_elt = (tmp > 0.0 ? static_cast<int> (tmp) : 0);
00272 
00273       // If the final element that we would compute for the range is
00274       // equal to the limit of the range, or is an adjacent floating
00275       // point number, accept it.  Otherwise, try a range with one
00276       // fewer element.  If that fails, try again with one more
00277       // element.
00278       //
00279       // I'm not sure this is very good, but it seems to work better than
00280       // just using tfloor as above.  For example, without it, the
00281       // expression 1.8:0.05:1.9 fails to produce the expected result of
00282       // [1.8, 1.85, 1.9].
00283 
00284       if (! teq (rng_base + (n_elt - 1) * rng_inc, rng_limit))
00285         {
00286           if (teq (rng_base + (n_elt - 2) * rng_inc, rng_limit))
00287             n_elt--;
00288           else if (teq (rng_base + n_elt * rng_inc, rng_limit))
00289             n_elt++;
00290         }
00291 
00292       retval = (n_elt >= INT_MAX - 1) ? -1 : n_elt;
00293     }
00294 
00295   return retval;
00296 }
00297 
00298 /*
00299 ;;; Local Variables: ***
00300 ;;; mode: C++ ***
00301 ;;; End: ***
00302 */

Wed Dec 29 11:52:18 2004に生成されました。 doxygen1.2.18
SEO [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送