bugGNU Octave - Bugs: bug #64692, colon range includes an extra value

 
 

bug #64692: colon range includes an extra value

Submitter:  None
Submitted:  Mon 18 Sep 2023 12:27:48 PM UTC
   
 
Category:  Interpreter Severity:  2 - Minor
Priority:  3 - Low Item Group:  Incorrect Result
Status:  In Progress Assigned to:  None
Originator Name:  Jeremie Knuesel Originator Email:  -email is unavailable-
Open/Closed:  * Open Release:  * 8.3.0
Operating System:  * Any Fixed Release:  None
Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Mon 25 Sep 2023 05:59:34 PM UTC, comment #37: 

@nrjank: thanks.

I didn't realize that the first and third example were the same.

The second one is the weird one, where the specified limit is used instead of the calculated final value because it falls within some tolerance.

Take a look at the M-file I attached to comment #35.  I can't say for sure that it provides 100% compatibility, but it seems to get closer and allows for easy experimentation.

John W. Eaton <jwe>
Group administrator
Mon 25 Sep 2023 05:50:05 PM UTC, comment #36: 

I'm attaching another attempt to compute the number of elements and the final value of ranges that is compatible with Matlab.  It's an M-file, just intended for discussion and experimentation.  After all this time, I'm still not sure what is best.  I'm sure that a solution providing the best level of compatibility will please Matlab users.  Whatever we decide, I would recommend to all users to avoid non-integer ranges.

