0

given a container like std::vector<T>, where T is a generic type for numerical quantities ( like int, float, etc ... ), I would like to have a predicate that takes as arguments :

  • the container itself
  • a range, a type expressing a numerical set of values, or simply 2 extreme numerical values, that should verify the predicate
  • a tolerance, a type expressing a possible ( optional ) extension to the range, in relative terms ( like a percentage ) or in absolute terms ( with a numeric )

I would like to have as an output:

  • the result of the predicate
  • if the range is not enough for some quantities so the tolerance is "used" by some values or not ( but the predicate is still true )

In the C++ standard library looks like there is not even the concept of range and this is strange to me, simply because there are a lot of interesting algorithms and types, but nothing that could possibly serve my purposes in this case.

Before continuing on my own path, I ask, there is something like this in terms of types and algorithms in the C++ library ?

user2485710
  • 9,451
  • 13
  • 58
  • 102
  • 1
    Sounds like a trivial composition of `std::accumulate` and a suitable lambda. – Kerrek SB Dec 04 '13 at 14:23
  • 4
    Nice formulated question without own effort. –  Dec 04 '13 at 14:25
  • In the standard library, ranges are generally represented by two separate values, or `std::pair` where a single value is needed. The lack of an explicit "range" concept is largely due to historical inertia - while it would be nice, it's not deemed worth making massive changes to the library to support it. – Mike Seymour Dec 04 '13 at 14:26
  • @KerrekSB so for each value in the container you are suggesting to "add" the part that is exceeding the range to a global counter and then verify the counter at the end of the cycle ? it could work but it's really ... I should work on this to make it more functional and reusable ... – user2485710 Dec 04 '13 at 14:29
  • @DieterLücking I'm out of Lück :( – user2485710 Dec 04 '13 at 14:29
  • @MikeSeymour actually ranges where planned for C++11 (or shortly afterwards), and dropped because they are far, far easier to deal with after we have concepts, and concepts was dropped because the heavy weight concepts took forever to compile the standard library. C++1y has concepts lite, which provides the machinery to make ranges easier to write and use, which means we should get ranges (and ranged-based algorithms) shortly. – Yakk - Adam Nevraumont Dec 04 '13 at 14:30
  • @user2485710: No, accumulate to a boolean with an "and"-combinator and a lambda that evaluates the condition. – Kerrek SB Dec 04 '13 at 14:30
  • @Kerrek `std::all_of` sounds like better fit for this. – jrok Dec 04 '13 at 14:31
  • 2
    @KerrekSB I'd rather use `std::find_if`, because we want to *stop* when we find something out of range. Or, as jrok says, `std::all_of` :) – Yakk - Adam Nevraumont Dec 04 '13 at 14:31
  • @Yakk yay for adopting one of the things that I envy to Haskell users. Good news. – user2485710 Dec 04 '13 at 14:31
  • jrok, yakk: yes, those are both better, indeed. – Kerrek SB Dec 04 '13 at 14:31
  • @user2485710 I just wrote my own ranges and range-based algorithms. Or use `boost` -- they are both acceptable. I understand why they aren't in `std`, as they aren't *ideal*. – Yakk - Adam Nevraumont Dec 04 '13 at 14:32
  • @Yakk I was browsing the library a couple of days ago and `std::all_of` got my attention, I didn't think of it today until now ... probably because I still would like to have a type for the range, I think that this is the best solution for now; I'm considering this as a 50% answer, and since the other 50% doesn't exist yet ( the T for ranges ), I assume that this should solve my problem ... – user2485710 Dec 04 '13 at 14:35

1 Answers1

1

Rather than evaluate the condition over each item in the collection, I think I'd start by using std::minmax_element to find the smallest and largest elements in the collection.

From there, it's a simple matter of testing whether result.first < minimum and/or result.second > maximum.

Dealing with the tolerance is basically a matter of repeating the test with the expanded range.

As to whether this is likely to be better than std::find_if or std::all_of, it'll depend on both the number of items you expect in the collection and the likelihood of finding a value out of range that would have allowed early exit. I think you'd need some knowledge of the data to give a meaningful prediction about it.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • the vector is containing `T`s in the order of millions of values, but I guess that I will try this 2-3 solutions, the only difference that comes to my mind is that they are both easy to split in multi-threaded code but sometime a `bool` is easier to "manage" than a numerical result. At least considering how my message queue is managed. – user2485710 Dec 04 '13 at 14:46
  • Unless you have multiple sockets, so each CPU has its own bus to memory, chances are that multi-threading won't do much (if any) good here. The computation is sufficiently trivial that the bandwidth to memory is almost certain to be the bottleneck, so unless your multithreading changes the bandwidth to memory, it's unlikely to help. – Jerry Coffin Dec 04 '13 at 15:20