with Standard_Natural_Numbers;           use Standard_Natural_Numbers;
with Standard_Integer_Numbers;           use Standard_Integer_Numbers;
with Standard_Floating_Numbers;          use Standard_Floating_Numbers;
with Double_Double_Numbers;              use Double_Double_Numbers;
with Triple_Double_Numbers;              use Triple_Double_Numbers;
with Quad_Double_Numbers;                use Quad_Double_Numbers;
with Penta_Double_Numbers;               use Penta_Double_Numbers;
with Octo_Double_Numbers;                use Octo_Double_Numbers;
with Deca_Double_Numbers;                use Deca_Double_Numbers;

package Hexa_Double_Numbers is

-- DESCRIPTION :
--   This package defines hexa double numbers and the arithmetic
--   to obtain 16 times the precision of the (standard hardware) doubles.

-- ACKNOWLEDGEMENTS :
--   The code is based on QD-2.3.9 (Y. Hida, X.S. Li, and D.H. Bailey),
--   for the parallels with double double and quad double arithmetic.
--   Definitions are based on the code generated by the CAMPARY library.
--   CAMPARY is the CudA Multiple Precision ARithmetic librarY,
--   by Mioara Joldes, Olivier Marty, Jean-Michel Muller,
--   Valentina Popescu and Warwick Tucker. 

  type hexa_double is private;

-- CONSTRUCTORS :

  function create ( i : integer ) return hexa_double;

  -- DECRIPTION :
  --   Returns the hexa double representation of the standard integer i.

  function create ( n : natural32 ) return hexa_double;
  function create ( n : natural64 ) return hexa_double;

  -- DESCRIPTION :
  --   Returns the hexa double representation of the 32-bit or 64-bit
  --   machine natural number n.

  function create ( i : integer32 ) return hexa_double;
  function create ( i : integer64 ) return hexa_double;

  -- DESCRIPTION :
  --   Returns the hexa double representation of the 32-bit or 64-bit
  --   machine integer number i.

  function create ( x : double_float ) return hexa_double;

  -- DESCRIPTION :
  --   The highest word in the hexa double on return is x.

  function create ( hihihihi,lohihihi,hilohihi,lolohihi : double_float;
                    hihilohi,lohilohi,hilolohi,lololohi : double_float;
                    hihihilo,lohihilo,hilohilo,lolohilo : double_float;
                    hihilolo,lohilolo,hilololo,lolololo : double_float )
                  return hexa_double;

  -- DESCRIPTION :
  --   Returns an hexa double with the doubles in the given order.
  --   The highest, most significant part is given in hihihihi.
  --   The lowest, least significant part is given in lolololo.

  function "abs" ( x : hexa_double ) return hexa_double;

  -- DESCRIPTION :
  --   Returns the absolute value of x.

  function AbsVal ( x : hexa_double ) return hexa_double; -- same as abs

  function floor ( x : hexa_double ) return hexa_double;

  -- DESCRIPTION :
  --   Returns nearest lower integer to x.

  function nint ( x : hexa_double ) return hexa_double;

  -- DESCRIPTION :
  --   Returns the nearest integer to x.

-- SELECTORS :

  function hihihihi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the most significant double of x.

  function lohihihi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the second most significant double of x.

  function hilohihi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the third most significant double of x.

  function lolohihi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the fourth most significant double of x.

  function hihilohi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the fifth least significant double of x.

  function lohilohi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the sixth least significant double of x.

  function hilolohi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the seventh least significant double of x.

  function lololohi_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the eighth significant double of x.

  function hihihilo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the eighth least significant double of x.

  function lohihilo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the seventh least significant double of x.

  function hilohilo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the sixth least significant double of x.

  function lolohilo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the fifth least significant double of x.

  function hihilolo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the fourth least significant double of x.

  function lohilolo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the third least significant double of x.

  function hilololo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the second least significant double of x.

  function lolololo_part ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns the least significant double of x.

-- TYPE CASTS :

  function to_int ( x : hexa_double ) return integer32;

  -- DESCRIPTION :
  --   Converts the highest word into a 32-bit integer;

  function to_double ( x : hexa_double ) return double_float;

  -- DESCRIPTION :
  --   Returns hihihi_part(x).

  function to_double_double ( x : hexa_double ) return double_double;

  -- DESCRIPTION :
  --   Returns the double double with the first two significant
  --   doubles of x.

  function to_triple_double ( x : hexa_double ) return triple_double;

  -- DESCRIPTION :
  --   Returns the double double with the first three significant
  --   doubles of x.

  function to_quad_double ( x : hexa_double ) return quad_double;

  -- DESCRIPTION :
  --   Returns the double double with the first four significant
  --   doubles of x.

  function to_penta_double ( x : hexa_double ) return penta_double;

  -- DESCRIPTION :
  --   Returns the double double with the first five significant
  --   doubles of x.

  function to_octo_double ( x : hexa_double ) return octo_double;

  -- DESCRIPTION :
  --   Returns the double double with the first eight significant
  --   doubles of x.

  function to_deca_double ( x : hexa_double ) return deca_double;

  -- DESCRIPTION :
  --   Returns the double double with the first ten significant
  --   doubles of x.

