#if !defined HAVE_ARITH1_H__
#define      HAVE_ARITH1_H__


#include "fxttypes.h"


template <typename Type>
inline Type sum(const Type *f, ulong n)
// return \sum_k {f[k]}
{
    Type s(0);
    while ( n-- )  s += f[n];
    return  s;
}
// -------------------------

template <typename Type>
inline Type mean(const Type *f, ulong n)
// return (\sum_k{f[k]})/n
{
    return  sum(f, n) / n;
}
// -------------------------

template <typename Type>
inline Type subtract_mean(Type *f, ulong n)
// subtract from f[] its mean value
// return mean value
{
    Type m = mean(f, n);
    for (ulong i=0; i<n; ++i)  f[i] -= m;
    return  m;
}
// -------------------------


template <typename Type>
inline Type scalar_product(const Type *f, ulong n)
// return \sum_k {f[k]*f[k]}
{
    Type s(0);
    while ( n-- )  s += f[n] * f[n];
    return  s;
}
// -------------------------

template <typename Type>
inline Type scalar_product(const Type *f, const Type *g, ulong n)
// return \sum_k {f[k]*g[k]}
{
    Type s(0);
    while ( n-- )  s += f[n] * g[n];
    return  s;
}
// -------------------------


template <typename Type>
inline Type sum_of_squares(const Type *f, ulong n)
// return \sum_k {f[k]*f[k]}
{
    Type s(0);
    while ( n-- )  s += f[n] * f[n];
    return  s;
}
// -------------------------

template <typename Type>
inline Type sqr_diff(const Type *f, const Type *g, ulong n)
// return \sum_k { (f[k]-g[k])^2 }
{
    Type s(0);
    while ( n-- ) { Type d = f[n] - g[n];  s += d * d; }
    return  s;
}
// -------------------------


template <typename Type>
inline void delta(Type *f, ulong n, ulong d, Type v=1)
// set array to delta(d0) (i.e. v at index d, zero else)
{
    for (ulong k=0; k<n; ++k)  f[k] = 0;
    if ( d<n )  f[d] = (Type)v;
}
// -------------------------

template <typename Type>
inline ulong test_delta(const Type *f, ulong n, Type *vp=0)
// if f[] is a delta sequence then
//   return index 0<=i<n where f[i]!=0
// else
//  return ~0
//
// if vp!=0 then
//   set vp to the value of the delta pulse
//   set vp to zero is sequence is no delta sequence
{
    ulong k = 0;
    ulong i = ~0UL;
    // search first element != 0:
    while ( k<n )  { if ( 0!=f[k] ) break;  ++k; }
    // check whether there is another one:
    if ( k<n )
    {
        i = k;
        ++k;
        while ( k<n )
        {
            if ( 0!=f[k] ) { i = ~0UL; break; }
            ++k;
        }
    }
    if ( (i!=~0UL) && (0!=vp) )  *vp = f[i];
    // zero if sequence is not a delta seq.

    return  i;
}
// -------------------------


template <typename Type>
inline Type delta_sqr_diff(const Type *f, ulong n, ulong d0, Type v=1)
// return \sum { (f[]-delta(d0) )^2 }
{
    Type s(0);
    for (ulong k=0; k<d0; ++k)  { Type d = f[k];  s += d * d; }
    if ( d0<n )  { Type d = f[d0] - v;  s += d * d; }
    for (ulong k=d0+1; k<n; ++k)  { Type d = f[k];  s += d * d; }
    return  s;
}
// -------------------------



template <typename Type>
inline void negate(Type *f, ulong n)
// negate every element of f[]
{
    while ( n-- )  f[n] = -f[n];
}
// -------------------------

template <typename Type>
inline void add_val(Type *f, ulong n, Type s)
// f[] += g
{
    while ( n-- )  f[n] += s;
}
// -------------------------

template <typename Type>
inline void subtract_val(Type *f, ulong n, Type s)
// f[] -= g
{
    while ( n-- )  f[n] -= s;
}
// -------------------------


template <typename Type>
inline void multiply_val(Type *f, ulong n, Type s)
// f[] *= s
{
    while ( n-- )  f[n] *= s;
}
// -------------------------

template <typename Type>
inline void add(Type *f, ulong n, const Type *g)
// f[] += g[] element-wise
{
    while ( n-- )  f[n] += g[n];
}
// -------------------------

template <typename Type>
inline void subtract(Type *f, ulong n, const Type *g)
// f[] -= g[] element-wise
{
    while ( n-- )  f[n] -= g[n];
}
// -------------------------


template <typename Type>
inline void multiply(Type *f, ulong n, const Type *g)
//  f[] *= g[] element-wise
{
    while ( n-- )  f[n] *= g[n];
}
// -------------------------

template <typename Type>
inline void divide(Type *f, ulong n, const Type *g)
//  f[] /= g[] element-wise  (no check for overflow !)
{
    while ( n-- )  f[n] /= g[n];
}
// -------------------------


#endif // !defined HAVE_ARITH1_H__
