/* This file quad_double_functions.h defines the arithmetical operations
   for quad double numbers.  A quad double is defined by four doubles.

The naming of the four doubles in a quad double is hihi, lohi, hilo, lolo,
listed in decreasing order of significance.

The algorithms are from the CAMPARY and QD software libraries with the 
modification that a quad double is not stored as an array of four doubles, 
but plainly by four double numbers.
All functions have the prefix qdf_ to avoid name clashes. */

#ifndef __quad_double_functions_h__
#define __quad_double_functions_h__

/************************* renormalizations **************************/

void qdf_renorm4
 ( double f0, double f1, double f2, double f3, double f4,
   double *pr, double *r0, double *r1, double *r2, double *r3 );
/*
 * DESCRIPTION :
 *   Definitions common to fast_renorm2L<5,4> and renorm2L_4Add1<4,4>
 *   from code of the specRenorm.h, generated by the CAMPARY library,
 *   in an unrolled form (Valentina Popescu, Mioara Joldes), with
 *   double double basics of QD-2.3.9 (Y. Hida, X.S. Li, and D.H. Bailey).
 *
 * ON ENTRY :
 *   f0       most significant word;
 *   f1       second most significant word;
 *   f2       third most significant word;
 *   f3       fourth most significant word;
 *   f4       fifth most significant word;
 *   pr       computed by the start of the renormalization.
 *
 * ON RETURN :
 *   pr       updated value by renormalization;
 *   r0       highest part of a quad double number;
 *   r1       second highest part of a quad double number;
 *   r2       second lowest part of a quad double number.
 *   r4       lowest part of a quad double number. */

void qdf_fast_renorm
 ( double x0, double x1, double x2, double x3, double x4,
   double *r0, double *r1, double *r2, double *r3 );
/*
 * DESCRIPTION :
 *   The definition is based on the fast_renorm2L<5,4>,
 *   from code of the specRenorm.h, generated by the CAMPARY library,
 *   in an unrolled form (Valentina Popescu, Mioara Joldes), with
 *   double double basics of QD-2.3.9 (Y. Hida, X.S. Li, and D.H. Bailey).
 *
 * ON ENTRY :
 *   x0       most significant word;
 *   x1       second most significant word;
 *   x2       third most significant word;
 *   x3       fourth most significant word;
 *   x4       least significant word.
 *
 * ON RETURN :
 *   r0       highest part of a quad double number;
 *   r1       second highest part of a quad double number;
 *   r2       second lowest part of a quad double number;
 *   r3       lowest part of a quad double number. */

void qdf_renorm_add1
 ( double x0, double x1, double x2, double x3, double y,
   double *r0, double *r1, double *r2, double *r3 );
/*
 * DESCRIPTION :
 *   The definition is based on the renorm2L_4Add1<4,4>,
 *   from code of the specRenorm.h, generated by the CAMPARY library,
 *   in an unrolled form (Valentina Popescu, Mioara Joldes), with
 *   double double basics of QD-2.3.9 (Y. Hida, X.S. Li, and D.H. Bailey).
 *
 * ON ENTRY :
 *   x0       most significant word of a quad double x;
 *   x1       second most significant word of a quad double x;
 *   x2       third most significant word of a quad double x;
 *   x3       least significant word of a quad double x;
 *   y        double to be added to x.
 *
 * ON RETURN :
 *   r0       highest part of x + y;
 *   r1       second highest part of x + y;
 *   r2       second lowest part of x + y;
 *   r3       lowest part of x + y. */

/************************ copy and abs *******************************/

void qdf_copy
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double *b_hihi, double *b_lohi, double *b_hilo, double *b_lolo );
/*
 * DESCRIPTION :
 *   Copies the quad double a (a_hihi, a_lohi, a_hilo, a_lolo)
 *   to the quad double b (b_hihi, b_lohi, b_hilo, b_lolo). */

void qdf_abs
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double *b_hihi, double *b_lohi, double *b_hilo, double *b_lolo );
/*
 * DESCRIPTION :
 *   Returns in b the absolute value of a. */

/****************** additions and subtractions ************************/

void qdf_add
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double b_hihi, double b_lohi, double b_hilo, double b_lolo,
   double *c_hihi, double *c_lohi, double *c_hilo, double *c_lolo );
/*
 * DESCRIPTION : c = a + b.
 *   Adds two quad doubles a (a_hihi, a_lohi, a_hilo, a_lolo)
 *   and b (b_hihi, b_lohi, b_hilo, b_lolo)
 *   to make the quad double c (c_hihi, c_lohi, c_hilo, c_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b_hihi   the highest part of the quad double b;
 *   b_lohi   the second highest part of the quad double b;
 *   b_hilo   the third highest part of the quad double b;
 *   b_lolo   the fourth highest part of the quad double b.
 *
 * ON RETURN :
 *   c_hihi   the highest part of the quad double c = a + b;
 *   c_lohi   the second highest part of the quad double c = a + b;
 *   c_hilo   the third highest part of the quad double c = a + b;
 *   c_lolo   the fourth highest part of the quad double c = a + b. */