-- COMPARISON and COPYING :

  function is_zero ( x : hexa_double ) return boolean;

  -- DESCRIPTION :
  --   Returns true if x is zero, returns false otherwise.

  function is_one ( x : hexa_double ) return boolean;

  -- DESCRIPTION :
  --   Returns true if x is one, returns false otherwise.

  function is_positive ( x : hexa_double ) return boolean;

  -- DESCRIPTION : 
  --   Returns true if x is positive, returns false otherwise.

  function is_negative ( x : hexa_double ) return boolean;

  -- DESCRIPTION : 
  --   Returns true if x is negative, returns false otherwise.

  function equal ( x,y : hexa_double ) return boolean;
  function equal ( x : hexa_double; y : double_float ) return boolean;

  function "<" ( x,y : hexa_double ) return boolean;
  function "<" ( x : hexa_double; y : double_float ) return boolean;
  function "<" ( x : double_float; y : hexa_double ) return boolean;
  function "<=" ( x,y : hexa_double ) return boolean;
  function "<=" ( x : hexa_double; y : double_float ) return boolean;
  function "<=" ( x : double_float; y : hexa_double ) return boolean;

  function ">" ( x,y : hexa_double ) return boolean;
  function ">" ( x : hexa_double; y : double_float ) return boolean;
  function ">" ( x : double_float; y : hexa_double ) return boolean;
  function ">=" ( x,y : hexa_double ) return boolean;
  function ">=" ( x : hexa_double; y : double_float ) return boolean;
  function ">=" ( x : double_float; y : hexa_double ) return boolean;

  procedure copy ( x : in hexa_double; y : in out hexa_double );

-- ARITHMETICAL OPERATIONS :

  function "+" ( x,y : hexa_double ) return hexa_double;   -- returns x+y
  function "+" ( x : hexa_double; y : double_float ) return hexa_double;
  function "+" ( x : double_float; y : hexa_double ) return hexa_double;
  function "+" ( x : hexa_double ) return hexa_double;     -- returns copy

  function "-" ( x : hexa_double ) return hexa_double;     -- returns -x
  function "-" ( x,y : hexa_double ) return hexa_double;   -- returns x-y
  function "-" ( x : hexa_double; y : double_float ) return hexa_double;
  function "-" ( x : double_float; y : hexa_double ) return hexa_double;

  function "*" ( x,y : hexa_double ) return hexa_double;   -- returns x*y
  function "*" ( x : hexa_double; y : double_float ) return hexa_double;
  function "*" ( x : double_float; y : hexa_double ) return hexa_double;

  function Mul_pwr2 ( x : hexa_double; y : double_float ) -- y = 2^k
                    return hexa_double;
  procedure Mul_pwr2 ( x : in out hexa_double; y : in double_float );
  -- multiplies x with y, where y is a power of 2

  function "/" ( x,y : hexa_double ) return hexa_double;   -- returns x/y
  function "/" ( x : hexa_double; y : double_float ) return hexa_double;
  function "/" ( x : double_float; y : hexa_double ) return hexa_double;

  function sqr ( x : hexa_double ) return hexa_double;     -- returns x*x
  function "**" ( x : hexa_double; n : integer ) return hexa_double; -- x^n

  function ldexp ( x : hexa_double; n : integer ) return hexa_double;
  -- returns (2^n)*x
  function "**" ( x,y : hexa_double ) return hexa_double; -- x^y
  function "**" ( x : hexa_double; y : double_float ) return hexa_double;

  function exp ( x : hexa_double ) return hexa_double;   -- returns exp(x)
  function log ( x : hexa_double ) return hexa_double;   -- natural log
  function log10 ( x : hexa_double ) return hexa_double; -- decimal log

-- ARITHMETICAL OPERATIONS AS PROCEDURES :

  procedure Add ( x : in out hexa_double; y : in hexa_double ); -- x := x+y
  procedure Sub ( x : in out hexa_double; y : in hexa_double ); -- x := x-y
  procedure Min ( x : in out hexa_double );                     -- x:= -x
  procedure Mul ( x : in out hexa_double; y : in hexa_double ); -- x := x*y
  procedure Div ( x : in out hexa_double; y : in hexa_double ); -- x := x/y

-- DESTRUCTOR :

  procedure clear ( x : in out hexa_double ); -- sets x to zero

private

-- DATA STRUCTURE :
--   An hexa double could be viewed as a double octo double number,
--   or a octo double double number.  The naming of the parts of an
--   hexa double is consistent with replacing the four doubles of a
--   quad double (called hihi, lohi, hilo, and lolo) by double doubles,
--   each with a high and low part.  The high and low part are used to
--   prefix the new names, so the lohi has parts hilohi and lolohi.
--   The first eight highest parts all have hi as suffix,
--   the last eight lowest parts all have lo as suffix.
--   The eight parts of an hexa double are eight doubles in a record.
--   In a corresponding array data type they would be named 
--   x0, x1, x2, .., x15 in order of significance.

  type hexa_double is record
    hihihihi : double_float; -- highest word, most significant double
    lohihihi : double_float; -- second highest word
    hilohihi : double_float; -- third highest word
    lolohihi : double_float; -- fourth highest word
    hihilohi : double_float; -- fifth lowest word
    lohilohi : double_float; -- sixth lowest word
    hilolohi : double_float; -- seventh lowest word
    lololohi : double_float; -- eighth hightest word
    hihihilo : double_float; -- eighth lowest word
    lohihilo : double_float; -- seventh lowest word
    hilohilo : double_float; -- sixth lowest word
    lolohilo : double_float; -- fifth lowest word
    hihilolo : double_float; -- fourth lowest word
    lohilolo : double_float; -- third lowest word
    hilololo : double_float; -- second lowest word
    lolololo : double_float; -- lowest word, least significant double
  end record;

end Hexa_Double_Numbers;
