# HG changeset patch # User Rik # Date 1443222914 25200 # Node ID 96153b16febe8a3d4d40bc1410d6d4f5c295315d # Parent 8164c580922b1dab8ecfa06a7c4ef89ce04fac8c Overhaul Range object in liboctave. * Range.h (Range (b, l), Range (b, l, i)): For 2- or 3-element form of constructor, set internal rng_limit equal to actual limit of range object. * Range.h (set_base, set_limit, set_inc): Change to prototypes only. Implementation moved to Range.cc * Range.cc (matrix_value): Return rng_base for first element, rng_limit for last element. * Range.cc (checkelem, elem, index): Simplify functions by returning rng_limit for last element. * Range.cc (sort_internal (bool), sort_internal (Array, bool)): Simplify functions by simply swapping rng_base and rng_limit when sorting a range in the opposite direction. * Range.cc (operator <<): Simplify function by returning rng_limit for last element. * Range.cc (operator >>): Fix input stream operator so a correctly sync'ed range object is created with the correct rng_limit and rng_numel. * Range.cc (set_base, set_inc): Update rng_numel by calling numel_internal () after changing base or increment so that range object is correctly in sync with itself. Clip rng_limit to true limit of data after base or inc has been set. * Range.h (set_limit): Update rng_numel after changing internal rng_limit. Clip rng_limit to actual limit of range object. diff -r 8164c580922b -r 96153b16febe liboctave/array/Range.cc --- a/liboctave/array/Range.cc Fri Sep 25 13:05:01 2015 -0700 +++ b/liboctave/array/Range.cc Fri Sep 25 16:15:14 2015 -0700 @@ -54,27 +54,17 @@ if (rng_numel > 0 && cache.numel () == 0) { cache.resize (1, rng_numel); + + // The first element must always be *exactly* the base. + // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment). + cache(0) = rng_base; + double b = rng_base; double increment = rng_inc; - if (rng_numel > 0) - { - // The first element must always be *exactly* the base. - // E.g, -0 would otherwise become +0 in the loop (-0 + 0*increment). - cache(0) = b; - for (octave_idx_type i = 1; i < rng_numel; i++) - cache(i) = b + i * increment; - } + for (octave_idx_type i = 1; i < rng_numel - 1; i++) + cache(i) = b + i * increment; - // On some machines (x86 with extended precision floating point - // arithmetic, for example) it is possible that we can overshoot - // the limit by approximately the machine precision even though - // we were very careful in our calculation of the number of - // elements. The tests need equality (>= rng_limit or <= rng_limit) - // to have expressions like -5:1:-0 result in a -0 endpoint. - - if ((rng_inc > 0 && cache(rng_numel-1) >= rng_limit) - || (rng_inc < 0 && cache(rng_numel-1) <= rng_limit)) - cache(rng_numel-1) = rng_limit; + cache(rng_numel - 1) = rng_limit; } return cache; @@ -91,14 +81,7 @@ else if (i < rng_numel - 1) return rng_base + i * rng_inc; else - { - double end = rng_base + i * rng_inc; - if ((rng_inc > 0 && end >= rng_limit) - || (rng_inc < 0 && end <= rng_limit)) - return rng_limit; - else - return end; - } + return rng_limit; } double @@ -112,14 +95,7 @@ else if (i < rng_numel - 1) return rng_base + i * rng_inc; else - { - double end = rng_base + i * rng_inc; - if ((rng_inc > 0 && end >= rng_limit) - || (rng_inc < 0 && end <= rng_limit)) - return rng_limit; - else - return end; - } + return rng_limit; #endif } @@ -137,13 +113,7 @@ else if (i < nmax) *array++ = base + i * inc; else - { - double end = base + i * inc; - if ((inc > 0 && end >= limit) || (inc < 0 && end <= limit)) - *array++ = limit; - else - *array++ = end; - } + *array++ = limit; } private: @@ -202,7 +172,7 @@ { retval = rng_base + (rng_numel - 1) * rng_inc; - // See the note in the matrix_value method above. + // Require '<=' test. See note in max (). if (retval <= rng_limit) retval = rng_limit; } @@ -221,7 +191,13 @@ { retval = rng_base + (rng_numel - 1) * rng_inc; - // See the note in the matrix_value method above. + // On some machines (x86 with extended precision floating point + // arithmetic, for example) it is possible that we can overshoot the + // limit by approximately the machine precision even though we were + // very careful in our calculation of the number of elements. + // Therefore, we clip the result to the limit if it overshoots. + // The test also includes equality (>= rng_limit) to have expressions + // such as -5:1:-0 result in a -0 endpoint. if (retval >= rng_limit) retval = rng_limit; } @@ -234,19 +210,10 @@ void Range::sort_internal (bool ascending) { - if (ascending && rng_base > rng_limit && rng_inc < 0.0) + if ((ascending && rng_base > rng_limit && rng_inc < 0.0) + || (! ascending && rng_base < rng_limit && rng_inc > 0.0)) { - double tmp = rng_base; - rng_base = min (); - rng_limit = tmp; - rng_inc = -rng_inc; - clear_cache (); - } - else if (! ascending && rng_base < rng_limit && rng_inc > 0.0) - { - double tmp = max (); - rng_limit = min (); - rng_base = tmp; + std::swap (rng_base, rng_limit); rng_inc = -rng_inc; clear_cache (); } @@ -263,20 +230,10 @@ bool reverse = false; - if (ascending && rng_base > rng_limit && rng_inc < 0.0) + if ((ascending && rng_base > rng_limit && rng_inc < 0.0) + || (! ascending && rng_base < rng_limit && rng_inc > 0.0)) { - double tmp = rng_base; - rng_base = min (); - rng_limit = tmp; - rng_inc = -rng_inc; - clear_cache (); - reverse = true; - } - else if (! ascending && rng_base < rng_limit && rng_inc > 0.0) - { - double tmp = max (); - rng_limit = min (); - rng_base = tmp; + std::swap (rng_base, rng_limit); rng_inc = -rng_inc; clear_cache (); reverse = true; @@ -346,6 +303,72 @@ return mode; } +void +Range::set_base (double b) +{ + if (rng_base != b) + { + rng_base = b; + rng_numel = numel_internal (); + + double tmplimit = rng_limit; + + if (rng_inc > 0) + tmplimit = max (); + else + tmplimit = min (); + + if (tmplimit != rng_limit) + rng_limit = tmplimit; + + clear_cache (); + } +} + +void +Range::set_limit (double l) +{ + if (rng_limit != l) + { + rng_limit = l; + rng_numel = numel_internal (); + + double tmplimit = rng_limit; + + if (rng_inc > 0) + tmplimit = max (); + else + tmplimit = min (); + + if (tmplimit != rng_limit) + rng_limit = tmplimit; + + clear_cache (); + } +} + +void +Range::set_inc (double i) +{ + if (rng_inc != i) + { + rng_inc = i; + rng_numel = numel_internal (); + + double tmplimit = rng_limit; + + if (rng_inc > 0) + tmplimit = max (); + else + tmplimit = min (); + + if (tmplimit != rng_limit) + rng_limit = tmplimit; + + clear_cache (); + } +} + std::ostream& operator << (std::ostream& os, const Range& a) { @@ -361,8 +384,8 @@ os << b + i * increment << " "; } - // Prevent overshoot. See comment in the matrix_value method above. - os << (increment > 0 ? a.max () : a.min ()) << "\n"; + // Print out exactly the last element, rather than a calculated last element. + os << a.rng_limit << "\n"; return os; } @@ -373,12 +396,14 @@ is >> a.rng_base; if (is) { - is >> a.rng_limit; + double tmp_rng_limit; + is >> tmp_rng_limit; + if (is) - { - is >> a.rng_inc; - a.rng_numel = a.numel_internal (); - } + is >> a.rng_inc; + + // Clip the rng_limit to the true limit and rebuild numel, clear cache + a.set_limit (tmp_rng_limit); } return is; diff -r 8164c580922b -r 96153b16febe liboctave/array/Range.h --- a/liboctave/array/Range.h Fri Sep 25 13:05:01 2015 -0700 +++ b/liboctave/array/Range.h Fri Sep 25 16:15:14 2015 -0700 @@ -43,11 +43,33 @@ Range (double b, double l) : rng_base (b), rng_limit (l), rng_inc (1), - rng_numel (numel_internal ()), cache () { } + rng_numel (numel_internal ()), cache () + { + double tmplimit = rng_limit; + + if (rng_inc > 0) + tmplimit = max (); + else + tmplimit = min (); + + if (tmplimit != rng_limit) + rng_limit = tmplimit; + } Range (double b, double l, double i) : rng_base (b), rng_limit (l), rng_inc (i), - rng_numel (numel_internal ()), cache () { } + rng_numel (numel_internal ()), cache () + { + double tmplimit = rng_limit; + + if (rng_inc > 0) + tmplimit = max (); + else + tmplimit = min (); + + if (tmplimit != rng_limit) + rng_limit = tmplimit; + } // For operators' usage (to preserve element count). Range (double b, double i, octave_idx_type n) @@ -56,6 +78,21 @@ { if (! xfinite (b) || ! xfinite (i) || ! xfinite (rng_limit)) rng_numel = -2; + else + { + // Code below is only needed if the resulting range must be 100% + // correctly constructed. If the Range object created is only + // a temporary one used by operators this may be unnecessary. + double tmplimit = rng_limit; + + if (rng_inc > 0) + tmplimit = max (); + else + tmplimit = min (); + + if (tmplimit != rng_limit) + rng_limit = tmplimit; + } } double base (void) const { return rng_base; } @@ -91,32 +128,11 @@ Array index (const idx_vector& i) const; - void set_base (double b) - { - if (rng_base != b) - { - rng_base = b; - clear_cache (); - } - } + void set_base (double b); - void set_limit (double l) - { - if (rng_limit != l) - { - rng_limit = l; - clear_cache (); - } - } + void set_limit (double l); - void set_inc (double i) - { - if (rng_inc != i) - { - rng_inc = i; - clear_cache (); - } - } + void set_inc (double i); friend OCTAVE_API std::ostream& operator << (std::ostream& os, const Range& r);