// File:       numeric.c++
// Version:    1.00
// Author:     Acorn C/C++ port (c) Miles Sabin, 1997
// Purpose:    approximation to ANSI C++ numeric ops

// Copyright (c) 1994
// Hewlett-Packard Company
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation.  Hewlett-Packard Company makes no
// representations about the suitability of this software for any
// purpose.  It is provided "as is" without express or implied warranty.

// Change log:
//  11/01/97   v. 1.00
//  01/04/97   Added non-ANSI iota().

#include "numeric.h"


// accumulate

template<class InputIterator, class T>
T accumulate(InputIterator first, InputIterator last, T init)
{
  while(first != last)
  {
    init = init+*first;
    ++first;
  }
  return init;
}

template<class InputIterator, class T, class BinaryOperation>
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation binary_op)
{
  while(first != last)
  {
    init = binary_op(init, *first);
    ++first;
  }
  return init;
}


// inner_product

template<class InputIterator1, class InputIterator2, class T>
T inner_product(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init)
{
  while(first1 != last1)
  {
    init = init+((*first1)*(*first2));
    ++first1;
    ++first2;
  }
  return init;
}

template<class InputIterator1, class InputIterator2, class T, class BinaryOperation1, class BinaryOperation2>
T inner_product
  (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init,
   BinaryOperation1 binary_op1, BinaryOperation2 binary_op2)
{
  while(first1 != last1)
  {
    init = binary_op1(init, binary_op2(*first1, *first2));
    ++first1;
    ++first2;
  }
  return init;
}


// partial_sum

template<class InputIterator, class OutputIterator, class T>
OutputIterator __partial_sum(InputIterator first, InputIterator last, OutputIterator result, T*)
{
  T value = *first;
  while(++first != last)
  {
    value = value+*first;
    *++result = value;
  }
  return ++result;
}

template<class InputIterator, class OutputIterator>
OutputIterator partial_sum(InputIterator first, InputIterator last, OutputIterator result)
{
  if(first == last)
    return result;
  *result = *first;
  return __partial_sum(first, last, result, value_type(first));
}

template<class InputIterator, class OutputIterator, class T, class BinaryOperation>
OutputIterator
  __partial_sum(InputIterator first, InputIterator last, OutputIterator result, T*, BinaryOperation binary_op)

{
  T value = *first;
  while(++first != last)
  {
    value = binary_op(value, *first);
    *++result = value;
  }
  return ++result;
}

template<class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator
  partial_sum(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op)
{
  if(first == last)
  return result;
  *result = *first;
  return __partial_sum(first, last, result, value_type(first), binary_op);
}


// adjacent_difference

template<class InputIterator, class OutputIterator, class T>
OutputIterator __adjacent_difference(InputIterator first, InputIterator last,  OutputIterator result, T*)
{
  T value = *first;
  while(++first != last)
  {
    T tmp = *first;
    *++result = tmp-value;
    value = tmp;
  }
  return ++result;
}

template<class InputIterator, class OutputIterator>
OutputIterator adjacent_difference(InputIterator first, InputIterator last, OutputIterator result)
{
  if(first == last)
    return result;
  *result = *first;
  return __adjacent_difference(first, last, result, value_type(first));
}

template<class InputIterator, class OutputIterator, class T, class BinaryOperation>
OutputIterator
  __adjacent_difference
    (InputIterator first, InputIterator last, OutputIterator result, T*, BinaryOperation binary_op)
{
  T value = *first;
  while(++first != last)
  {
    T tmp = *first;
    *++result = binary_op(tmp, value);
    value = tmp;
  }
  return ++result;
}

template<class InputIterator, class OutputIterator, class BinaryOperation>
OutputIterator
  adjacent_difference(InputIterator first, InputIterator last, OutputIterator result, BinaryOperation binary_op)
{
  if(first == last)
    return result;
  *result = *first;
  return __adjacent_difference(first, last, result, value_type(first), binary_op);
}