(file #55168)

John W. Eaton <jwe>
Group administrator
Mon 25 Sep 2023 05:45:33 PM UTC, comment #35: 

sorry missed the second part of jwe's request.  assuming all(rng==fix(rng)) will catch the 'are all integers?' question:


>> rng = 1 : (1001/250)/(1/250);
>> numel(rng), rng(end), all(rng==fix(rng))
ans =
        1000
ans =
        1000
ans =
  logical
   1

>> rng = 2000: -1 : (1001/250)/(1/250);
>> numel(rng), rng(end), all(rng==fix(rng))
ans =
        1000
ans =
   1.0010e+03
ans =
  logical
   0

>> rng = 1 : (1001/250)/(1/250);
>> numel(rng), rng(end), all(rng==fix(rng))
ans =
        1000
ans =
        1000
ans =
  logical
   1


 looking at the second one:


>> rng = 2000: -1 : (1001/250)/(1/250);
>> rng(find(rng~=fix(rng)))
ans =
   1.0e+03 *
  Columns 1 through 6
    1.0240    1.0230    1.0220    1.0210    1.0200    1.0190
  Columns 7 through 12
    1.0180    1.0170    1.0160    1.0150    1.0140    1.0130
  Columns 13 through 18
    1.0120    1.0110    1.0100    1.0090    1.0080    1.0070
  Columns 19 through 24
    1.0060    1.0050    1.0040    1.0030    1.0020    1.0010

>> fix(rng(find(rng~=fix(rng))))
ans =
  Columns 1 through 5
        1023        1022        1021        1020        1019
  Columns 6 through 10
        1018        1017        1016        1015        1014
  Columns 11 through 15
        1013        1012        1011        1010        1009
  Columns 16 through 20
        1008        1007        1006        1005        1004
  Columns 21 through 24
        1003        1002        1001        1000

>> rng(find(rng~=fix(rng)))-[1024:-1:1001]
ans =
   1.0e-12 *
  Columns 1 through 6
   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137
  Columns 7 through 12
   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137
  Columns 13 through 18
   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137
  Columns 19 through 24
   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137   -0.1137

>> ans(1)/eps
ans =
  -512


Nicholas Jankowski <nrjank>
Group Member
Sun 24 Sep 2023 02:20:13 AM UTC, comment #34: 

matlab 2023a:


>> rng = 1 : (1001/250)/(1/250);
>> numel(rng), rng(end)
ans =
        1000
ans =
        1000

>> rng = 2000: -1 : (1001/250)/(1/250);
>> numel(rng), rng(end)
ans =
        1000
ans =
   1.0010e+03

>> rng = 1 : (1001/250)/(1/250);
>> numel(rng), rng(end)
ans =
        1000
ans =
        1000


Nicholas Jankowski <nrjank>
Group Member
Sat 23 Sep 2023 11:40:01 PM UTC, comment #33: 

I can't verify Matlab myself but the changes look reasonable with some questions.

  • Do you not want to issue warnings for the case where limit is a non-integer when base and inc are?


  • IIUC Octave will now follow Matlab compatibility more closely even though some ranges will no longer have the same number of elements? (The 1000 vs 1001 thing.) If so, is backward compatibility a concern?
Arun Giridhar <arungiridhar>
Group Member
Sat 23 Sep 2023 07:49:16 PM UTC, comment #32: 

I propose the attached changes.  I think they improve Matlab compatibility but I had to make some changes to the expected results for some existing tests in range.tst so it would help to verify the behavior of Matlab for the following tests.  For these ranges, are all elements of the result integers or are any non-integer limits preserved in the range result?  Is that behavior consistent?


rng = 1 : (1001/250)/(1/250);
assert (numel (rng), 1000);
assert (rng(end), 1000);

rng = 2000: -1 : (1001/250)/(1/250);
assert (numel (rng), 1000);
assert (rng(end), 1001);

rng = 1 : (1001/250)/(1/250);
assert (numel (rng), (1000));
assert (rng(end), 1000);



(file #55164)

John W. Eaton <jwe>
Group administrator
Sat 23 Sep 2023 04:47:32 PM UTC, comment #31: 

Yes, I was going with the basis that if those warnings are issued then the user code needs to be made more robust, so Matlab compatibility becomes secondary to that. In that sense, having the warnings allows Octave to not work extra hard for Matlab compatibility, since the user strengthening their own code would benefit the code running on Matlab as well. But I'm OK with what you're describing in comment #30.

Arun Giridhar <arungiridhar>
Group Member
Sat 23 Sep 2023 04:34:06 PM UTC, comment #30: 

I backed out the changes mentioned in comment #28.

After looking at this some more, it seems to me that the special cases in Range.cc for floating point ranges could be handled differently that will make the code both easier to understand and more compatible with Matlab.

If we set the tolerance to zero, doesn't that break compatibility with Matlab for things like 1.8:0.05:1.9?  For me, with the patch from comment #29 the result of that expression doesn't include 1.9 as it apparently does in Matlab and that happens with or without the changes mentioned in comment #28.

We might still want the warnings, but having them doesn't mean we can disregard compatibility issues.

Marking as in progress.

John W. Eaton <jwe>
Group administrator
Sat 23 Sep 2023 03:50:52 PM UTC, comment #29: 

Re comment #27 and comment #26, the change of calling xteq in that place did not affect 1.8 : 0.05 : 1.9 but did change the behavior of 1.85 : 0.05 : 1.9. Previously that was returning the scalar value 1.85 but now it returns two elements [1.85 1.90]. This was also the subject of the FIXME I wrote in my WIP in comment #24, but I removed the FIXME after trying the code in comment #26.

This raises the question: Now that we have the warnings in place, do we even need the extra code in xnumel_internal that tries to decrement / increment n_elt? The same thing also applies to whether we can reduce the 3*eps tolerance to zero. If anything was hitting against that limit, it was a problematic input anyway, to be fixed with the help of the warnings.

WIP patch attached for that proposed change.


(file #55163)

Arun Giridhar <arungiridhar>
Group Member
Sat 23 Sep 2023 03:16:23 PM UTC, comment #28: 
Arun Giridhar <arungiridhar>
Group Member
Sat 23 Sep 2023 03:10:33 PM UTC, comment #27: 

from comment #8 I assumed that the only real difference btw matlab and octave for the 1.8:0.05:1.9 example is the tolerance value used.

Nicholas Jankowski <nrjank>
Group Member
Sat 23 Sep 2023 12:13:04 PM UTC, comment #26: 

I just noticed the inconsistency with 1.8:0.05:1.9 (Octave produces one value and Matlab produces 2).

That problem appears to be due to not using a tolerant comparison when attempting to detect ranges that produce a single value.  So we probably need something like this change (there may be a better way to do it):


diff --git a/liboctave/array/Range.cc b/liboctave/array/Range.cc
--- a/liboctave/array/Range.cc
+++ b/liboctave/array/Range.cc
@@ -219,8 +219,9 @@ xinit (T base, T limit, T inc, bool reve
   // The following case also catches Inf values for increment when
   // there will be only one element.

-  if ((limit <= base && base + inc < limit)
-      || (limit >= base && base + inc > limit))
+  if (((limit <= base && base + inc < limit)
+       || (limit >= base && base + inc > limit))
+      && ! xteq (base + inc, limit))
     {
       final_val = base;
       nel = 1;


John W. Eaton <jwe>
Group administrator
Sat 23 Sep 2023 02:20:58 AM UTC, comment #25: 

@nrjank:

In interpn.m, changing this line:

      y{i} = 1 : (1 / (2 ^ m)) : sz(i);

to this:

      y{i} = ((2 ^ m) : (2 ^ m * sz(i))) / (2 ^ m);


eliminates the BIST failure.

Arun Giridhar <arungiridhar>
Group Member
Sat 23 Sep 2023 01:59:01 AM UTC, comment #24: 

OK I moved it around and now it doesn't miss any warnings, even if it returns a scalar not a range.

WIP patch attached.

But it breaks two tests with interp3 and interpn because the warning is now different.


>>>>> processing ....octave/scripts/general/interp3.m
***** warning <ignoring unsupported '\*' flag> interp3 (rand (3,3,3), 1, "*linear");
!!!!! warning failed.
Expected <ignoring unsupported '\*' flag>, but got <using floating point values in range may yield unexpected results>

>>>>> processing ....octave/scripts/general/interpn.m
***** warning <ignoring unsupported '\*' flag> interpn (rand (3,3), 1, "*linear");
!!!!! warning failed.
Expected <ignoring unsupported '\*' flag>, but got <using floating point values in range may yield unexpected results>



(file #55162)

Arun Giridhar <arungiridhar>
Group Member
Sat 23 Sep 2023 01:01:44 AM UTC, comment #23: 

I pushed the documentation edits on stable.

Re the code change, this is what I get:

octave:2> -2:0     # normal
ans =
  -2  -1   0

octave:3> -2 : (0.3 - 0.2 - 0.1)
warning: range limit is not an integer and will not be reached exactly
ans =
  -2  -1   0

octave:6> 1.8 : 0.05 : 1.9
warning: using floating point values in range may yield unexpected results
ans =
    1.8000    1.8500    1.9000

octave:7> 1.85 : 0.05 : 1.9       #  MISSED WARNING!
ans = 1.8500


How do I fix that last missed warning? Evidently the fact that it has only one element somehow makes it return early but I'm not sure yet which early path it takes...

Here's the code change so far:


diff -r 9d758cacf7ca libinterp/corefcn/interpreter.cc
--- a/libinterp/corefcn/interpreter.cc  Fri Sep 22 20:28:30 2023 -0400
+++ b/libinterp/corefcn/interpreter.cc  Fri Sep 22 20:59:53 2023 -0400
@@ -2084,6 +2084,8 @@ void interpreter::maximum_braindamage ()

   m_error_system.disable_warning ("Octave:abbreviated-property-match");
   m_error_system.disable_warning ("Octave:colon-nonscalar-argument");
+  m_error_system.disable_warning ("Octave:floating-point-limit-in-range");
+  m_error_system.disable_warning ("Octave:floating-point-in-range");
   m_error_system.disable_warning ("Octave:data-file-in-path");
   m_error_system.disable_warning ("Octave:empty-index");
   m_error_system.disable_warning ("Octave:function-name-clash");
diff -r 9d758cacf7ca liboctave/array/Range.cc
--- a/liboctave/array/Range.cc  Fri Sep 22 20:28:30 2023 -0400
+++ b/liboctave/array/Range.cc  Fri Sep 22 20:59:53 2023 -0400
@@ -249,6 +249,17 @@ xinit (T base, T limit, T inc, bool reve
       return;
     }

+  // Warn about floating point values in ranges.
+  if (math::nint_big (base) == base && math::nint_big (inc) == inc
+      && math::nint_big (limit) != limit)
+    (*current_liboctave_warning_with_id_handler)
+      ("Octave:floating-point-limit-in-range",
+       "range limit is not an integer and will not be reached exactly");
+  else if (math::nint_big (base) != base || math::nint_big (inc) != inc)
+    (*current_liboctave_warning_with_id_handler)
+      ("Octave:floating-point-in-range",
+       "using floating point values in range may yield unexpected results");
+
   // Now that we have handled all the special cases, we can compute
   // the number of elements and the final value in a way that attempts
   // to avoid rounding errors as much as possible.


Arun Giridhar <arungiridhar>
Group Member
Fri 22 Sep 2023 08:52:12 PM UTC, comment #22: 

I wouldn't try to guess what is "dangerous" or not.  I'd just have something like

  • if base and increment are integers and limit is not, warn about that (maybe)
  • if either base or increment are not integers, warn that floating point ranges may produce unexpected results


In any case, the warning should have an ID like Octave:floating-point-range to allow it to be disabled.

And, of course, any warning like this needs to be disabled if Octave is started with the --traditional option.

John W. Eaton <jwe>
Group administrator
Fri 22 Sep 2023 08:43:43 PM UTC, comment #21: 

comment #13:

> How MATLAB Stores Floating-Point Numbers
> MATLAB constructs its double and single floating-point data types according to IEEE format and follows the round to nearest, ties to even rounding mode by default.

That is what IEEE 754 does by default anyway. They could have simplified it by saying they're not changing the default hardware rounding mode of IEEE floating points. This makes our life a bit easier because we don't need to set rounding mode differently, but there's still inconsistency in spite of that.

I'm experimenting now with a conditional warning in Range.cc, something like this:

+verbatim+
delta = abs (calculated final value - specified final value);
if (delta <= 3 * eps)   // really close, probably intended
   include the final value
elseif (delta > 1e-12)  // far away, likely not intended
   exclude the final value if not excluded already
else // delta is small but bigger than roundoff error
   warning ("Dangerous use of floating point in range")



Arun Giridhar <arungiridhar>
Group Member
Fri 22 Sep 2023 08:43:18 PM UTC, comment #20: 

Instead of "larger than the specified limit" I should have written "beyond the specified limit" to account for ranges with negative increments, of course.

John W. Eaton <jwe>
Group administrator
Fri 22 Sep 2023 08:41:11 PM UTC, comment #19: 

There is no way to know that the intended end point is 0, is there?  We only know that the value is approximately -eps.  It is not an integer but the base and increment are exact integer values.

In the other cases considered in this report so far, the base and increment are not exactly integers.

I'm just suggesting that in the name of compatibility we avoid computing a final value that is larger than the specified limit of the range when both the base and increment are integers.  Does that improve compatibility?  If so, then I think we should do it.   Can we find any case where Matlab computes a final value that is larger than the specified limit of the range when the base and increment are both exact integers?  For example, what does it do with -10:-1e200 or similar expressions?  If it doesn't create a range that includes zero in that case, then I'm pretty sure it is never using tolerant rounding to guess that the intent was a final value of zero when the base and increment are exact integers.

John W. Eaton <jwe>
Group administrator
Fri 22 Sep 2023 08:09:34 PM UTC, comment #18: 

My previous comment got mis-formatted by the asterisks. Read the multiplication signs where it becomes bold.

comment #15:

> HOWEVER, for the example shown in the initial submission, maybe we are just missing the fact that the beginning value and the increment are integers, so we shouldn't need to use the tolerant comparison to compute the number of elements and if the final target value is not an integer, it should never be included in the final set of values and we should never include any value that is outside that range?


This hinges on what the value of (0.3 - 0.2 - 0.1) "ought" to be. Currently we interpret it as "close to zero and intended to be zero" and act on that basis. As I mentioned in my comment #2, this is less astonishing to me than applying strict rounding rules, because as we see in Matlab's case, it misses the "intended" end point of zero.

In either case, coding that as any of these would work:


b = 0.3 - 0.2 - 0.1;
b = round (b * 1e12) / 1e12;
-2 : 1 : b



hi = 0.3 - 0.2 - 0.1;
lo = -2;
N = 2;
(0:N) * (hi - lo) / N + lo


Etc.

Arun Giridhar <arungiridhar>
Group Member
Fri 22 Sep 2023 08:04:35 PM UTC, comment #17: 

I probably wouldn't actually make the warning unconditional, but it is tempting.

John W. Eaton <jwe>
Group administrator
Fri 22 Sep 2023 07:58:59 PM UTC, comment #16: 

comment #14:

> I'm beginning to think Octave should unconditionally issue a loud warning when a range is specified with non-integer values.
>


Good idea. The Symbolic package does something similar already. There was also the related topic that Range objects may be removed from Octave and replaced with conventional arrays. If that's happening soon, the two changes could be combined, otherwise the warning is good to go by itself.

I'll add a section to the manual hopefully in the next few days documenting these pitfalls. It's a hairy problem if users rely on (0.3 - 0.2 - 0.1) to be strictly less than / greater than / equal to zero, and if such behavior relies on deep implementation details.

One place where floating point rounding is explicitly guarded against is in in tsearch.cc, to determine if a point is inside or outside a triangle. The tolerance used there is 1e-12. Anything smaller is deemed to be noise.

From examining my production Octave code with grep, it seems I don't use floating-point ranges at all; it was never a conscious choice, but it was easier for me to think in terms of "(0:N) slope + base", so "(0:2) 0.1 / 2 + 1.8" instead of "1.8 : 0.05 : 1.9". In any case, they are all saved as arrays / vectors / matrices, so the initial range calculation is always on integer values.

Arun Giridhar <arungiridhar>
Group Member
Fri 22 Sep 2023 07:45:16 PM UTC, comment #15: 

HOWEVER, for the example shown in the initial submission, maybe we are just missing the fact that the beginning value and the increment are integers, so we shouldn't need to use the tolerant comparison to compute the number of elements and if the final target value is not an integer, it should never be included in the final set of values and we should never include any value that is outside that range?

John W. Eaton <jwe>
Group administrator
Fri 22 Sep 2023 07:27:10 PM UTC, comment #14: 

After 30+ years of trying and failing to exactly match Matlab behavior with regard to floating point ranges, I can only conclude that they are harmful and should be avoided, especially if you are given only the initial value, an increment, and a final target value to aim for but that might not be an element of the final set of values.

I'm beginning to think Octave should unconditionally issue a loud warning when a range is specified with non-integer values.

John W. Eaton <jwe>
Group administrator
Fri 22 Sep 2023 07:15:50 PM UTC, comment #13: 


How MATLAB Stores Floating-Point Numbers
MATLAB constructs its double and single floating-point data types according to IEEE format and follows the round to nearest, ties to even rounding mode by default.

A floating-point number x has the form:

x=−1^s * (1+f) * 2^e

where:

s determines the sign.

f is the fraction, or mantissa, which satisfies 0 ≤ f < 1.

e is the exponent.

s, f, and e are each determined by a finite number of bits in memory, with f and e depending on the precision of the data type.

https://www.mathworks.com/help/matlab/matlab_prog/floating-point-numbers.html

i don't know if "MATLAB constructs its double and single floating-point data types according to IEEE format and follows the round to nearest, ties to even rounding mode by default." means anything related to what we're discussing here.

Nicholas Jankowski <nrjank>
Group Member
Fri 22 Sep 2023 07:02:14 PM UTC, comment #12: 

matlab 2023a:

>> 1.85 : 0.05 : 1.9

1.8 : 0.05 : 1.9

-2 : (0.3 - 0.2 - 0.1)

ans =

    1.8500    1.9000


ans =

    1.8000    1.8500    1.9000


ans =

    -2    -1


Nicholas Jankowski <nrjank>
Group Member
Fri 22 Sep 2023 06:33:10 PM UTC, comment #11: 

I tried some experiments with the multiple of eps. It looks zero-sum to me though. The best of the bunch is between 1*eps and 3*eps, but there are edge cases like "1.85 : 0.05 : 1.9" which sometimes return only one value 1.85 and not the second one 1.9. Changing eps or commenting or the special override code to make that work causes some other test to break. At this point, I'm not sure which test to favor.

Has Matlab published their rounding rules on a public site? If not,  try these:

1.85 : 0.05 : 1.9

1.8 : 0.05 : 1.9

-2 : (0.3 - 0.2 - 0.1)

In all cases, the code should be written in a more defensive way anyway.

Arun Giridhar <arungiridhar>
Group Member
Fri 22 Sep 2023 05:51:05 PM UTC, comment #10: 

Understanding how this is a rather subjective behavior, I would recommend if nothing else we maybe try to pull in the arbitrary decision making to be a bit closer to what matlab does.  if nothing else, that lets us at least continue aiming for compatibility and reduction in reports of different behavior.

Down below, my comment #8 test case puts some values on the balance point, but i wouldn't be surprised to see that value scale with X similar to eps(X), so it may need a few more tests to pin that down.

Nicholas Jankowski <nrjank>
Group Member
Fri 22 Sep 2023 04:45:48 PM UTC, comment #9: 

Just for comparison, I ran this in Nelson (version '0.7.9.0 (Freedom)') . Here is what I got:


>> 0.3 - 0.1 - 0.2
ans =
  -2.7756e-17

>> -2 : (0.3 - 0.1 - 0.2)
ans =
    -2    -1     0

>> 1.8 : 0.05 : 1.9
ans =
    1.8000    1.8500

>> 1.9 : -0.05 : 1.8
ans =
    1.9000    1.8500


It seems to indicate that the question of deducing intent in the presence of floating point roundoff is subjective at best, so there's no single way to cover all cases. Each program does its own thing, even when they're aiming for compatibility.

If anyone wants to experiment with Octave's rounding rules for ranges, they're in Range.cc, in the functions xteq() and xnumel_internal().

Lowering the priority for this bug, since there are many workarounds.

Arun Giridhar <arungiridhar>
Group Member
Tue 19 Sep 2023 03:03:12 PM UTC, comment #8: 

I suspect matlab must have some similar behavior, but the tolerance is a bit tighter than octave.  doing some simple bisection to find the balance point:

matlab

>> 1.8:.05+1.42187499999999989*eps:1.9

ans =

   1.800000000000000   1.850000000000000

>> 1.8:.05+1.42187499999999988*eps:1.9

ans =

   1.800000000000000   1.850000000000000   1.900000000000000

>> 1.42187499999999988*eps

ans =

 3.157196726277788e-16


Octave:

>>  1.8:.05+2.42187499999999978*eps:1.9
ans =
    1.8000    1.8500

>>  1.8:.05+2.42187499999999977*eps:1.9
ans =
    1.8000    1.8500    1.9000

>> 2.42187499999999977*eps
ans = 5.3776e-16


Nicholas Jankowski <nrjank>
Group Member
Mon 18 Sep 2023 08:31:24 PM UTC, comment #7: 

I've just verified empirically that reducing the default tolerance ct to 0 in Range.cc (function xteq and the place it's called) causes 1.8 : 0.05 : 1.9 to return only 1.8 and 1.85. Only with a nonzero tolerance ct does it give 1.9 as well.

The existing case seems to do well except for marginal values less than some 2e-15 away from a range limit. If anyone has a better solution from other open source numerical software, pls post it.

Arun Giridhar <arungiridhar>
Group Member
Mon 18 Sep 2023 03:55:17 PM UTC, comment #6: 

comment #2:

> Speaking for myself, this behavior seems to be less astonishing than strict application of limit rules due to floating point artifacts.
>
> What do others think?


One thing that can be quite surprising I think is when someones defines c=a:b (with a<=b), and then some code that assumes c(end) <= b. The current behavior means that such code is not correct.

Regarding the note about 1.8 : 0.05 : 1.9 it's a bit odd since 1.8 + 0.05 + 0.05 gives a value larger than 1.9 anyway.

Jeremie Knuesel <emid>
Mon 18 Sep 2023 02:51:53 PM UTC, comment #5: 

Matlab 2023a:


>> 1.8 : 0.05 : 1.9

ans =

    1.8000    1.8500    1.9000


Nicholas Jankowski <nrjank>
Group Member
Mon 18 Sep 2023 02:11:02 PM UTC, comment #4: 

https://hg.savannah.gnu.org/hgweb/octave/file/489e63504a94/liboctave/array/Range.cc#l75

That function xteq has a default tolerance of plus or minus 3*eps.

https://hg.savannah.gnu.org/hgweb/octave/file/489e63504a94/liboctave/array/Range.cc#l109

The comment here says it intends to help 1.8 : 0.05 : 1.9 achieve the final value of 1.9. What does Matlab do for that?

Arun Giridhar <arungiridhar>
Group Member
Mon 18 Sep 2023 01:58:38 PM UTC, comment #3: 

Sorry, crossed with Pantxo. Have fixed categories now.

Arun Giridhar <arungiridhar>
Group Member
Mon 18 Sep 2023 01:57:08 PM UTC, comment #2: 

Comment: this seems to be a conscious choice as shown by comments in Range.h and Range.cc.

Example: https://hg.savannah.gnu.org/hgweb/octave/file/489e63504a94/liboctave/array/Range.h#l58

// LIMIT is an upper limit and may be outside the range of actual values.  For floating point ranges, we perform a tolerant check to attempt to capture limit in the set of values if it is "close" to the value of base + a multiple of the increment.

There are various helper functions in Range.cc aimed at achieving that effect.

Since the numerical value of -2.7e-17 is close to 0, the 0 gets included. If the final value is more than some 2.3e-15 away, then it is not included.

Speaking for myself, this behavior seems to be less astonishing than strict application of limit rules due to floating point artifacts.

What do others think?

Arun Giridhar <arungiridhar>
Group Member
Mon 18 Sep 2023 01:48:40 PM UTC, comment #1: 

Confirmed with a simpler example (that doesn't involve using a number lower than the machine precision) on 8.3:


octave:1> -2:(-10*eps)
ans =

  -2  -1   0

octave:2> -2:(-11*eps)
ans =

  -2  -1


Pantxo Diribarne <pantxo>
Group Member
Mon 18 Sep 2023 12:27:48 PM UTC, original submission:  

Consider the following:


octave> b = 0.3 - 0.1 - 0.2
b = -2.7756e-17

octave> -2:b
ans =

  -2  -1   0


Here the 0 should not be included: the documentation describes the 'b' value of a:b as "a maximum value which the elements of the range will not exceed". This was observed on Octave 6.4.0, and 8.0.1 using https://octave-online.net/.

This is also different from Matlab's behavior:


>> b = 0.3 - 0.2 - 0.1
b =
  -2.7756e-17

>> -2:b
ans =
    -2    -1


Anonymous

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #55168:  xcolon.m added by jwe (6KiB - text/x-objcsrc)
file #55164:  range-diffs.txt added by jwe (3KiB - text/plain)
file #55163:  eps.patch added by arungiridhar (2KiB - text/x-patch)
file #55162:  range.patch added by arungiridhar (2KiB - text/x-patch)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by jwe (Posted a comment)
  • -email is unavailable- added by emid (Posted a comment)
  • -email is unavailable- added by nrjank (Posted a comment)
  • -email is unavailable- added by arungiridhar (Posted a comment)
  • -email is unavailable- added by pantxo (Posted a comment)
  • -email is unavailable- added by None (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 20 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2023-09-25 jwe Attached File- Added xcolon.m, #55168
    2023-09-23 jwe Attached File- Added range-diffs.txt, #55164
    2023-09-23 jwe StatusReady For Test In Progress
    2023-09-23 arungiridhar Attached File- Added eps.patch, #55163
    2023-09-23 arungiridhar StatusConfirmed Ready For Test
    2023-09-23 jwe StatusPatch Submitted Confirmed
    2023-09-23 arungiridhar StatusConfirmed Patch Submitted
    2023-09-23 arungiridhar Attached File- Added range.patch, #55162
    2023-09-22 nrjank Operating SystemGNU/Linux Any
    2023-09-22 arungiridhar Severity3 - Normal 2 - Minor
        Priority5 - Normal 3 - Low
    2023-09-18 arungiridhar CategoryNone Interpreter
        StatusNone Confirmed
        Release6.4.0 8.3.0
    2023-09-18 arungiridhar CategoryInterpreter None
        StatusConfirmed None
        Release8.3.0 6.4.0
    2023-09-18 pantxo CategoryNone Interpreter
        StatusNone Confirmed
        Release6.4.0 8.3.0

    Back to the top

    Powered by Savane 3.12.
    Corresponding source code