Velocity Reviews > C++ > computing average value

# computing average value

Raider
Guest
Posts: n/a

 02-26-2006
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

Ivan Vecerina
Guest
Posts: n/a

 02-26-2006
"Raider" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) oups.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(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

Kai-Uwe Bux
Guest
Posts: n/a

 02-26-2006
Ivan Vecerina wrote:

> "Raider" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) oups.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(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

Ivan Vecerina
Guest
Posts: n/a

 02-26-2006
"Kai-Uwe Bux" <(E-Mail Removed)> wrote in message
news:dtscim\$rus\$(E-Mail Removed)...
: 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/Articl...Transform.html

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

Daniel T.
Guest
Posts: n/a

 02-26-2006
In article <(E-Mail Removed) .com>,
"Raider" <(E-Mail Removed)> 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.

Raider
Guest
Posts: n/a

 02-27-2006
> '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