     with BitsAKD;
     with ConsAKD; use ConsAKD;
     with ErroAKD;
     with FloaAKD; use FloaAKD;
     with MathAK ;
     with TextAKD; use TextAKD;
     with StriAK;

     package body MathAKD is
     ---------------------------------------------------------------------------
     -- Copyright (C) 1994 David Wallace Croft.  All rights reserved.
     ---------------------------------------------------------------------------

     function  Characteristic ( InFloat: in float ) return long_integer is
     ---------------------------------------------------------------------------
     -- Rounds towards zero.  Example: Characteristic ( -1.999 ) => -1
     -- Long_integer ( float ) will round to the nearest long_integer, or the
     -- nearest _even_ long_integer when it is centered ( 0.5 ==> 0.0 ).
     -- Characteristic ( float ) truncates, instead.
     ---------------------------------------------------------------------------
       Temp : long_integer;
     begin
       if InFloat >= 0.0 then
      Temp := long_integer ( InFloat - 0.5 );
       else
      Temp := long_integer ( InFloat );
       end if;
       if abs ( float ( Temp ) ) + 1.0 = abs ( InFloat ) then
      if InFloat > 0.0 then
	Temp := Temp + 1;
      else
	Temp := Temp - 1;
      end if;
       end if;
       return Temp;
     exception
       when others =>
      ErroAKD.Notify ( "MathAKD.Characteristic" );
      raise;
     end Characteristic;

     function Combination (
       N : in natural;
       R : in natural )
       return float is
     ---------------------------------------------------------------------------
     -- The number of ways to form combinations of length r from a set of n
     -- distinct objects, repetitions not allowed, is denoted by the symbol
     -- / n \        / n \       n!
     -- |   |, where |   | = ---------------.
     -- \ r /        \ r /   r! * ( n - r )!
     -- "An Introduction to Probability and Its Applications" by Larsen & Marx,
     --   1985, p117, Theorem 3.3.1.
     -- constraint_error if not N >= R
     ---------------------------------------------------------------------------
       Temp : float;
     begin
       Temp := MathAK.Factorial ( N )
	 / ( MathAK.Factorial ( R ) * MathAK.Factorial ( N - R ) );
       return Temp;
     exception
       when constraint_error =>
      ErroAKD.Notify ( "MathAKD.Combination", "Constraint_Error" );
      raise;
       when numeric_error =>
      ErroAKD.Notify ( "MathAKD.Combination", "Numeric_Error" );
      raise;
     end Combination;

     procedure Demo is
     ----------------------------------------------------------------------
     begin
       Put_Line ( Copyright );
