# computing average value

Discussion in 'C++' started by Raider, Feb 26, 2006.

1. ### RaiderGuest

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(arr, 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

Raider, Feb 26, 2006

2. ### Ivan VecerinaGuest

"Raider" <> wrote in message
news:...
: 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(arr, 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:air<double,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

Ivan Vecerina, Feb 26, 2006

3. ### Kai-Uwe BuxGuest

Ivan Vecerina wrote:

> "Raider" <> wrote in message
> news:...
> : 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(arr, 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.

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

[25.1.1]

template<class InputIterator, class Function>
Function for_each(InputIterator 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

Kai-Uwe Bux, Feb 26, 2006
4. ### Ivan VecerinaGuest

"Kai-Uwe Bux" <> wrote in message
news:dtscim\$rus\$...
: 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
:
: [25.1.1]
:
: template<class InputIterator, class Function>
: Function for_each(InputIterator 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:
http://www.angelikalanger.com/Articles/Cuj/03.ForeachTransform/ForEachTransform.html

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

Ivan Vecerina, Feb 26, 2006
5. ### Daniel T.Guest

In article <>,
"Raider" <> wrote:

> 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;

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

> 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(arr, 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?

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:air<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<double> );
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.

> 2. ": public unary_function<T, void>" is not nessesary. Should I use it
> anyway?

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.

Daniel T., Feb 26, 2006
6. ### RaiderGuest

> '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

Raider, Feb 27, 2006