################################################################################
#
#  kPerl Logics/Mathematics Library Group
#  Library for Logical Operations and Basic Calculations
#
#  copyright (c)
#    Institute of Molecular Biotechnology Jena, Dept. Genome Analysis, 1998-2003
#    Karol Szafranski and Inst. Physiol. Chem., Univ. Düsseldorf, 1997-1998
#  author
#    Karol Szafranski, karol.szafranski@leibniz-fli.de
#
################################################################################
#
#  DESCRIPTION
#
# - individual description of functions can be found at the beginning of the
#   code blocks
#
################################################################################
#
#  FUNCTIONS, DATA
#
#   @EXPORT
#
# - constants
#   %const
#
# - numeric evaluation
#   &Sign
#   &SignChar
#   &Min
#   &Max
#   &Mean
#
# - arithmetics
#   &Sum
#   &Multiply
#   &ModuloExt
#
#
#  STD OPTIONS
#
#   -debug      print debug protocol to STDERR
#
################################################################################

package Math::kCalc;

# includes
use strict; #use warnings;  # OK 20040810
# we cannot use MainLib::Misc here - it would could cause cross-include!

# symbol export
use Exporter qw(import);
our @EXPORT = qw (
  %const
  &Sign &SignChar &Min &Max &Mean
  &Sum &Multiply &ModuloExt
  );


################################################################################
# constants
################################################################################


our %const = (
  euler => 2.71828182845905,
  pi    => 3.141592653589793238462643383279502884197,
  );


################################################################################
# numeric evaluation
################################################################################


# return sign of value
#
# INTERFACE
# - argument 1: integer or float value
#
# - options:
#   -allow0     allow sign = 0 for argument == 0 or non-numeric,
#               default: +1
#
# - return val: sign value
#
sub Sign {
  my ($value, %opt) = @_;

  # evaluate to sign value, default 1
  if (!$opt{-allow0} or ($value=~m/\d/ and $value!=0)) {
    return ($value<0) ? -1 : 1;
  }

  # evaluate to 0, possibly non-numeric
  else { return 0 }
}


# return sign character of value
#
# INTERFACE
# - argument 1: integer or float value
#
# - options:
#   -allow0     allow sign = '.' (or specified character different from '1')
#               for argument == 0 or non-numeric, default: '+'
#
# - return val: sign character
#
sub SignChar {
  my ($value, %opt) = @_;

  # evaluate to default +
  if (! $opt{-allow0} or ($value =~ m/\d/ and $value != 0)) {
    return ($value < 0) ? '-' : '+';
  }

  # evaluate 0 / non-numeric
  else {
    return ($opt{-allow0} != 1 ) ? $opt{-allow0}:'.';
  }
}


# return minimum of array of values
#
# INTERFACE
# - argument 1+: array of values
# - return val:  minimum value
#
# DESCRIPTION
# - An undef in the array of values will evaluate to 0.
# - Implementation could also be realized via sort / pop. But this would work
#   much slower than the implemented way cause the computational work would
#   increases quadratically with array size.
#
sub Min {
  my ($Value1, @ArrayPlus) = @_;
  my $min;

  # minimum start value
  $min = $Value1;

  # get minimum value
  foreach (@ArrayPlus) {
    $min = ($min < $_) ? $min : $_;
  }

  # return result
  return $min;
}


# return maximum of array of values
#
# INTERFACE
# - argument 1+: array of values
# - return val:  maximum value
#
# DESCRIPTION
# - An undef in the array of values will evaluate to 0.
# - Implementation could also be realized via sort / pop. But this would work
#   much slower than the implemented way cause the computational work would
#   increases quadratically with array size.
#
sub Max {
  my ($val1, @ArrayPlus) = @_;

  # maximum start value
  my $max = $val1 || 0;

  # get overall maximum value
  foreach (@ArrayPlus) {
    $max = ($max > ($_||0)) ? $max : $_||0;
  }

  # return result
  return $max;
}


# calculate mean value from array of values
#
# INTERFACE
# - argument 1+: reference to array of values
# - return val:  mean value
#
# DESCRIPTION
# - this function is implemented in a similar way in &Math::Statist::SampleMean
#
sub Mean {
  my (@data) = @_;

  # sample size, mean value
  my $ValN;
  unless ($ValN = int(@data)) { die sprintf "%s. ERROR: missing the data!\n", (caller(0))[3] }
  return &Sum(@data) / $ValN;
}


################################################################################
# arithmetics
################################################################################


# sum of values
#
# INTERFACE
# - argument 1+: array of values
# - return val:  sum of values
#
sub Sum {
  my ($sum);

  # all that is to do here
  foreach (grep { defined($_) } @_) { $sum += $_; }
  return $sum;
}


# overall product of values
#
# INTERFACE
# - argument 1+: array of values
# - return val:  product of values
#
sub Multiply {
  my $product = 1;

  # all that is to do here
  foreach (@_) { $product *= $_; }
  return $product;
}


# extended modulo, applicable to float values
#
# INTERFACE
# - argument 1: moduland, float value
# - argument 2: modulo operand
# - return val: modulo, float value
#
# DESCRIPTION
# - this function allows a floating point value being a modulo operand
# - like for the classical function the result value will have the same sign
#   as the input value
#
sub ModuloExt {
  my ($value,$operand) = @_;
  $operand or return 0;

  # calculate
  my $modulo = $value - int($value/$operand) * $operand;
  if (&Sign($modulo) != &Sign($operand)) {
    $modulo += $operand;
  }
  
  return $modulo;
}


1;
# $Id: kCalc.pm,v 1.15 2018/06/05 18:02:56 szafrans Exp $