--     Put_Line ( Description );
       New_Line;
       Put_Line ( "Math sub-programs package" );
       Put_Line ( "for the ""Meridian OpenAda for DOS"" Ada compiler." );
       New_Line;
       Put_Line ( "No demonstration is currently available." );
       New_Line;
       Pause;
     end Demo;

     procedure Float_String (
	      In_Str: in string;
	      Is_Float: out boolean;
	      Out_Float: out float ) is
     ---------------------------------------------------------------------------
       Exponent    : integer := 0;
       Is_Integer  : boolean := false;
       Is_Positive : boolean := true;
       Place       : integer := 0;
       Position    : integer range 1..In_Str'length := 2;
       Temp_Float  : float   := 0.0;
       Temp_Str    : string ( 1..In_Str'length );
     begin
       Is_Float := false;
       Temp_Str := StriAK.Filtered ( In_Str, "_," );
       if Temp_Str ( 1 ) = '-' then
      Is_Positive := false;
       elsif Temp_Str ( 1 ) = '+' then
      Is_Positive := true;
       else
      Is_Positive := true;
      Position := 1;
       end if;
       for index in Position..Temp_Str'last loop
      Position := index;
      exit when Temp_Str ( index ) = '.';
      if Temp_Str ( index ) not in ( '0'..'9' ) then
	return;
      end if;
      Temp_Float := Temp_Float * 10.0
	+ float ( integer'value ( Temp_Str ( index..index ) ) );
       end loop;
       for index in Position + 1 .. Temp_Str'last loop
      Position := index;
      Place := Place + 1;
      exit when Temp_Str ( index ) = 'E' or Temp_Str ( index ) = 'e';
      exit when Temp_Str ( index ) = ASCII.NUL or Temp_Str ( index ) = ' ';
      if Temp_Str ( index ) not in ( '0'..'9' ) then
	return;
      end if;
      Temp_Float := Temp_Float
	+ float ( integer'value ( Temp_Str ( index..index ) ) )
	     / float ( 10 ** Place );
       end loop;
       if Temp_Str ( Position ) = 'E' or Temp_Str ( Position ) = 'e' then
      Integer_String ( Temp_Str ( Position + 1 .. Temp_Str'last ),
	Is_Integer, Exponent );
      if not Is_Integer then
	return;
      end if;
      Temp_Float := Temp_Float * ( 10.0 ** Exponent );
       end if;
       if Is_Positive then
      Out_Float := Temp_Float;
       else
      Out_Float := - Temp_Float;
       end if;
       Is_Float := true;
     exception
       when others =>
      ErroAKD.Notify ( "MathAKD.Float_String ( string; boolean; float )" );
      raise;
     end Float_String;

     procedure Integer_String (
	      In_Str: in string;
	      Is_Integer: out boolean;
	      Out_Integer: out integer ) is
     ---------------------------------------------------------------------------
     begin
       Is_Integer := true;
       Out_Integer := integer'value ( In_Str );
     exception
       when Constraint_Error => Is_Integer := false;
       when others =>
      ErroAKD.Notify ( "MathAKD.Integer_String" );
      raise;
     end Integer_String;

     procedure Integrate
	      ( F: in     TypeAKD.Array_Float_2;
		E: in     float;
		Y: in out TypeAKD.Array_Float ) is
     ---------------------------------------------------------------------------
     -- Euler's method
     --
     -- y'' + 0.1y' + y = 0 becomes
     --
     -- y1 = y
     -- y2 = y' =  0.0y1 + 1.0y2     F = ( (  0.0, 1.0 ),
     -- y3 = y''= -1.0y1 - 0.1y2           ( -1.0, -0.1 ) )
     --
     -- Y' = ( y1' , = ( y'   , = FY = F ( y1 , = F ( y   ,
     --        y2' ,     y''  ,            y2 ,       y'  ,
     --        y3' )     y''' )            y3 )       y'' )
     --
     -- Integrate by
     --   Y_New = Y_Old + Epsilon * F * Y_Old
     ---------------------------------------------------------------------------
     use TypeAKD;
     ---------------------------------------------------------------------------
     begin
       Y :=  Y + E * ( F * Y );
     exception
       when Constraint_Error =>
      ErroAKD.Notify ( "MathAKD.Integrate", "Constraint_Error" );
      raise;
     end Integrate;

     function  Mantissa ( InFloat: in float ) return float is
     ---------------------------------------------------------------------------
     -- Example:  Mantissa ( 1.3567 ) => 0.3567
     ---------------------------------------------------------------------------
     begin
       return InFloat - float ( MathAKD.Characteristic ( InFloat ) );
     end Mantissa;

     function Mantissa ( InFloat: in float ) return string is
     ---------------------------------------------------------------------------
     -- Example:  Mantissa ( 1.3567 ) ==> ".3567"
     ---------------------------------------------------------------------------
       Mantissa_Tmp: float;
       Mantissa_Str: string ( 1..float'digits + 1 );
     begin
       Mantissa_Tmp := Mantissa ( InFloat );
       Mantissa_Str ( 1 ) := '.';
       for index in 2..Mantissa_Str'last loop
      Mantissa_Tmp := Mantissa ( Mantissa_Tmp ) * 10.0;
      Mantissa_Str ( index ) := StriAK.Image
	( MathAKD.Characteristic ( Mantissa_Tmp ),
	Signed => false ) ( 1 );
       end loop;
       return Mantissa_Str;
     exception
       when others =>
      ErroAKD.Notify ( "MathAKD.Mantissa ( float ) return string" );
      raise;
     end Mantissa;

     function Pos (
       X : in float )
       return float is
     ---------------------------------------------------------------------------
     -- Returns X if it is positive, returns 0.0 otherwise.
     ---------------------------------------------------------------------------
     begin
       if X > 0.0 then
      return X;
       else
      return 0.0;
       end if;
     end Pos;

     function Factorial (
       X : in natural )
       return float is
     ---------------------------------------------------------------------------
       Result : float := 1.0;
     begin
       for index in 1..X loop
      Result := Result * float ( index );
       end loop;
       return Result;
     exception
       when constraint_error =>
      ErroAKD.Notify ( "MathAKD.Factorial", "Constraint_Error" );
      raise;
       when numeric_error =>
      ErroAKD.Notify ( "MathAKD.Factorial", "Numeric_Error" );
      raise;
     end Factorial;

     function Sigmoid (
	     InFloat  : in float;
	     Reversed : in boolean := false )
	     return float is
     ---------------------------------------------------------------------------
     --  Input :          - Infinity         0.0        + Infinity
     --  Output:              0.0            0.5            1.0
     ---------------------------------------------------------------------------
     begin
       if Reversed then
      return - Ln ( ( 1.0 / InFloat ) - 1.0 );
       else
      return ( 1.0 / ( 1.0 + ( Exp ( - InFloat ) ) ) );
       end if;
     end Sigmoid;

     function  Sign ( InFloat: in float ) return float is
     ---------------------------------------------------------------------------
     -- Zero will return as a positive.
     ---------------------------------------------------------------------------
     begin
       if InFloat >= 0.0 then
      return +1.0;
       else
      return -1.0;
       end if;
     end Sign;

     function  Tanh ( X :  in float ) return float is
     ---------------------------------------------------------------------------
     --  Input :          - Infinity         0.0        + Infinity
     --  Output:             -1.0            0.0            1.0
     ---------------------------------------------------------------------------
     begin
       return ( Exp ( X ) - Exp ( -X ) ) / ( Exp ( X ) + Exp ( -X ) );
     end Tanh;

     ---------------------------------------------------------------------------
     ---------------------------------------------------------------------------
     end MathAKD;
