home *** CD-ROM | disk | FTP | other *** search
- // Range.cc -*- C++ -*-
- /*
-
- Copyright (C) 1992, 1993, 1994, 1995 John W. Eaton
-
- This file is part of Octave.
-
- Octave is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 2, or (at your option) any
- later version.
-
- Octave is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License
- along with Octave; see the file COPYING. If not, write to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
-
- */
-
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
-
- #include <iostream.h>
- #include <limits.h>
-
- #include "Range.h"
- #include "dMatrix.h"
-
- Matrix
- Range::matrix_value (void) const
- {
- Matrix retval;
-
- if (rng_nelem > 0)
- {
- retval.resize (1, rng_nelem);
- double b = rng_base;
- double increment = rng_inc;
- for (int i = 0; i < rng_nelem; i++)
- retval.elem (0, i) = b + i * increment;
- }
-
- return retval;
- }
-
- // NOTE: max and min only return useful values if nelem > 0.
-
- double
- Range::min (void) const
- {
- double retval = 0.0;
- if (rng_nelem > 0)
- {
- if (rng_inc > 0)
- retval = rng_base;
- else
- retval = rng_base + (rng_nelem - 1) * rng_inc;
- }
- return retval;
- }
-
- double
- Range::max (void) const
- {
- double retval = 0.0;
- if (rng_nelem > 0)
- {
- if (rng_inc > 0)
- retval = rng_base + (rng_nelem - 1) * rng_inc;
- else
- retval = rng_base;
- }
- return retval;
- }
-
- void
- Range::sort (void)
- {
- if (rng_base > rng_limit && rng_inc < 0.0)
- {
- double tmp = rng_base;
- rng_base = min ();
- rng_limit = tmp;
- rng_inc = -rng_inc;
- }
- }
-
- void
- Range::print_range (void)
- {
- cerr << "Range: rng_base = " << rng_base
- << " rng_limit " << rng_limit
- << " rng_inc " << rng_inc
- << " rng_nelem " << rng_nelem << "\n";
- }
-
- ostream&
- operator << (ostream& os, const Range& a)
- {
- double b = a.base ();
- double increment = a.inc ();
- int num_elem = a.nelem ();
-
- for (int i = 0; i < num_elem; i++)
- os << b + i * increment << " ";
-
- os << "\n";
-
- return os;
- }
-
- istream&
- operator >> (istream& is, Range& a)
- {
- is >> a.rng_base;
- if (is)
- {
- is >> a.rng_limit;
- if (is)
- {
- is >> a.rng_inc;
- a.rng_nelem = a.nelem_internal ();
- }
- }
-
- return is;
- }
-
- int
- Range::nelem_internal (void) const
- {
- // Find an approximate number of intervals, then do the best we can to
- // find the number of intervals that we would get if we had done
- // something like
- //
- // nelem = 0;
- // while (base + nelem * inc <= limit)
- // nelem++;
- //
- // (for limit > base && inc > 0)
- //
- // The number of elements in the range is one greater than the number
- // of intervals.
-
- // We can't have more than INT_MAX elements in the range.
-
- double d_n_intervals = (rng_limit - rng_base) / rng_inc;
- int max_intervals = INT_MAX - 1;
- double d_max_val = (double) max_intervals;
-
- if (d_n_intervals > d_max_val)
- return -1;
-
- int n_intervals = (d_n_intervals > 0)
- ? ((int) (d_n_intervals + 0.5))
- : ((int) (d_n_intervals - 0.5));
-
- if (rng_limit > rng_base && rng_inc > 0)
- {
- // Our approximation may have been too big.
-
- while (rng_base + n_intervals * rng_inc > rng_limit && n_intervals > 0)
- n_intervals--;
-
- // Now that we are close, get the actual number. Try to avoid
- // problems with extended precision registers.
-
- for (;;)
- {
- volatile double tmp_inc = (n_intervals + 1) * rng_inc;
- volatile double tmp_val = rng_base + tmp_inc;
- if (tmp_val <= rng_limit && n_intervals < max_intervals)
- n_intervals++;
- else
- break;
- }
- }
- else if (rng_limit < rng_base && rng_inc < 0)
- {
- // Our approximation may have been too big.
-
- while (rng_base + n_intervals * rng_inc < rng_limit && n_intervals > 0)
- n_intervals--;
-
- // Now that we are close, get the actual number. Try to avoid
- // problems with extended precision registers.
-
- for (;;)
- {
- volatile double tmp_inc = (n_intervals + 1) * rng_inc;
- volatile double tmp_val = rng_base + tmp_inc;
- if (tmp_val >= rng_limit && n_intervals < max_intervals)
- n_intervals++;
- else
- break;
- }
- }
- else if (rng_limit == rng_base)
- n_intervals = 0;
- else
- n_intervals = -1;
-
- return (n_intervals >= max_intervals) ? -1 : n_intervals + 1;
- }
-
- /*
- ;;; Local Variables: ***
- ;;; mode: C++ ***
- ;;; page-delimiter: "^/\\*" ***
- ;;; End: ***
- */
-