void qdf_inc
 ( double *a_hihi, double *a_lohi, double *a_hilo, double *a_lolo,
   double b_hihi, double b_lohi, double b_hilo, double b_lolo );
/*
 * DESCRIPTION : a = a + b.
 *   Adds to the quad double a (a_hihi, a_lohi, a_hilo, a_lolo)
 *   the quad double b (b_hihi, b_lohi, b_hilo, b_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b_hihi   the highest part of the quad double b;
 *   b_lohi   the second highest part of the quad double b;
 *   b_hilo   the third highest part of the quad double b;
 *   b_lolo   the fourth highest part of the quad double b.
 *
 * ON RETURN :
 *   a_hihi   the highest part of the quad double a + b;
 *   a_lohi   the second highest part of the quad double a + b;
 *   a_hilo   the third highest part of the quad double a + b;
 *   a_lolo   the fourth highest part of the quad double a + b. */

void qdf_inc_d
 ( double *a_hihi, double *a_lohi, double *a_hilo, double *a_lolo,
   double b );
/*
 * DESCRIPTION : a = a + b.
 *   Adds the double b 
 *   to the quad double a (a_hihi, a_lohi, a_hilo, a_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b        some double.
 *
 * ON RETURN :
 *   a_hihi   the highest part of the quad double a + b;
 *   a_lohi   the second highest part of the quad double a + b;
 *   a_hilo   the third highest part of the quad double a + b;
 *   a_lolo   the fourth highest part of the quad double a + b. */

void qdf_dec
 ( double *a_hihi, double *a_lohi, double *a_hilo, double *a_lolo,
   double b_hihi, double b_lohi, double b_hilo, double b_lolo );
/*
 * DESCRIPTION : a = a - b.
 *   Inplace decrement of the quad double a (a_hihi, a_lohi, a_hilo, a_lolo)
 *   with the quad double in b (b_hihi, b_lohi, b_hilo, b_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b_hihi   the highest part of the quad double b;
 *   b_lohi   the second highest part of the quad double b;
 *   b_hilo   the third highest part of the quad double b;
 *   b_lolo   the fourth highest part of the quad double b.
 *
 * ON RETURN :
 *   a_hihi   the highest part of the quad double a - b;
 *   a_lohi   the second highest part of the quad double a - b;
 *   a_hilo   the third highest part of the quad double a - b;
 *   a_lolo   the fourth highest part of the quad double a - b. */

void qdf_minus
 ( double *a_hihi, double *a_lohi, double *a_hilo, double *a_lolo );
/*
 * DESCRIPTION :
 *   Flips the sign of a (a_hihi, a_lohi, a_hilo, a_lolo). */

void qdf_sub
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double b_hihi, double b_lohi, double b_hilo, double b_lolo,
   double *c_hihi, double *c_lohi, double *c_hilo, double *c_lolo );
/*
 * DESCRIPTION : c = a - b.
 *   Subtracts the quad double b (b_hihi, b_lohi, b_hilo, b_lolo)
 *   from the quad double in a (a_hihi, a_lohi, a_hilo, a_lolo)
 *   and places the result in c (c_hihi, c_lohi, c_hilo, c_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b_hihi   the highest part of the quad double b;
 *   b_lohi   the second highest part of the quad double b;
 *   b_hilo   the third highest part of the quad double b;
 *   b_lolo   the fourth highest part of the quad double b;
 *
 * ON RETURN :
 *   c_hihi   the highest part of the quad double c = a - b;
 *   c_lohi   the second highest part of the quad double c = a - b;
 *   c_hilo   the third highest part of the quad double c = a - b;
 *   c_lolo   the fourth highest part of the quad double c = a - b. */

/***************** multiplications and division ********************/

void qdf_mul_pwr2
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo, double b,
   double *c_hihi, double *c_lohi, double *c_hilo, double *c_lolo );
/*
 * DESCRIPTION : c = a * b, where b is a power of two.
 *   As b is a power of two, all components of the quad double
 *   are plainly multiplied by b.
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the second lowest part of the quad double a;
 *   a_lolo   the lowest part of the quad double a;
 *   b        a power of two.
 *
 * ON RETURN :
 *   c_hihi   the highest part of the quad double c = a * b;
 *   c_lohi   the second highest part of the quad double c = a * b;
 *   c_hihi   the second lowest part of the quad double c = a * b;
 *   c_lolo   the lowest part of the quad double c = a * b. */

void qdf_mul
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double b_hihi, double b_lohi, double b_hilo, double b_lolo,
   double *c_hihi, double *c_lohi, double *c_hilo, double *c_lolo );
