computing average value

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Raider

    #1

    computing average value

    I'm trying to get average value. My first attempt is:

    #include <...>

    template <typename T>
    struct avg : public unary_function< T, void>
    {
    T sum, count;
    avg() : sum(0), count(0) {}
    void operator()(T value) { sum+=value; ++count; }
    T result() { return sum / count; }
    };

    int main()
    {
    const int N = 4;
    double arr[N] = { 1, 2, 3, 4 };
    avg<double> res = std::for_each(a rr, arr+N, avg<double>());
    std::cout << "avg=" << res.result() << std::endl;
    }

    Questions are:
    1. Is for_each a right way? May be I should use accumulate or
    something?
    2. ": public unary_function< T, void>" is not nessesary. Should I use it
    anyway?

    Raider

  • Ivan Vecerina

    #2
    Re: computing average value

    "Raider" <sraider@yandex .ru> wrote in message
    news:1140952356 .484221.126760@ z34g2000cwc.goo glegroups.com.. .
    : I'm trying to get average value. My first attempt is:
    :
    : #include <...>
    :
    : template <typename T>
    : struct avg : public unary_function< T, void>
    : {
    : T sum, count;
    : avg() : sum(0), count(0) {}
    : void operator()(T value) { sum+=value; ++count; }
    : T result() { return sum / count; }
    : };
    :
    : int main()
    : {
    : const int N = 4;
    : double arr[N] = { 1, 2, 3, 4 };
    : avg<double> res = std::for_each(a rr, arr+N, avg<double>());
    : std::cout << "avg=" << res.result() << std::endl;
    : }
    :
    : Questions are:
    : 1. Is for_each a right way? May be I should use accumulate or
    : something?

    I have to say that my first instinct would be to use (in main):
    double avg = std::accumulate ( arr, arr+N, 0 ) / N;
    Only if the item count is unknown would you need a special class.

    I think that a problem with for_each is that you have no
    guarantee that the algorithm won't create copies of the
    provided function object.
    So std::accumulate would be safer. You could eventually use
    a custom predicate, and an accumulation value of type
    std::pair<doubl e,unsigned> -- sum and count -- or similar.

    : 2. ": public unary_function< T, void>" is not nessesary.
    : Should I use it anyway?
    It is probably a good habit to take, as it will be useful for
    some more advanced generic programming techniques.


    hth -Ivan
    --
    http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
    Brainbench MVP for C++ <> http://www.brainbench.com


    Comment

    • Kai-Uwe Bux

      #3
      Re: computing average value

      Ivan Vecerina wrote:
      [color=blue]
      > "Raider" <sraider@yandex .ru> wrote in message
      > news:1140952356 .484221.126760@ z34g2000cwc.goo glegroups.com.. .
      > : I'm trying to get average value. My first attempt is:
      > :
      > : #include <...>
      > :
      > : template <typename T>
      > : struct avg : public unary_function< T, void>
      > : {
      > : T sum, count;
      > : avg() : sum(0), count(0) {}
      > : void operator()(T value) { sum+=value; ++count; }
      > : T result() { return sum / count; }
      > : };
      > :
      > : int main()
      > : {
      > : const int N = 4;
      > : double arr[N] = { 1, 2, 3, 4 };
      > : avg<double> res = std::for_each(a rr, arr+N, avg<double>());
      > : std::cout << "avg=" << res.result() << std::endl;
      > : }
      > :
      > : Questions are:
      > : 1. Is for_each a right way? May be I should use accumulate or
      > : something?
      >
      > I have to say that my first instinct would be to use (in main):
      > double avg = std::accumulate ( arr, arr+N, 0 ) / N;
      > Only if the item count is unknown would you need a special class.
      >
      > I think that a problem with for_each is that you have no
      > guarantee that the algorithm won't create copies of the
      > provided function object.[/color]

      My understanding of the standard is that this guarantee actually is made:

      [25.1.1]

      template<class InputIterator, class Function>
      Function for_each(InputI terator first, InputIterator last, Function f);
      Effects: Applies f to the result of dereferencing every iterator in the
      range [first, last), starting from first and proceeding to
      last - 1.
      Returns: f.
      Complexity: Applies f exactly last - first times.
      Notes: If f returns a result, the result is ignored.

      As I read this paragraph, "f" denotes the function object passed. The only
      copy that is made is in passing the object by value. Other than that, you
      should be safe. Besides:

      (a) If copies were to be made, the return of f would not make sense. This
      hook is provided to pass back information that the function object may
      collect during its pass over the objects in the sequence.

      (b) If this is *not* the intended meaning of the standard, that should
      qualify as a bug in the standard.


      [snip]


      Best

      Kai-Uwe Bux

      Comment

      • Ivan Vecerina

        #4
        Re: computing average value

        "Kai-Uwe Bux" <jkherciueh@gmx .net> wrote in message
        news:dtscim$rus $1@murdoch.acc. Virginia.EDU...
        : Ivan Vecerina wrote:
        ....
        : > I think that a problem with for_each is that you have no
        : > guarantee that the algorithm won't create copies of the
        : > provided function object.
        :
        : My understanding of the standard is that this guarantee actually is
        made:
        :
        : [25.1.1]
        :
        : template<class InputIterator, class Function>
        : Function for_each(InputI terator first, InputIterator last, Function f);
        : Effects: Applies f to the result of dereferencing every iterator in the
        : range [first, last), starting from first and proceeding to
        : last - 1.
        : Returns: f.
        : Complexity: Applies f exactly last - first times.
        : Notes: If f returns a result, the result is ignored.
        :
        : As I read this paragraph, "f" denotes the function object passed. The
        only
        : copy that is made is in passing the object by value. Other than that,
        you
        : should be safe.

        Right -- I'm afraid that I confused for_each with other algorithms.
        for_each
        is actually the one that provides the most guarantees regarding side
        effects
        and order of execution. See for example the following discussion:



        Thank you for the correction,
        Ivan
        --
        http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form


        Comment

        • Daniel T.

          #5
          Re: computing average value

          In article <1140952356.484 221.126760@z34g 2000cwc.googleg roups.com>,
          "Raider" <sraider@yandex .ru> wrote:
          [color=blue]
          > I'm trying to get average value. My first attempt is:
          >
          > #include <...>
          >
          > template <typename T>
          > struct avg : public unary_function< T, void>
          > {
          > T sum, count;[/color]

          'sum' above probably shouldn't be of type T
          [color=blue]
          > avg() : sum(0), count(0) {}
          > void operator()(T value) { sum+=value; ++count; }
          > T result() { return sum / count; }
          > };
          >
          > int main()
          > {
          > const int N = 4;
          > double arr[N] = { 1, 2, 3, 4 };
          > avg<double> res = std::for_each(a rr, arr+N, avg<double>());
          > std::cout << "avg=" << res.result() << std::endl;
          > }
          >
          > Questions are:
          > 1. Is for_each a right way? May be I should use accumulate or
          > something?[/color]

          Although for_each works, I'd be inclined to use accumulate. What you are
          doing is accumulating the total of the items and the number of items,
          then doing a divide on them...

          template < typename T >
          pair<T, int> avg_accum( const std::pair<T, int>& prev, T next )
          {
          return make_pair( prev.first + next, prev.second + 1 );
          }

          pair< double, int > p = accumulate( arr, arr + N, make_pair( 0.0, 0 ),
          &avg_accum<doub le> );
          cout << "avg2 = " << (p.first/p.second) << '\n';


          Of course in your particular case, you already know the number of items
          so you could just use the specialized form of accumulate, but the above
          will even work for input iterators, whereas the specialized form would
          not.

          [color=blue]
          > 2. ": public unary_function< T, void>" is not nessesary. Should I use it
          > anyway?[/color]

          I think it's good to be in the habit of using them, it communicates
          intent, and is useful for functor composition.


          --
          Magic depends on tradition and belief. It does not welcome observation,
          nor does it profit by experiment. On the other hand, science is based
          on experience; it is open to correction by observation and experiment.

          Comment

          • Raider

            #6
            Re: computing average value

            > 'sum' above probably shouldn't be of type T

            I think it must be as follows:

            typename T sum;
            int count;

            And thanks for the rest feedback!

            Raider

            Comment

            Working...