GNU Octave 7.1.0
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-2022 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <cmath>
31
32#include <istream>
33#include <limits>
34#include <ostream>
35
36#include "Array-util.h"
37#include "Range.h"
38#include "lo-error.h"
39#include "lo-mappers.h"
40#include "lo-utils.h"
41
42namespace octave
43{
44 template <typename T>
45 T xtfloor (T x, T ct)
46 {
47 // C---------FLOOR(X) is the largest integer algebraically less than
48 // C or equal to X; that is, the unfuzzy FLOOR function.
49
50 // DINT (X) = X - DMOD (X, 1.0);
51 // FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
52
53 // C---------Hagerty's FL5 function follows...
54
55 T q = 1;
56
57 if (x < 0)
58 q = 1 - ct;
59
60 T rmax = q / (2 - ct);
61
62 T t1 = 1 + std::floor (x);
63 t1 = (ct / q) * (t1 < 0 ? -t1 : t1);
64 t1 = (rmax < t1 ? rmax : t1);
65 t1 = (ct > t1 ? ct : t1);
66 t1 = std::floor (x + t1);
67
68 if (x <= 0 || (t1 - x) < rmax)
69 return t1;
70 else
71 return t1 - 1;
72 }
73
74 template <typename T>
75 bool xteq (T u, T v, T ct = 3 * std::numeric_limits<T>::epsilon ())
76 {
77 T tu = std::abs (u);
78 T tv = std::abs (v);
79
80 return std::abs (u - v) < ((tu > tv ? tu : tv) * ct);
81 }
82
83 template <typename T>
84 octave_idx_type xnumel_internal (T base, T limit, T inc)
85 {
86 octave_idx_type retval = -1;
87 if (! math::isfinite (base) || ! math::isfinite (inc)
88 || math::isnan (limit))
89 retval = -2;
90 else if (math::isinf (limit)
91 && ((inc > 0 && limit > 0)
92 || (inc < 0 && limit < 0)))
94 else if (inc == 0
95 || (limit > base && inc < 0)
96 || (limit < base && inc > 0))
97 {
98 retval = 0;
99 }
100 else
101 {
102 T ct = 3 * std::numeric_limits<T>::epsilon ();
103
104 T tmp = xtfloor ((limit - base + inc) / inc, ct);
105
106 octave_idx_type n_elt
107 = (tmp > 0 ? static_cast<octave_idx_type> (tmp) : 0);
108
109 // If the final element that we would compute for the range is
110 // equal to the limit of the range, or is an adjacent floating
111 // point number, accept it. Otherwise, try a range with one
112 // fewer element. If that fails, try again with one more
113 // element.
114 //
115 // I'm not sure this is very good, but it seems to work better
116 // than just using tfloor as above. For example, without it,
117 // the expression 1.8:0.05:1.9 fails to produce the expected
118 // result of [1.8, 1.85, 1.9].
119
120 if (! xteq (base + (n_elt - 1) * inc, limit))
121 {
122 if (xteq (base + (n_elt - 2) * inc, limit))
123 n_elt--;
124 else if (xteq (base + n_elt * inc, limit))
125 n_elt++;
126 }
127
129 ? n_elt : -1);
130 }
131
132 return retval;
133 }
134
135 template <typename T>
136 bool xall_elements_are_ints (T base, T inc, T final_val, octave_idx_type nel)
137 {
138 // If the range is empty or NaN then there are no elements so there
139 // can be no int elements.
140 if (nel == 0 || math::isnan (final_val))
141 return false;
142
143 // If the base and increment are ints, all elements will be
144 // integers.
145 if (math::nint_big (base) == base && math::nint_big (inc) == inc)
146 return true;
147
148 // If the range has only one element, then the base needs to be an
149 // integer.
150 if (nel == 1 && math::nint_big (base))
151 return true;
152
153 return false;
154 }
155
156 template <typename T>
157 T
158 xfinal_value (T base, T limit, T inc, octave_idx_type nel)
159 {
160 T retval = T (0);
161
162 if (nel <= 1)
163 return base;
164
165 // If increment is 0, then numel should also be zero.
166
167 retval = base + (nel - 1) * inc;
168
169 // On some machines (x86 with extended precision floating point
170 // arithmetic, for example) it is possible that we can overshoot
171 // the limit by approximately the machine precision even though
172 // we were very careful in our calculation of the number of
173 // elements. Therefore, we clip the result to the limit if it
174 // overshoots.
175
176 // NOTE: The test also includes equality (>= limit) to have
177 // expressions such as -5:1:-0 result in a -0 endpoint.
178
179 if ((inc > T (0) && retval >= limit) || (inc < T (0) && retval <= limit))
180 retval = limit;
181
182 // If all elements are integers, then ensure the final value is.
183 // Note that we pass the preliminary computed final value to
184 // xall_elements_are_ints, but it only checks whether that value is
185 // NaN.
186
187 if (xall_elements_are_ints (base, inc, retval, nel))
188 retval = std::round (retval);
189
190 return retval;
191 }
192
193 template <typename T>
194 void
195 xinit (T base, T limit, T inc, bool reverse, T& final_val,
196 octave_idx_type& nel)
197 {
198 // Catch obvious NaN ranges.
199 if (math::isnan (base) || math::isnan (limit) || math::isnan (inc))
200 {
201 final_val = numeric_limits<T>::NaN ();
202 nel = 1;
203 return;
204 }
205
206 // Floating point numbers are always signed
207 if (reverse)
208 inc = -inc;
209
210 // Catch empty ranges.
211 if (inc == 0
212 || (limit < base && inc > 0)
213 || (limit > base && inc < 0))
214 {
215 nel = 0;
216 return;
217 }
218
219 // The following case also catches Inf values for increment when
220 // there will be only one element.
221
222 if ((limit <= base && base + inc < limit)
223 || (limit >= base && base + inc > limit))
224 {
225 final_val = base;
226 nel = 1;
227 return;
228 }
229
230 // Any other calculations with Inf will give us either a NaN range
231 // or an infinite nember of elements.
232
233 T dnel = (limit - base) / inc;
234 if (math::isnan (dnel))
235 {
236 nel = 1;
237 final_val = numeric_limits<T>::NaN ();
238 return;
239 }
240
241 if (dnel > 0 && math::isinf (dnel))
242 {
243 // FIXME: Should this be an immediate error?
245
246 // FIXME: Will this do the right thing in all cases?
247 final_val = xfinal_value (base, limit, inc, nel);
248
249 return;
250 }
251
252 // Now that we have handled all the special cases, we can compute
253 // the number of elements and the final value in a way that attempts
254 // to avoid rounding errors as much as possible.
255
256 nel = xnumel_internal (base, limit, inc);
257 final_val = xfinal_value (base, limit, inc, nel);
258 }
259
260 template <typename T>
261 void
262 xinit (const octave_int<T>& base, const octave_int<T>& limit,
263 const octave_int<T>& inc, bool reverse,
264 octave_int<T>& final_val, octave_idx_type& nel)
265 {
266 // We need an integer division that is truncating decimals instead
267 // of rounding. So, use underlying C++ types instead of
268 // octave_int<T>.
269
270 // FIXME: The numerator might underflow or overflow. Add checks for
271 // that.
272 if (reverse)
273 {
274 nel = ((inc == octave_int<T> (0)
275 || (limit > base && inc > octave_int<T> (0))
276 || (limit < base && inc < octave_int<T> (0)))
277 ? 0
278 : (base.value () - limit.value () + inc.value ())
279 / inc.value ());
280
281 final_val = base - (nel - 1) * inc;
282 }
283 else
284 {
285 nel = ((inc == octave_int<T> (0)
286 || (limit > base && inc < octave_int<T> (0))
287 || (limit < base && inc > octave_int<T> (0)))
288 ? 0
289 : (limit.value () - base.value () + inc.value ())
290 / inc.value ());
291
292 final_val = base + (nel - 1) * inc;
293 }
294 }
295
296 template <typename T>
297 bool
298 xis_storable (T base, T limit, octave_idx_type nel)
299 {
300 return ! (nel > 1 && (math::isinf (base) || math::isinf (limit)));
301 }
302
303 template <>
304 bool
305 range<double>::all_elements_are_ints (void) const
306 {
307 return xall_elements_are_ints (m_base, m_increment, m_final, m_numel);
308 }
309
310 template <>
311 bool
312 range<float>::all_elements_are_ints (void) const
313 {
314 return xall_elements_are_ints (m_base, m_increment, m_final, m_numel);
315 }
316
317 template <>
318 void
319 range<double>::init (void)
320 {
321 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
322 }
323
324 template <>
325 void
326 range<float>::init (void)
327 {
328 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
329 }
330
331 // For now, only define for float and double.
332
333#if 0
334
335 template <>
336 void
337 range<octave_int8>::init (void)
338 {
339 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
340 }
341
342 template <>
343 void
344 range<octave_int16>::init (void)
345 {
346 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
347 }
348
349 template <>
350 void
351 range<octave_int32>::init (void)
352 {
353 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
354 }
355
356 template <>
357 void
358 range<octave_int64>::init (void)
359 {
360 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
361 }
362
363 template <>
364 void
365 range<octave_uint8>::init (void)
366 {
367 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
368 }
369
370 template <>
371 void
372 range<octave_uint16>::init (void)
373 {
374 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
375 }
376
377 template <>
378 void
379 range<octave_uint32>::init (void)
380 {
381 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
382 }
383
384 template <>
385 void
386 range<octave_uint64>::init (void)
387 {
388 xinit (m_base, m_limit, m_increment, m_reverse, m_final, m_numel);
389 }
390
391#endif
392
393 template <>
394 bool
395 range<double>::is_storable (void) const
396 {
397 return xis_storable (m_base, m_limit, m_numel);
398 }
399
400 template <>
401 bool
402 range<float>::is_storable (void) const
403 {
404 return xis_storable (m_base, m_limit, m_numel);
405 }
406
407 template <typename T>
409 xnnz (T base, T limit, T inc, T final_val, octave_idx_type nel)
410 {
411 // Note that the order of the following checks matters.
412
413 // If there are no elements, there can be no non-zero elements.
414 if (nel == 0)
415 return 0;
416
417 // All elements have the same sign, hence there are no zeros.
418 if ((base > 0 && limit > 0) || (base < 0 && limit < 0))
419 return nel;
420
421 // All elements are equal (inc = 0) but we know from the previous
422 // condition that they are not positive or negative, therefore all
423 // elements are zero.
424 if (inc == 0)
425 return 0;
426
427 // Exactly one zero at beginning or end of range.
428 if (base == 0 || final_val == 0)
429 return nel - 1;
430
431 // Range crosses negative/positive without hitting zero.
432 // FIXME: Is this test sufficiently tolerant or do we need to be
433 // more careful?
434 if (math::mod (-base, inc) != 0)
435 return nel;
436
437 // Range crosses negative/positive and hits zero.
438 return nel - 1;
439 }
440
441 template <>
443 range<double>::nnz (void) const
444 {
445 return xnnz (m_base, m_limit, m_increment, m_final, m_numel);
446 }
447
448 template <>
450 range<float>::nnz (void) const
451 {
452 return xnnz (m_base, m_limit, m_increment, m_final, m_numel);
453 }
454}
455
456bool
458{
459 // If the base and increment are ints, the final value in the range will also
460 // be an integer, even if the limit is not. If there is one or fewer
461 // elements only the base needs to be an integer.
462
465 && (octave::math::nint_big (m_inc) == m_inc || m_numel <= 1));
466}
467
469Range::nnz (void) const
470{
471 octave_idx_type retval = 0;
472
473 if (! isempty ())
474 {
475 if ((m_base > 0.0 && m_limit > 0.0) || (m_base < 0.0 && m_limit < 0.0))
476 {
477 // All elements have the same sign, hence there are no zeros.
478 retval = m_numel;
479 }
480 else if (m_inc != 0.0)
481 {
482 if (m_base == 0.0 || m_limit == 0.0)
483 // Exactly one zero at beginning or end of range.
484 retval = m_numel - 1;
485 else if ((m_base / m_inc) != std::floor (m_base / m_inc))
486 // Range crosses negative/positive without hitting zero.
487 retval = m_numel;
488 else
489 // Range crosses negative/positive and hits zero.
490 retval = m_numel - 1;
491 }
492 else
493 {
494 // All elements are equal (m_inc = 0) but not positive or negative,
495 // therefore all elements are zero.
496 retval = 0;
497 }
498 }
499
500 return retval;
501}
502
503Matrix
505{
506 Matrix retval (1, m_numel);
507
508 if (m_numel > 0)
509 {
510 // The first element must always be *exactly* the base.
511 // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment).
512 retval(0) = m_base;
513
514 double b = m_base;
515 double increment = m_inc;
516 for (octave_idx_type i = 1; i < m_numel - 1; i++)
517 retval.xelem (i) = b + i * increment;
518
519 retval.xelem (m_numel - 1) = m_limit;
520 }
521
522 return retval;
523}
524
525double
527{
528 if (i < 0 || i >= m_numel)
530
531 if (i == 0)
532 return m_base;
533 else if (i < m_numel - 1)
534 return m_base + i * m_inc;
535 else
536 return m_limit;
537}
538
539double
541{
542 // Ranges are *always* row vectors.
543 if (i != 0)
545
546 return checkelem (j);
547}
548
549double
551{
552 if (i == 0)
553 return m_base;
554 else if (i < m_numel - 1)
555 return m_base + i * m_inc;
556 else
557 return m_limit;
558}
559
562{
563 Array<double> retval;
564
566
567 if (idx.is_colon ())
568 {
569 retval = matrix_value ().reshape (dim_vector (m_numel, 1));
570 }
571 else
572 {
573 if (idx.extent (n) != n)
574 octave::err_index_out_of_range (1, 1, idx.extent (n), n, dims ()); // throws
575
576 dim_vector idx_dims = idx.orig_dimensions ();
577 octave_idx_type idx_len = idx.length (n);
578
579 // taken from Array.cc.
580 if (n != 1 && idx_dims.isvector ())
581 idx_dims = dim_vector (1, idx_len);
582
583 retval.clear (idx_dims);
584
585 // Loop over all values in IDX, executing the lambda expression
586 // for each index value.
587
588 double *array = retval.fortran_vec ();
589
590 idx.loop (n, [=, &array] (idx_vector i)
591 {
592 if (i == 0)
593 *array++ = m_base;
594 else if (i < m_numel - 1)
595 *array++ = m_base + i * m_inc;
596 else
597 *array++ = m_limit;
598 });
599 }
600
601 return retval;
602}
603
604// NOTE: max and min only return useful values if numel > 0.
605// do_minmax_body() in max.cc avoids calling Range::min/max if numel == 0.
606
607double
608Range::min (void) const
609{
610 double retval = 0.0;
611 if (m_numel > 0)
612 {
613 if (m_inc > 0)
614 retval = m_base;
615 else
616 {
617 retval = m_base + (m_numel - 1) * m_inc;
618
619 // Require '<=' test. See note in max ().
620 if (retval <= m_limit)
621 retval = m_limit;
622 }
623
624 }
625 return retval;
626}
627
628double
629Range::max (void) const
630{
631 double retval = 0.0;
632 if (m_numel > 0)
633 {
634 if (m_inc > 0)
635 {
636 retval = m_base + (m_numel - 1) * m_inc;
637
638 // On some machines (x86 with extended precision floating point
639 // arithmetic, for example) it is possible that we can overshoot the
640 // limit by approximately the machine precision even though we were
641 // very careful in our calculation of the number of elements.
642 // Therefore, we clip the result to the limit if it overshoots.
643 // The test also includes equality (>= m_limit) to have expressions
644 // such as -5:1:-0 result in a -0 endpoint.
645 if (retval >= m_limit)
646 retval = m_limit;
647 }
648 else
649 retval = m_base;
650 }
651 return retval;
652}
653
654void
655Range::sort_internal (bool ascending)
656{
657 if ((ascending && m_base > m_limit && m_inc < 0.0)
658 || (! ascending && m_base < m_limit && m_inc > 0.0))
659 {
660 std::swap (m_base, m_limit);
661 m_inc = -m_inc;
662 }
663}
664
665void
667{
668 octave_idx_type nel = numel ();
669
670 sidx.resize (dim_vector (1, nel));
671
672 octave_idx_type *psidx = sidx.fortran_vec ();
673
674 bool reverse = false;
675
676 if ((ascending && m_base > m_limit && m_inc < 0.0)
677 || (! ascending && m_base < m_limit && m_inc > 0.0))
678 {
679 std::swap (m_base, m_limit);
680 m_inc = -m_inc;
681 reverse = true;
682 }
683
684 octave_idx_type tmp = (reverse ? nel - 1 : 0);
685 octave_idx_type stp = (reverse ? -1 : 1);
686
687 for (octave_idx_type i = 0; i < nel; i++, tmp += stp)
688 psidx[i] = tmp;
689}
690
691Matrix
693{
694 return matrix_value ().diag (k);
695}
696
697Range
699{
700 Range retval = *this;
701
702 if (dim == 1)
703 {
704 if (mode == ASCENDING)
705 retval.sort_internal (true);
706 else if (mode == DESCENDING)
707 retval.sort_internal (false);
708 }
709 else if (dim != 0)
710 (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
711
712 return retval;
713}
714
715Range
717 sortmode mode) const
718{
719 Range retval = *this;
720
721 if (dim == 1)
722 {
723 if (mode == ASCENDING)
724 retval.sort_internal (sidx, true);
725 else if (mode == DESCENDING)
726 retval.sort_internal (sidx, false);
727 }
728 else if (dim != 0)
729 (*current_liboctave_error_handler) ("Range::sort: invalid dimension");
730
731 return retval;
732}
733
736{
737 if (m_numel > 1 && m_inc > 0)
738 mode = (mode == DESCENDING) ? UNSORTED : ASCENDING;
739 else if (m_numel > 1 && m_inc < 0)
740 mode = (mode == ASCENDING) ? UNSORTED : DESCENDING;
741 else
742 mode = (mode == UNSORTED) ? ASCENDING : mode;
743
744 return mode;
745}
746
747void
749{
750 if (m_base != b)
751 {
752 m_base = b;
753
754 init ();
755 }
756}
757
758void
760{
761 if (m_limit != l)
762 {
763 m_limit = l;
764
765 init ();
766 }
767}
768
769void
771{
772 if (m_inc != i)
773 {
774 m_inc = i;
775
776 init ();
777 }
778}
779
780std::ostream&
781operator << (std::ostream& os, const Range& a)
782{
783 double b = a.base ();
784 double increment = a.increment ();
785 octave_idx_type nel = a.numel ();
786
787 if (nel > 1)
788 {
789 // First element must be the base *exactly* (e.g., -0).
790 os << b << ' ';
791 for (octave_idx_type i = 1; i < nel-1; i++)
792 os << b + i * increment << ' ';
793 }
794
795 // Print out the last element exactly, rather than a calculated last element.
796 os << a.m_limit << "\n";
797
798 return os;
799}
800
801std::istream&
802operator >> (std::istream& is, Range& a)
803{
804 is >> a.m_base;
805 if (is)
806 {
807 double tmp_limit;
808 is >> tmp_limit;
809
810 if (is)
811 is >> a.m_inc;
812
813 // Clip the m_limit to the true limit, rebuild numel, clear cache
814 a.set_limit (tmp_limit);
815 }
816
817 return is;
818}
819
820// DEPRECATED in Octave 7.
822{
823 return Range (-r.base (), -r.limit (), -r.increment (), r.numel ());
824}
825
826// DEPRECATED in Octave 7.
827Range operator + (double x, const Range& r)
828{
829 return Range (x + r.base (), x + r.limit (), r.increment (), r.numel ());
830}
831
832// DEPRECATED in Octave 7.
833Range operator + (const Range& r, double x)
834{
835 return Range (r.base () + x, r.limit () + x, r.increment (), r.numel ());
836}
837
838// DEPRECATED in Octave 7.
839Range operator - (double x, const Range& r)
840{
841 return Range (x - r.base (), x - r.limit (), -r.increment (), r.numel ());
842}
843
844// DEPRECATED in Octave 7.
845Range operator - (const Range& r, double x)
846{
847 return Range (r.base () - x, r.limit () - x, r.increment (), r.numel ());
848}
849
850// DEPRECATED in Octave 7.
851Range operator * (double x, const Range& r)
852{
853 return Range (x * r.base (), x * r.limit (), x * r.increment (), r.numel ());
854}
855
856// DEPRECATED in Octave 7.
857Range operator * (const Range& r, double x)
858{
859 return Range (r.base () * x, r.limit () * x, r.increment () * x, r.numel ());
860}
861
862// C See Knuth, Art Of Computer Programming, Vol. 1, Problem 1.2.4-5.
863// C
864// C===Tolerant FLOOR function.
865// C
866// C X - is given as a Double Precision argument to be operated on.
867// C It is assumed that X is represented with M mantissa bits.
868// C CT - is given as a Comparison Tolerance such that
869// C 0.LT.CT.LE.3-SQRT(5)/2. If the relative difference between
870// C X and A whole number is less than CT, then TFLOOR is
871// C returned as this whole number. By treating the
872// C floating-point numbers as a finite ordered set note that
873// C the heuristic EPS=2.**(-(M-1)) and CT=3*EPS causes
874// C arguments of TFLOOR/TCEIL to be treated as whole numbers
875// C if they are exactly whole numbers or are immediately
876// C adjacent to whole number representations. Since EPS, the
877// C "distance" between floating-point numbers on the unit
878// C interval, and M, the number of bits in X'S mantissa, exist
879// C on every floating-point computer, TFLOOR/TCEIL are
880// C consistently definable on every floating-point computer.
881// C
882// C For more information see the following references:
883// C (1) P. E. Hagerty, "More On Fuzzy Floor And Ceiling," APL QUOTE
884// C QUAD 8(4):20-24, June 1978. Note that TFLOOR=FL5.
885// C (2) L. M. Breed, "Definitions For Fuzzy Floor And Ceiling", APL
886// C QUOTE QUAD 8(3):16-23, March 1978. This paper cites FL1 through
887// C FL5, the history of five years of evolutionary development of
888// C FL5 - the seven lines of code below - by open collaboration
889// C and corroboration of the mathematical-computing community.
890// C
891// C Penn State University Center for Academic Computing
892// C H. D. Knoble - August, 1978.
893
894static inline double
895tfloor (double x, double ct)
896{
897// C---------FLOOR(X) is the largest integer algebraically less than
898// C or equal to X; that is, the unfuzzy FLOOR function.
899
900// DINT (X) = X - DMOD (X, 1.0);
901// FLOOR (X) = DINT (X) - DMOD (2.0 + DSIGN (1.0, X), 3.0);
902
903// C---------Hagerty's FL5 function follows...
904
905 double q = 1.0;
906
907 if (x < 0.0)
908 q = 1.0 - ct;
909
910 double rmax = q / (2.0 - ct);
911
912 double t1 = 1.0 + std::floor (x);
913 t1 = (ct / q) * (t1 < 0.0 ? -t1 : t1);
914 t1 = (rmax < t1 ? rmax : t1);
915 t1 = (ct > t1 ? ct : t1);
916 t1 = std::floor (x + t1);
917
918 if (x <= 0.0 || (t1 - x) < rmax)
919 return t1;
920 else
921 return t1 - 1.0;
922}
923
924static inline bool
925teq (double u, double v,
926 double ct = 3.0 * std::numeric_limits<double>::epsilon ())
927{
928 double tu = std::abs (u);
929 double tv = std::abs (v);
930
931 return std::abs (u - v) < ((tu > tv ? tu : tv) * ct);
932}
933
936{
937 octave_idx_type retval = -1;
938
941 retval = -2;
943 && ((m_inc > 0 && m_limit > 0)
944 || (m_inc < 0 && m_limit < 0)))
946 else if (m_inc == 0
947 || (m_limit > m_base && m_inc < 0)
948 || (m_limit < m_base && m_inc > 0))
949 {
950 retval = 0;
951 }
952 else
953 {
954 double ct = 3.0 * std::numeric_limits<double>::epsilon ();
955
956 double tmp = tfloor ((m_limit - m_base + m_inc) / m_inc, ct);
957
958 octave_idx_type n_elt = (tmp > 0.0
959 ? static_cast<octave_idx_type> (tmp) : 0);
960
961 // If the final element that we would compute for the range is equal to
962 // the limit of the range, or is an adjacent floating point number,
963 // accept it. Otherwise, try a range with one fewer element. If that
964 // fails, try again with one more element.
965 //
966 // I'm not sure this is very good, but it seems to work better than just
967 // using tfloor as above. For example, without it, the expression
968 // 1.8:0.05:1.9 fails to produce the expected result of [1.8, 1.85, 1.9].
969
970 if (! teq (m_base + (n_elt - 1) * m_inc, m_limit))
971 {
972 if (teq (m_base + (n_elt - 2) * m_inc, m_limit))
973 n_elt--;
974 else if (teq (m_base + n_elt * m_inc, m_limit))
975 n_elt++;
976 }
977
979 ? n_elt : -1);
980 }
981
982 return retval;
983}
984
985double
987{
988 double new_limit = m_inc > 0 ? max () : min ();
989
990 // If result must be an integer then force the new_limit to be one.
992 new_limit = std::round (new_limit);
993
994 return new_limit;
995}
996
997void
999{
1001
1004}
#define NaN
Definition: Faddeeva.cc:261
Range operator*(double x, const Range &r)
Definition: Range.cc:851
Range operator-(const Range &r)
Definition: Range.cc:821
Range operator+(double x, const Range &r)
Definition: Range.cc:827
std::ostream & operator<<(std::ostream &os, const Range &a)
Definition: Range.cc:781
static bool teq(double u, double v, double ct=3.0 *std::numeric_limits< double >::epsilon())
Definition: Range.cc:925
std::istream & operator>>(std::istream &is, Range &a)
Definition: Range.cc:802
static double tfloor(double x, double ct)
Definition: Range.cc:895
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:504
OCTARRAY_API void clear(void)
Definition: Array.cc:87
OCTARRAY_API void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1010
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array.cc:1744
MArray< T > reshape(const dim_vector &new_dims) const
Definition: MArray.h:87
Definition: dMatrix.h:42
OCTAVE_API Matrix diag(octave_idx_type k=0) const
Definition: dMatrix.cc:2402
Definition: Range.h:400
double increment(void) const
Definition: Range.h:465
bool isempty(void) const
Definition: Range.h:485
OCTAVE_API void set_inc(double i)
Definition: Range.cc:770
OCTAVE_API octave_idx_type numel_internal(void) const
Definition: Range.cc:935
OCTAVE_API Array< double > index(const octave::idx_vector &i) const
Definition: Range.cc:561
double m_inc
Definition: Range.h:544
octave_idx_type m_numel
Definition: Range.h:546
dim_vector dims(void) const
Definition: Range.h:478
OCTAVE_API sortmode issorted(sortmode mode=ASCENDING) const
Definition: Range.cc:735
OCTAVE_API double elem(octave_idx_type i) const
Definition: Range.cc:550
OCTAVE_API Range sort(octave_idx_type dim=0, sortmode mode=ASCENDING) const
Definition: Range.cc:698
OCTAVE_API Matrix diag(octave_idx_type k=0) const
Definition: Range.cc:692
double base(void) const
Definition: Range.h:462
OCTAVE_API octave_idx_type nnz(void) const
Definition: Range.cc:469
OCTAVE_API double limit_internal(void) const
Definition: Range.cc:986
OCTAVE_API void init(void)
Definition: Range.cc:998
double m_limit
Definition: Range.h:543
double m_base
Definition: Range.h:542
OCTAVE_API Matrix matrix_value(void) const
Definition: Range.cc:504
OCTAVE_API void set_base(double b)
Definition: Range.cc:748
double limit(void) const
Definition: Range.h:463
OCTAVE_API void sort_internal(bool ascending=true)
Definition: Range.cc:655
OCTAVE_API bool all_elements_are_ints(void) const
Definition: Range.cc:457
octave_idx_type numel(void) const
Definition: Range.h:476
OCTAVE_API double max(void) const
Definition: Range.cc:629
OCTAVE_API double min(void) const
Definition: Range.cc:608
OCTAVE_API double checkelem(octave_idx_type i) const
Definition: Range.cc:526
OCTAVE_API void set_limit(double l)
Definition: Range.cc:759
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
bool isvector(void) const
Definition: dim-vector.h:395
bool is_colon(void) const
Definition: idx-vector.h:556
void loop(octave_idx_type n, Functor body) const
Definition: idx-vector.h:818
octave_idx_type extent(octave_idx_type n) const
Definition: idx-vector.h:540
dim_vector orig_dimensions(void) const
Definition: idx-vector.h:574
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:537
T value(void) const
Definition: oct-inttypes.h:830
F77_RET_T const F77_DBLE * x
bool isfinite(double x)
Definition: lo-mappers.h:192
bool isnan(bool)
Definition: lo-mappers.h:178
bool isinf(double x)
Definition: lo-mappers.h:203
octave_idx_type nint_big(double x)
Definition: lo-mappers.cc:184
double round(double x)
Definition: lo-mappers.h:136
T mod(T x, T y)
Definition: lo-mappers.h:294
std::complex< T > floor(const std::complex< T > &x)
Definition: lo-mappers.h:130
static OCTAVE_NORETURN void err_index_out_of_range(void)
Definition: idx-vector.cc:52
octave_idx_type xnnz(T base, T limit, T inc, T final_val, octave_idx_type nel)
Definition: Range.cc:409
T xtfloor(T x, T ct)
Definition: Range.cc:45
octave_idx_type xnumel_internal(T base, T limit, T inc)
Definition: Range.cc:84
T xfinal_value(T base, T limit, T inc, octave_idx_type nel)
Definition: Range.cc:158
bool xis_storable(T base, T limit, octave_idx_type nel)
Definition: Range.cc:298
bool xteq(T u, T v, T ct=3 *std::numeric_limits< T >::epsilon())
Definition: Range.cc:75
void xinit(T base, T limit, T inc, bool reverse, T &final_val, octave_idx_type &nel)
Definition: Range.cc:195
bool xall_elements_are_ints(T base, T inc, T final_val, octave_idx_type nel)
Definition: Range.cc:136
sortmode
Definition: oct-sort.h:97
@ UNSORTED
Definition: oct-sort.h:97
@ ASCENDING
Definition: oct-sort.h:97
@ DESCENDING
Definition: oct-sort.h:97
static T abs(T x)
Definition: pr-output.cc:1678