/*
 * DESCRIPTION : c = a * b.
 *   Multiplies two quad doubles a (a_hihi, a_lohi, a_hilo, a_lolo)
 *   and b (b_hihi, b_lohi, b_hilo, b_lolo) to make the quad double
 *   c (c_hihi, c_lohi, c_hilo, c_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b_hihi   the highest part of the quad double b;
 *   b_lohi   the second highest part of the quad double b;
 *   b_hilo   the third highest part of the quad double b;
 *   b_lolo   the fourth highest part of the quad double b.
 *
 * ON RETURN :
 *   c_hihi   the highest part of the quad double c = a * b;
 *   c_lohi   the second highest part of the quad double c = a * b;
 *   c_hilo   the third highest part of the quad double c = a * b;
 *   c_lolo   the fourth highest part of the quad double c = a * b. */

void qdf_sqr
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double *c_hihi, double *c_lohi, double *c_hilo, double *c_lolo );
/*
 * DESCRIPTION : c = a * a.
 *   Multiplies the quad double a (a_hihi, a_lohi, a_hilo, a_lolo)
 *   with a to make the quad double c (c_hihi, c_lohi, c_hilo, c_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a.
 *
 * ON RETURN :
 *   c_hihi   the highest part of the quad double c = a * a;
 *   c_lohi   the second highest part of the quad double c = a * a;
 *   c_hilo   the third highest part of the quad double c = a * a;
 *   c_lolo   the fourth highest part of the quad double c = a * a. */

void qdf_mul_qd_d
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double b,
   double *c_hihi, double *c_lohi, double *c_hilo, double *c_lolo );
/*
 * DESCRIPTION : c = a * b.
 *   Multiplies the quad double a (a_hihi, a_lohi, a_hilolo, a_lolo)
 *   with b to make the quad double c (c_hihi, c_lohi, c_hihlolo, c_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b        some double.
 *
 * ON RETURN :
 *   c_hihi   the highest part of the quad double c = a * b;
 *   c_lohi   the second highest part of the quad double c = a * b;
 *   c_hilo   the third highest part of the quad double c = a * b;
 *   c_lolo   the fourth highest part of the quad double c = a * b. */

void qdf_mlt_d
 ( double *a_hihi, double *a_lohi, double *a_hilo, double *a_lolo,
   double b );
/*
 * DESCRIPTION : a = a * b.
 *   Inplace multiplication of the quad double a (a_hihi, a_lohi,
 *   a_hilo, a_lolo) with the double b.
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b        some double.
 *
 * ON RETURN :
 *   a_hihi   the highest part of the quad double a = a * b;
 *   a_lohi   the second highest part of the quad double a = a * b;
 *   a_hilo   the third highest part of the quad double a = a * b;
 *   a_lolo   the fourth highest part of the quad double a = a * b. */

void qdf_div
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double b_hihi, double b_lohi, double b_hilo, double b_lolo,
   double *c_hihi, double *c_lohi, double *c_hilo, double *c_lolo );
/*
 * DESCRIPTION : c = a / b.
 *   Divides the quad double a (a_hihi, a_lohi, a_hilolo, a_lolo)
 *   by the quad double b (b_hihi, b_lohi, b_hilo, b_lolo)
 *   to make the quad double c (c_hihi, c_lohi, c_hilo, c_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the third highest part of the quad double a;
 *   a_lolo   the fourth highest part of the quad double a;
 *   b_hihi   the highest part of the quad double b;
 *   b_lohi   the second highest part of the quad double b;
 *   b_hilo   the third highest part of the quad double b;
 *   b_lolo   the fourth highest part of the quad double b.
 *
 * ON RETURN :
 *   c_hihi   the highest part of the quad double c = a / b;
 *   c_lohi   the second highest part of the quad double c = a / b;
 *   c_hilo   the third highest part of the quad double c = a / b;
 *   c_lolo   the fourth highest part of the quad double c = a / b. */

/***************************** square root *****************************/

void qdf_sqrt
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo,
   double *b_hihi, double *b_lohi, double *b_hilo, double *b_lolo );
/*
 * DESCRIPTION :
 *   Returns in the quad double b (b_hihi, b_lohi, b_hilo, b_lolo) 
 *   the square root of the quad double a (a_hihi, a_lohi, a_hilo, a_lolo).
 *
 * ON ENTRY :
 *   a_hihi   the highest part of the quad double a;
 *   a_lohi   the second highest part of the quad double a;
 *   a_hilo   the second lowest part of the quad double a;
 *   a_lolo   the lowest part of the quad double a.
 *
 * ON RETURN :
 *   b_hihi   the highest part of the quad double b;
 *   b_lohi   the second highest part of the quad double b;
 *   b_hilo   the second lowest part of the quad double b;
 *   b_lolo   the lowest part of the quad double b. */

/*************************** basic output ***************************/

void qdf_write_doubles
 ( double a_hihi, double a_lohi, double a_hilo, double a_lolo );
/*
 * DESCRIPTION :
 *   Writes the four doubles (a_hihi, a_lohi, a_hilo, a_lolo) of the 
 *   quad double a in scientific format with 16 decimal places. */

#endif
