GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Range.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1993-2018 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <cmath>
28 
29 #include <iostream>
30 #include <limits>
31 
32 #include "Array-util.h"
33 #include "Range.h"
34 #include "lo-error.h"
35 #include "lo-mappers.h"
36 #include "lo-utils.h"
37 
38 bool
40 {
41  // If the base and increment are ints, the final value in the range
42  // will also be an integer, even if the limit is not. If there is one
43  // or fewer elements only the base needs to be an integer
44 
48 }
49 
51 Range::nnz (void) const
52 {
54 
55  if (! isempty ())
56  {
57  if ((rng_base > 0.0 && rng_limit > 0.0)
58  || (rng_base < 0.0 && rng_limit < 0.0))
59  {
60  // All elements have the same sign, hence there are no zeros.
61  retval = rng_numel;
62  }
63  else if (rng_inc != 0.0)
64  {
65  if (rng_base == 0.0 || rng_limit == 0.0)
66  retval = rng_numel - 1;
67  else if ((rng_base / rng_inc) != std::floor (rng_base / rng_inc))
68  retval = rng_numel;
69  else
70  retval = rng_numel - 1;
71  }
72  else
73  {
74  // All elements are equal (rng_inc = 0) but not positive or negative,
75  // therefore all elements are zero.
76  retval = 0;
77  }
78  }
79 
80  return retval;
81 }
82 
83 Matrix
84 Range::matrix_value (void) const
85 {
86  if (rng_numel > 0 && cache.isempty ())
87  {
88  cache.resize (1, rng_numel);
89 
90  // The first element must always be *exactly* the base.
91  // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
92  cache(0) = rng_base;
93 
94  double b = rng_base;
95  double increment = rng_inc;
96  for (octave_idx_type i = 1; i < rng_numel - 1; i++)
97  cache(i) = b + i * increment;
98 
99  cache(rng_numel - 1) = rng_limit;
100  }
101 
102  return cache;
103 }
104 
105 double
107 {
108  // Ranges are row vectors.
109 
110  if (i < 0 || i >= rng_numel)
112 
113  if (i == 0)
114  return rng_base;
115  else if (i < rng_numel - 1)
116  return rng_base + i * rng_inc;
117  else
118  return rng_limit;
119 }
120 
121 double
123 {
124  if (i != 0)
126 
127  return checkelem (j);
128 }
129 
130 double
132 {
133  if (i == 0)
134  return rng_base;
135  else if (i < rng_numel - 1)
136  return rng_base + i * rng_inc;
137  else
138  return rng_limit;
139 }
140 
141 // Helper class used solely for idx_vector.loop () function call
143 {
144 public:
145  __rangeidx_helper (double *a, double b, double i, double l, octave_idx_type n)
146  : array (a), base (b), inc (i), limit (l), nmax (n-1) { }
147 
149  {
150  if (i == 0)
151  *array++ = base;
152  else if (i < nmax)
153  *array++ = base + i * inc;
154  else
155  *array++ = limit;
156  }
157 
158 private:
159 
160  double *array, base, inc, limit;
162 
163 };
164 
166 Range::index (const idx_vector& i) const
167 {
169 
171 
172  if (i.is_colon ())
173  {
175  }
176  else
177  {
178  if (i.extent (n) != n)
179  octave::err_index_out_of_range (1, 1, i.extent (n), n); // throws
180 
181  dim_vector rd = i.orig_dimensions ();
182  octave_idx_type il = i.length (n);
183 
184  // taken from Array.cc.
185  if (n != 1 && rd.isvector ())
186  rd = dim_vector (1, il);
187 
188  retval.clear (rd);
189 
190  // idx_vector loop across all values in i,
191  // executing __rangeidx_helper (i) for each i
192  i.loop (n, __rangeidx_helper (retval.fortran_vec (),
194  }
195 
196  return retval;
197 }
198 
199 // NOTE: max and min only return useful values if numel > 0.
200 // do_minmax_body() in max.cc avoids calling Range::min/max if numel == 0.
201 
202 double
203 Range::min (void) const
204 {
205  double retval = 0.0;
206  if (rng_numel > 0)
207  {
208  if (rng_inc > 0)
209  retval = rng_base;
210  else
211  {
212  retval = rng_base + (rng_numel - 1) * rng_inc;
213 
214  // Require '<=' test. See note in max ().
215  if (retval <= rng_limit)
216  retval = rng_limit;
217  }
218 
219  }
220  return retval;
221 }
222 
223 double
224 Range::max (void) const
225 {
226  double retval = 0.0;
227  if (rng_numel > 0)
228  {
229  if (rng_inc > 0)
230  {
231  retval = rng_base + (rng_numel - 1) * rng_inc;
232 
233  // On some machines (x86 with extended precision floating point
234  // arithmetic, for example) it is possible that we can overshoot the
235  // limit by approximately the machine precision even though we were
236  // very careful in our calculation of the number of elements.
237  // Therefore, we clip the result to the limit if it overshoots.
238  // The test also includes equality (>= rng_limit) to have expressions
239  // such as -5:1:-0 result in a -0 endpoint.
240  if (retval >= rng_limit)
241  retval = rng_limit;
242  }
243  else
244  retval = rng_base;
245  }
246  return retval;
247 }
248 
249 void
250 Range::sort_internal (bool ascending)
251 {
252  if ((ascending && rng_base > rng_limit && rng_inc < 0.0)
253  || (! ascending && rng_base < rng_limit && rng_inc > 0.0))
254  {
256  rng_inc = -rng_inc;
257  clear_cache ();
258  }
259 }
260 
261 void
263 {
264  octave_idx_type nel = numel ();
265 
266  sidx.resize (dim_vector (1, nel));
267 
268  octave_idx_type *psidx = sidx.fortran_vec ();
269 
270  bool reverse = false;
271 
272  if ((ascending && rng_base > rng_limit && rng_inc < 0.0)
273  || (! ascending && rng_base < rng_limit && rng_inc > 0.0))
274  {
276  rng_inc = -rng_inc;
277  clear_cache ();
278  reverse = true;
279  }
280 
281  octave_idx_type tmp = (reverse ? nel - 1 : 0);
282  octave_idx_type stp = (reverse ? -1 : 1);
283 
284  for (octave_idx_type i = 0; i < nel; i++, tmp += stp)
285  psidx[i] = tmp;
286 
287 }
288 
289 Matrix
291 {
292  return matrix_value ().diag (k);
293 }
294 
295 Range
297 {
298  Range retval = *this;
299 
300  if (dim == 1)
301  {
302  if (mode == ASCENDING)
303  retval.sort_internal (true);
304  else if (mode == DESCENDING)
305  retval.sort_internal (false);
306  }
307  else if (dim != 0)
308  (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
309 
310  return retval;
311 }
312 
313 Range
315  sortmode mode) const
316 {
317  Range retval = *this;
318 
319  if (dim == 1)
320  {
321  if (mode == ASCENDING)
322  retval.sort_internal (sidx, true);
323  else if (mode == DESCENDING)
324  retval.sort_internal (sidx, false);
325  }
326  else if (dim != 0)
327  (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
328 
329  return retval;
330 }
331 
332 sortmode
334 {
335  if (rng_numel > 1 && rng_inc > 0)
337  else if (rng_numel > 1 && rng_inc < 0)
339  else
340  mode = (mode ? mode : ASCENDING);
341 
342  return mode;
343 }
344 
345 void
347 {
348  if (rng_base != b)
349  {
350  rng_base = b;
351 
352  init ();
353  }
354 }
355 
356 void
358 {
359  if (rng_limit != l)
360  {
361  rng_limit = l;
362 
363  init ();
364  }
365 }
366 
367 void
369 {
370  if (rng_inc != i)
371  {
372  rng_inc = i;
373 
374  init ();
375  }
376 }
377 
378 std::ostream&
379 operator << (std::ostream& os, const Range& a)
380 {
381  double b = a.base ();
382  double increment = a.inc ();
383  octave_idx_type num_elem = a.numel ();
384 
385  if (num_elem > 1)
386  {
387  // First element must be the base *exactly* (-0).
388  os << b << ' ';
389  for (octave_idx_type i = 1; i < num_elem-1; i++)
390  os << b + i * increment << ' ';
391  }
392 
393  // Print out exactly the last element, rather than a calculated last element.
394  os << a.rng_limit << "\n";
395 
396  return os;
397 }
398 
399 std::istream&
400 operator >> (std::istream& is, Range& a)
401 {
402  is >> a.rng_base;
403  if (is)
404  {
405  double tmp_rng_limit;
406  is >> tmp_rng_limit;
407 
408  if (is)
409  is >> a.rng_inc;
410 
411  // Clip the rng_limit to the true limit and rebuild numel, clear cache
412  a.set_limit (tmp_rng_limit);
413  }
414 
415  return is;
416 }
417 
418 Range
420 {
421  return Range (-r.base (), -r.limit (), -r.inc (), r.numel ());
422 }
423 
424 Range operator + (double x, const Range& r)
425 {
426  Range result (x + r.base (), x + r.limit (), r.inc (), r.numel ());
427  if (result.rng_numel < 0)
428  result.cache = x + r.matrix_value ();
429 
430  return result;
431 }
432 
433 Range operator + (const Range& r, double x)
434 {
435  Range result (r.base () + x, r.limit () + x, r.inc (), r.numel ());
436  if (result.rng_numel < 0)
437  result.cache = r.matrix_value () + x;
438 
439  return result;
440 }
441 
442 Range operator - (double x, const Range& r)
443 {
444  Range result (x - r.base (), x - r.limit (), -r.inc (), r.numel ());
445  if (result.rng_numel < 0)
446  result.cache = x - r.matrix_value ();
447 
448  return result;
449 }
450 
451 Range operator - (const Range& r, double x)
452 {
453  Range result (r.base () - x, r.limit () - x, r.inc (), r.numel ());
454  if (result.rng_numel < 0)
455  result.cache = r.matrix_value () - x;
456 
457  return result;
458 }
459 
460 Range operator * (double x, const Range& r)
461 {
462  Range result (x * r.base (), x * r.limit (), x * r.inc (), r.numel ());
463  if (result.rng_numel < 0)
464  result.cache = x * r.matrix_value ();
465 
466  return result;
467 }
468 
469 Range operator * (const Range& r, double x)
470 {
471  Range result (r.base () * x, r.limit () * x, r.inc () * x, r.numel ());
472  if (result.rng_numel < 0)
473  result.cache = r.matrix_value () * x;
474 
475  return result;
476 }
477 
478 // C See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5.
479 // C
480 // C===Tolerant FLOOR function.
481 // C
482 // C X - is given as a Double Precision argument to be operated on.
483 // C It is assumed that X is represented with M mantissa bits.
484 // C CT - is given as a Comparison Tolerance such that
485 // C 0.LT.CT.LE.3-SQRT(5)/2. If the relative difference between
486 // C X and A whole number is less than CT, then TFLOOR is
487 // C returned as this whole number. By treating the
488 // C floating-point numbers as a finite ordered set note that
489 // C the heuristic EPS=2.**(-(M-1)) and CT=3*EPS causes
490 // C arguments of TFLOOR/TCEIL to be treated as whole numbers
491 // C if they are exactly whole numbers or are immediately
492 // C adjacent to whole number representations. Since EPS, the
493 // C "distance" between floating-point numbers on the unit
494 // C interval, and M, the number of bits in X'S mantissa, exist
495 // C on every floating-point computer, TFLOOR/TCEIL are
496 // C consistently definable on every floating-point computer.
497 // C
498 // C For more information see the following references:
499 // C (1) P. E. Hagerty, "More On Fuzzy Floor And Ceiling," APL QUOTE
500 // C QUAD 8(4):20-24, June 1978. Note that TFLOOR=FL5.
501 // C (2) L. M. Breed, "Definitions For Fuzzy Floor And Ceiling", APL
502 // C QUOTE QUAD 8(3):16-23, March 1978. This paper cites FL1 through
503 // C FL5, the history of five years of evolutionary development of
504 // C FL5 - the seven lines of code below - by open collaboration
505 // C and corroboration of the mathematical-computing community.
506 // C
507 // C Penn State University Center for Academic Computing
508 // C H. D. Knoble - August, 1978.
509 
510 static inline double
511 tfloor (double x, double ct)
512 {
513 // C---------FLOOR(X) is the largest integer algebraically less than
514 // C or equal to X; that is, the unfuzzy FLOOR function.
515 
516 // DINT (X) = X - DMOD (X, 1.0);
517 // FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
518 
519 // C---------Hagerty's FL5 function follows...
520 
521  double q = 1.0;
522 
523  if (x < 0.0)
524  q = 1.0 - ct;
525 
526  double rmax = q / (2.0 - ct);
527 
528  double t1 = 1.0 + std::floor (x);
529  t1 = (ct / q) * (t1 < 0.0 ? -t1 : t1);
530  t1 = (rmax < t1 ? rmax : t1);
531  t1 = (ct > t1 ? ct : t1);
532  t1 = std::floor (x + t1);
533 
534  if (x <= 0.0 || (t1 - x) < rmax)
535  return t1;
536  else
537  return t1 - 1.0;
538 }
539 
540 static inline bool
541 teq (double u, double v,
542  double ct = 3.0 * std::numeric_limits<double>::epsilon ())
543 {
544  double tu = fabs (u);
545  double tv = fabs (v);
546 
547  return fabs (u - v) < ((tu > tv ? tu : tv) * ct);
548 }
549 
552 {
553  octave_idx_type retval = -1;
554 
555  if (rng_inc == 0
556  || (rng_limit > rng_base && rng_inc < 0)
557  || (rng_limit < rng_base && rng_inc > 0))
558  {
559  retval = 0;
560  }
561  else
562  {
563  double ct = 3.0 * std::numeric_limits<double>::epsilon ();
564 
565  double tmp = tfloor ((rng_limit - rng_base + rng_inc) / rng_inc, ct);
566 
567  octave_idx_type n_elt = (tmp > 0.0 ? static_cast<octave_idx_type> (tmp)
568  : 0);
569 
570  // If the final element that we would compute for the range is
571  // equal to the limit of the range, or is an adjacent floating
572  // point number, accept it. Otherwise, try a range with one
573  // fewer element. If that fails, try again with one more
574  // element.
575  //
576  // I'm not sure this is very good, but it seems to work better than
577  // just using tfloor as above. For example, without it, the
578  // expression 1.8:0.05:1.9 fails to produce the expected result of
579  // [1.8, 1.85, 1.9].
580 
581  if (! teq (rng_base + (n_elt - 1) * rng_inc, rng_limit))
582  {
583  if (teq (rng_base + (n_elt - 2) * rng_inc, rng_limit))
584  n_elt--;
585  else if (teq (rng_base + n_elt * rng_inc, rng_limit))
586  n_elt++;
587  }
588 
590  ? n_elt : -1;
591  }
592 
593  return retval;
594 }
595 
596 double
598 {
599  double tmp_limit = rng_limit;
600 
601  if (rng_inc > 0)
602  tmp_limit = max ();
603  else
604  tmp_limit = min ();
605 
606  return (tmp_limit != rng_limit) ? tmp_limit : rng_limit;
607 }
608 
609 void
611 {
614 
615  clear_cache ();
616 }
static bool teq(double u, double v, double ct=3.0 *std::numeric_limits< double >::epsilon())
Definition: Range.cc:541
Range sort(octave_idx_type dim=0, sortmode mode=ASCENDING) const
Definition: Range.cc:296
Matrix cache
Definition: Range.h:164
sortmode issorted(sortmode mode=ASCENDING) const
Definition: Range.cc:333
std::ostream & operator<<(std::ostream &os, const Range &a)
Definition: Range.cc:379
Matrix diag(octave_idx_type k=0) const
Definition: Range.cc:290
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:148
double rng_limit
Definition: Range.h:159
bool isempty(void) const
Definition: Array.h:565
Range operator-(const Range &r)
Definition: Range.cc:419
sortmode
Definition: oct-sort.h:105
bool all_elements_are_ints(void) const
Definition: Range.cc:39
double limit
Definition: Range.cc:160
Return the CPU time used by your Octave session The first output is the total time spent executing your process and is equal to the sum of second and third which are the number of CPU seconds spent executing in user mode and the number of CPU seconds spent executing in system mode
Definition: data.cc:6348
for large enough k
Definition: lu.cc:617
const T * fortran_vec(void) const
Definition: Array.h:584
Range operator+(double x, const Range &r)
Definition: Range.cc:424
Definition: Range.h:33
bool isnan(bool)
Definition: lo-mappers.h:187
void err_index_out_of_range(int nd, int dim, octave_idx_type idx, octave_idx_type ext)
std::complex< T > floor(const std::complex< T > &x)
Definition: lo-mappers.h:139
void clear_cache(void) const
Definition: Range.h:172
u
Definition: lu.cc:138
double rng_base
Definition: Range.h:158
void init(void)
Definition: Range.cc:610
void operator()(octave_idx_type i)
Definition: Range.cc:148
double limit(void) const
Definition: Range.h:79
double base(void) const
Definition: Range.h:78
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:400
bool swap
Definition: load-save.cc:738
Array< double > index(const idx_vector &i) const
Definition: Range.cc:166
double limit_internal(void) const
Definition: Range.cc:597
Matrix diag(octave_idx_type k=0) const
Definition: dMatrix.cc:2583
MArray< T > reshape(const dim_vector &new_dims) const
Definition: MArray.h:91
void sort_internal(bool ascending=true)
Definition: Range.cc:250
Range operator*(double x, const Range &r)
Definition: Range.cc:460
octave_idx_type nnz(void) const
Definition: Range.cc:51
void set_base(double b)
Definition: Range.cc:346
Matrix matrix_value(void) const
Definition: Range.cc:84
octave_idx_type numel(void) const
Definition: Range.h:85
void resize(const dim_vector &dv, const T &rfv)
Resizing (with fill).
Definition: Array.cc:1010
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
octave_idx_type numel_internal(void) const
Definition: Range.cc:551
std::istream & operator>>(std::istream &is, Range &a)
Definition: Range.cc:400
void set_limit(double l)
Definition: Range.cc:357
double elem(octave_idx_type i) const
Definition: Range.cc:131
Definition: dMatrix.h:36
octave_idx_type rng_numel
Definition: Range.h:162
With real return the complex result
Definition: data.cc:3260
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:227
void set_inc(double i)
Definition: Range.cc:368
octave_idx_type nint_big(double x)
Definition: lo-mappers.cc:182
octave_idx_type nmax
Definition: Range.cc:161
double checkelem(octave_idx_type i) const
Definition: Range.cc:106
static double tfloor(double x, double ct)
Definition: Range.cc:511
double max(void) const
Definition: Range.cc:224
bool isvector(void) const
Definition: dim-vector.h:422
b
Definition: cellfun.cc:400
double min(void) const
Definition: Range.cc:203
for i
Definition: data.cc:5264
double rng_inc
Definition: Range.h:160
double * array
Definition: Range.cc:160
write the output to stdout if nargout is
Definition: load-save.cc:1612
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
__rangeidx_helper(double *a, double b, double i, double l, octave_idx_type n)
Definition: Range.cc:145
bool isempty(void) const
Definition: Range.h:92
octave::stream os
Definition: file-io.cc:627
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE * x
double inc(void) const
Definition: Range.h:80