lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Unexpected gcc diagnostic


From: Greg Chicares
Subject: Re: [lmi] Unexpected gcc diagnostic
Date: Sat, 10 Apr 2021 00:22:00 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.9.0

On 4/7/21 10:27 AM, Vadim Zeitlin wrote:
> On Wed, 7 Apr 2021 10:00:19 +0000 Greg Chicares <gchicares@sbcglobal.net> 
> wrote:
> 
> GC> On 4/6/21 6:59 PM, Greg Chicares wrote:
[...]
> GC> The question is when it's okay to dereference this iterator:
> GC>   LowestBft = *std::min_element(Bfts.begin(), last_bft_in_test_period);
> GC> The answer is not whenever
> GC>   Bfts.begin() < last_bft_in_test_period
> GC> but, rather, whenever both
> GC>   Bfts.begin() < Bfts.end()               [the vector is not empty], and
> GC>   Bfts.begin() <= last_bft_in_test_period [the range is not insane]
> 
>  IMO the answer is whenever _either_
> 
>       Bfts.begin() < last_bft_in_test_period
> 
> _or_
> 
>       last_bft_in_test_period < Bfts.end()
> 
> I.e., by construction of last_bft_in_test_period we know that
> 
>       Bfts.begin() ≤ last_bft_in_test_period ≤ Bfts.end()
> 
> and we need at least one of these inequalities to be strict and I would
> assert that this is true.

Agreed.

What I did in commit 79741b1ed3d17 is similar, though not
identical. The reason is that I wanted to add a !empty()
conditional before every call to std::min_element(), here
and elsewhere; and here, adding that is enough.

> GC> Maybe it's just the aftereffects of yesterday's surgery, but somehow
> GC> it troubles me to think that we have different empty sets that have
> GC> different minimums: if a≠b, then min [a,a) ≠ min [b,b) .
> 
>  I don't think it's correct to say that these sets have different minimums.
> min_element() returns different iterators for them, but neither of these
> iterators can be dereferenced, so the actual value of the minimum is the
> same for both empty sets: undefined/undetermined/none.

#include <algorithm>
#include <iostream>
#include <vector>

int main(int, char*[])
{
    std::vector<int> v {1729};
    std::cout << *std::min_element(v.begin(), v.begin()) << std::endl;
    return 0;
}

That's defined to print "1729\n".

Thus, C++ ranges are not always half-open intervals. Proof:
By definition, a half-open interval is
  [a,b) = {x | a ≤ x < b}
so a half-open interval with identical endpoints is empty:
  [a,a) = {x | a ≤ x < a} = ∅
because a is not less than a. As you say, the minimum of
that empty interval is undefined/undetermined/none.

Assume that this
  (v.begin(), v.begin())
(above) is a half-open interval. Then it has no minimum.
But its minimum is 1729.

And, if we let
  std::vector<int> v2 {17};
then
  (v2.begin(), v2.begin())
is the same kind of interval as above, but its minimum is 17,
by special dispensation of the Standard.

Therefore, C++ doesn't adhere strictly to the set-theoretic
definitions. It treats a range with identical endpoints
as a closed interval
  [a,a]
or, following
   [alg.min.max/26] ("Returns last if first == last")
exactly, as {a}.

> GC> I guess the explanation is that viewing C++ iterator ranges as
> GC> half-open is not rigorous, when I had assumed it was.
> 
>  I do believe it is and std::min_element() seems perfectly consistent with
> the usual C++ convention to me.
> 
>  Sorry if I'm still missing something here, but I just don't see what is
> the problem in all this?

I had thought C++ iterator ranges were always half-open
intervals. That's not rigorously true. The [alg.min.max/26]
behavior is reasonable, but it doesn't follow rigorously
from set theory; rather, it's just a convention, like
defining 0/0 to be zero, or one, as you please.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]