/* Copyright (C) 2007  Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.

In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file.  (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combine
executable.)

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to the Free
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.  */

/*****************************************************************************
 * 
 *  BID128 fma   x * y + z
 * 
 ****************************************************************************/

#include "bid_internal.h"

static void
rounding_correction (unsigned int rnd_mode,
        	     unsigned int is_inexact_lt_midpoint,
        	     unsigned int is_inexact_gt_midpoint,
        	     unsigned int is_midpoint_lt_even,
        	     unsigned int is_midpoint_gt_even,
        	     int unbexp,
        	     UINT128 * ptrres, _IDEC_flags * ptrfpsf) {
  // unbiased true exponent unbexp may be larger than emax

  UINT128 res = *ptrres; // expected to have the correct sign and coefficient
  // (the exponent field is ignored, as unbexp is used instead)
  UINT64 sign, exp;
  UINT64 C_hi, C_lo;

  // general correction from RN to RA, RM, RP, RZ
  // Note: if the result is negative, then is_inexact_lt_midpoint, 
  // is_inexact_gt_midpoint, is_midpoint_lt_even, and is_midpoint_gt_even 
  // have to be considered as if determined for the absolute value of the 
  // result (so they seem to be reversed)

  if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
      is_midpoint_lt_even || is_midpoint_gt_even) {
    *ptrfpsf |= INEXACT_EXCEPTION;
  }
  // apply correction to result calculated with unbounded exponent
  sign = res.w[1] & MASK_SIGN;
  exp = (UINT64) (unbexp + 6176) << 49; // valid only if expmin<=unbexp<=expmax
  C_hi = res.w[1] & MASK_COEFF;
  C_lo = res.w[0];
  if ((!sign && ((rnd_mode == ROUNDING_UP && is_inexact_lt_midpoint) ||
      ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_UP) && 
      is_midpoint_gt_even))) || 
      (sign && ((rnd_mode == ROUNDING_DOWN && is_inexact_lt_midpoint) ||
      ((rnd_mode == ROUNDING_TIES_AWAY || rnd_mode == ROUNDING_DOWN) && 
      is_midpoint_gt_even)))) {
    // C = C + 1
    C_lo = C_lo + 1;
    if (C_lo == 0)
      C_hi = C_hi + 1;
    if (C_hi == 0x0001ed09bead87c0ull && C_lo == 0x378d8e6400000000ull) {
      // C = 10^34 => rounding overflow
      C_hi = 0x0000314dc6448d93ull;
      C_lo = 0x38c15b0a00000000ull; // 10^33
      // exp = exp + EXP_P1;
      unbexp = unbexp + 1;
      exp = (UINT64) (unbexp + 6176) << 49;
    }
  } else if ((is_midpoint_lt_even || is_inexact_gt_midpoint) &&
      ((sign && (rnd_mode == ROUNDING_UP || rnd_mode == ROUNDING_TO_ZERO)) ||
      (!sign && (rnd_mode == ROUNDING_DOWN || rnd_mode == ROUNDING_TO_ZERO)))) {
    // C = C - 1
    C_lo = C_lo - 1;
    if (C_lo == 0xffffffffffffffffull)
      C_hi--;
    // check if we crossed into the lower decade
    if (C_hi == 0x0000314dc6448d93ull && C_lo == 0x38c15b09ffffffffull) { 
      // C = 10^33 - 1
      if (exp > 0) {
        C_hi = 0x0001ed09bead87c0ull; // 10^34 - 1
        C_lo = 0x378d8e63ffffffffull;
        // exp = exp - EXP_P1;
        unbexp = unbexp - 1;
        exp = (UINT64) (unbexp + 6176) << 49;
      } else { // if exp = 0
        if (is_midpoint_lt_even || is_midpoint_lt_even ||
            is_inexact_gt_midpoint || is_inexact_gt_midpoint) // tiny & inexact
          *ptrfpsf |= UNDERFLOW_EXCEPTION;
      }
    }
  } else {
    ; // the result is already correct
  }
  if (unbexp > expmax) { // 6111
    *ptrfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
    exp = 0;
    if (!sign) { // result is positive
      if (rnd_mode == ROUNDING_UP || rnd_mode == ROUNDING_TIES_AWAY) { // +inf
        C_hi = 0x7800000000000000ull;
        C_lo = 0x0000000000000000ull;
      } else { // res = +MAXFP = (10^34-1) * 10^emax
        C_hi = 0x5fffed09bead87c0ull;
        C_lo = 0x378d8e63ffffffffull;
      }
    } else { // result is negative
      if (rnd_mode == ROUNDING_DOWN || rnd_mode == ROUNDING_TIES_AWAY) { // -inf
        C_hi = 0xf800000000000000ull;
        C_lo = 0x0000000000000000ull;
      } else { // res = -MAXFP = -(10^34-1) * 10^emax
        C_hi = 0xdfffed09bead87c0ull;
        C_lo = 0x378d8e63ffffffffull;
      }
    }
  }
  // assemble the result
  res.w[1] = sign | exp | C_hi;
  res.w[0] = C_lo;
  *ptrres = res;
}

static void
add256 (UINT256 x, UINT256 y, UINT256 * pz) {
  // *z = x + yl assume the sum fits in 256 bits
  UINT256 z;
  z.w[0] = x.w[0] + y.w[0];
  if (z.w[0] < x.w[0]) {
    x.w[1]++;
    if (x.w[1] == 0x0000000000000000ull) {
      x.w[2]++;
      if (x.w[2] == 0x0000000000000000ull) {
        x.w[3]++;
      }
    }
  }
  z.w[1] = x.w[1] + y.w[1];
  if (z.w[1] < x.w[1]) {
    x.w[2]++;
    if (x.w[2] == 0x0000000000000000ull) {
      x.w[3]++;
    }
  }
  z.w[2] = x.w[2] + y.w[2];
  if (z.w[2] < x.w[2]) {
    x.w[3]++;
  }
  z.w[3] = x.w[3] + y.w[3]; // it was assumed that no carry is possible
  *pz = z;
}

static void
sub256 (UINT256 x, UINT256 y, UINT256 * pz) {
  // *z = x - y; assume x >= y
  UINT256 z;
  z.w[0] = x.w[0] - y.w[0];
  if (z.w[0] > x.w[0]) {
    x.w[1]--;
    if (x.w[1] == 0xffffffffffffffffull) {
      x.w[2]--;
      if (x.w[2] == 0xffffffffffffffffull) {
        x.w[3]--;
      }
    }
  }
  z.w[1] = x.w[1] - y.w[1];
  if (z.w[1] > x.w[1]) {
    x.w[2]--;
    if (x.w[2] == 0xffffffffffffffffull) {
      x.w[3]--;
    }
  }
  z.w[2] = x.w[2] - y.w[2];
  if (z.w[2] > x.w[2]) {
    x.w[3]--;
  }
  z.w[3] = x.w[3] - y.w[3]; // no borrow possible, because x >= y
  *pz = z;
}


static int
nr_digits256 (UINT256 R256) {
  int ind;
  // determine the number of decimal digits in R256
  if (R256.w[3] == 0x0 && R256.w[2] == 0x0 && R256.w[1] == 0x0) {
    // between 1 and 19 digits
    for (ind = 1; ind <= 19; ind++) {
      if (R256.w[0] < ten2k64[ind]) {
        break;
      }
    }
    // ind digits
  } else if (R256.w[3] == 0x0 && R256.w[2] == 0x0 &&
             (R256.w[1] < ten2k128[0].w[1] ||
              (R256.w[1] == ten2k128[0].w[1]
               && R256.w[0] < ten2k128[0].w[0]))) {
    // 20 digits
    ind = 20;
  } else if (R256.w[3] == 0x0 && R256.w[2] == 0x0) {
    // between 21 and 38 digits
    for (ind = 1; ind <= 18; ind++) {
      if (R256.w[1] < ten2k128[ind].w[1] ||
          (R256.w[1] == ten2k128[ind].w[1] &&
           R256.w[0] < ten2k128[ind].w[0])) {
        break;
      }
    }
    // ind + 20 digits
    ind = ind + 20;
  } else if (R256.w[3] == 0x0 &&
             (R256.w[2] < ten2k256[0].w[2] ||
              (R256.w[2] == ten2k256[0].w[2] &&
               R256.w[1] < ten2k256[0].w[1]) ||
              (R256.w[2] == ten2k256[0].w[2] &&
               R256.w[1] == ten2k256[0].w[1] &&
               R256.w[0] < ten2k256[0].w[0]))) {
    // 39 digits
    ind = 39;
  } else {
    // between 40 and 68 digits
    for (ind = 1; ind <= 29; ind++) {
      if (R256.w[3] < ten2k256[ind].w[3] ||
          (R256.w[3] == ten2k256[ind].w[3] &&
           R256.w[2] < ten2k256[ind].w[2]) ||
          (R256.w[3] == ten2k256[ind].w[3] &&
           R256.w[2] == ten2k256[ind].w[2] &&
           R256.w[1] < ten2k256[ind].w[1]) ||
          (R256.w[3] == ten2k256[ind].w[3] &&
           R256.w[2] == ten2k256[ind].w[2] &&
           R256.w[1] == ten2k256[ind].w[1] &&
           R256.w[0] < ten2k256[ind].w[0])) {
        break;
      }
    }
    // ind + 39 digits
    ind = ind + 39;
  }
  return (ind);
}

// add/subtract C4 and C3 * 10^scale; this may follow a previous rounding, so
// use the rounding information from ptr_is_* to avoid a double rounding error
static void
add_and_round (int q3,
               int q4,
               int e4,
               int delta,
               int p34,
               UINT64 z_sign,
               UINT64 p_sign,
               UINT128 C3,
               UINT256 C4,
               int rnd_mode,
               int *ptr_is_midpoint_lt_even,
               int *ptr_is_midpoint_gt_even,
               int *ptr_is_inexact_lt_midpoint,
               int *ptr_is_inexact_gt_midpoint,
               _IDEC_flags * ptrfpsf, UINT128 * ptrres) {

  int scale;
  int x0;
  int ind;
  UINT64 R64;
  UINT128 P128, R128;
  UINT192 P192, R192;
  UINT256 R256;
  int is_midpoint_lt_even = 0;
  int is_midpoint_gt_even = 0;
  int is_inexact_lt_midpoint = 0;
  int is_inexact_gt_midpoint = 0;
  int is_midpoint_lt_even0 = 0;
  int is_midpoint_gt_even0 = 0;
  int is_inexact_lt_midpoint0 = 0;
  int is_inexact_gt_midpoint0 = 0;
  int incr_exp = 0;
  int is_tiny = 0;
  int lt_half_ulp = 0;
  int eq_half_ulp = 0;
  // int gt_half_ulp = 0;
  UINT128 res = *ptrres;

  // scale C3 up by 10^(q4-delta-q3), 0 <= q4-delta-q3 <= 2*P34-2 = 66
  scale = q4 - delta - q3; // 0 <= scale <= 66 (or 0 <= scale <= 68 if this
  // comes from Cases (2), (3), (4), (5), (6), with 0 <= |delta| <= 1

  // calculate C3 * 10^scale in R256 (it has at most 67 decimal digits for
  // Cases (15),(16),(17) and at most 69 for Cases (2),(3),(4),(5),(6))
  if (scale == 0) {
    R256.w[3] = 0x0ull;
    R256.w[2] = 0x0ull;
    R256.w[1] = C3.w[1];
    R256.w[0] = C3.w[0];
  } else if (scale <= 19) { // 10^scale fits in 64 bits
    P128.w[1] = 0;
    P128.w[0] = ten2k64[scale];
    __mul_128x128_to_256 (R256, P128, C3);
  } else if (scale <= 38) { // 10^scale fits in 128 bits
    __mul_128x128_to_256 (R256, ten2k128[scale - 20], C3);
  } else if (scale <= 57) { // 39 <= scale <= 57 
    // 10^scale fits in 192 bits but C3 * 10^scale fits in 223 or 230 bits
    // (10^67 has 223 bits; 10^69 has 230 bits);  
    // must split the computation:  
    // 10^scale * C3 = 10*38 * 10^(scale-38) * C3 where 10^38 takes 127
    // bits and so 10^(scale-38) * C3 fits in 128 bits with certainty
    // Note that 1 <= scale - 38 <= 19 => 10^(scale-38) fits in 64 bits
    __mul_64x128_to_128 (R128, ten2k64[scale - 38], C3);
    // now multiply R128 by 10^38
    __mul_128x128_to_256 (R256, R128, ten2k128[18]);
  } else { // 58 <= scale <= 66
    // 10^scale takes between 193 and 220 bits,
    // and C3 * 10^scale fits in 223 bits (10^67/10^69 has 223/230 bits)
    // must split the computation: 
    // 10^scale * C3 = 10*38 * 10^(scale-38) * C3 where 10^38 takes 127
    // bits and so 10^(scale-38) * C3 fits in 128 bits with certainty 
    // Note that 20 <= scale - 38 <= 30 => 10^(scale-38) fits in 128 bits
    // Calculate first 10^(scale-38) * C3, which fits in 128 bits; because
    // 10^(scale-38) takes more than 64 bits, C3 will take less than 64
    __mul_64x128_to_128 (R128, C3.w[0], ten2k128[scale - 58]);
    // now calculate 10*38 * 10^(scale-38) * C3 
    __mul_128x128_to_256 (R256, R128, ten2k128[18]);
  }
  // C3 * 10^scale is now in R256 

  // for Cases (15), (16), (17) C4 > C3 * 10^scale because C4 has at least 
  // one extra digit; for Cases (2), (3), (4), (5), or (6) any order is 
  // possible 
  // add/subtract C4 and C3 * 10^scale; the exponent is e4
  if (p_sign == z_sign) { // R256 = C4 + R256
    // calculate R256 = C4 + C3 * 10^scale = C4 + R256 which is exact,
    // but may require rounding
    add256 (C4, R256, &R256);
  } else { // if (p_sign != z_sign) { // R256 = C4 - R256
    // calculate R256 = C4 - C3 * 10^scale = C4 - R256 or
    // R256 = C3 * 10^scale - C4 = R256 - C4 which is exact,
    // but may require rounding

    // compare first R256 = C3 * 10^scale and C4 
    if (R256.w[3] > C4.w[3] || (R256.w[3] == C4.w[3] && R256.w[2] > C4.w[2]) ||
        (R256.w[3] == C4.w[3] && R256.w[2] == C4.w[2] && R256.w[1] > C4.w[1]) ||
        (R256.w[3] == C4.w[3] && R256.w[2] == C4.w[2] && R256.w[1] == C4.w[1] &&
        R256.w[0] >= C4.w[0])) { // C3 * 10^scale >= C4
      // calculate R256 = C3 * 10^scale - C4 = R256 - C4, which is exact,
      // but may require rounding 
      sub256 (R256, C4, &R256);
      // flip p_sign too, because the result has the sign of z 
      p_sign = z_sign;
    } else { // if C4 > C3 * 10^scale
      // calculate R256 = C4 - C3 * 10^scale = C4 - R256, which is exact,
      // but may require rounding  
      sub256 (C4, R256, &R256);
    }
    // if the result is pure zero, the sign depends on the rounding mode
    // (x*y and z had opposite signs) 
    if (R256.w[3] == 0x0ull && R256.w[2] == 0x0ull &&
        R256.w[1] == 0x0ull && R256.w[0] == 0x0ull) {
      if (rnd_mode != ROUNDING_DOWN)
        p_sign = 0x0000000000000000ull;
      else
        p_sign = 0x8000000000000000ull;
      // the exponent is max (e4, expmin)
      if (e4 < -6176)
        e4 = expmin;
      // assemble result 
      res.w[1] = p_sign | ((UINT64) (e4 + 6176) << 49);
      res.w[0] = 0x0;
      *ptrres = res;
      return;
    }
  }

  // determine the number of decimal digits in R256
  ind = nr_digits256 (R256);

  // the exact result is (-1)^p_sign * R256 * 10^e4 where q (R256) = ind;
  // round to the destination precision, with unbounded exponent

  if (ind <= p34) {
    // result rounded to the destination precision with unbounded exponent
    // is exact
    if (ind + e4 < p34 + expmin) {
      is_tiny = 1; // applies to all rounding modes
    }
    res.w[1] = p_sign | ((UINT64) (e4 + 6176) << 49) | R256.w[1];
    res.w[0] = R256.w[0];
    // Note: res is correct only if expmin <= e4 <= expmax
  } else { // if (ind > p34)
    // if more than P digits, round to nearest to P digits
    // round R256 to p34 digits
    x0 = ind - p34; // 1 <= x0 <= 34 as 35 <= ind <= 68
    if (ind <= 38) {
      P128.w[1] = R256.w[1];
      P128.w[0] = R256.w[0];
      round128_19_38 (ind, x0, P128, &R128, &incr_exp,
        	      &is_midpoint_lt_even, &is_midpoint_gt_even,
        	      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
    } else if (ind <= 57) {
      P192.w[2] = R256.w[2];
      P192.w[1] = R256.w[1];
      P192.w[0] = R256.w[0];
      round192_39_57 (ind, x0, P192, &R192, &incr_exp,
        	      &is_midpoint_lt_even, &is_midpoint_gt_even,
        	      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
      R128.w[1] = R192.w[1];
      R128.w[0] = R192.w[0];
    } else { // if (ind <= 68)
      round256_58_76 (ind, x0, R256, &R256, &incr_exp,
        	      &is_midpoint_lt_even, &is_midpoint_gt_even,
        	      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
      R128.w[1] = R256.w[1];
      R128.w[0] = R256.w[0];
    }
    // the rounded result has p34 = 34 digits
    e4 = e4 + x0 + incr_exp;
    if (rnd_mode == ROUNDING_TO_NEAREST) {
      if (e4 < expmin) {
        is_tiny = 1; // for other rounding modes apply correction
      }
    } else {
      // for RM, RP, RZ, RA apply correction in order to determine tininess
      // but do not save the result; apply the correction to 
      // (-1)^p_sign * significand * 10^0
      P128.w[1] = p_sign | 0x3040000000000000ull | R128.w[1];
      P128.w[0] = R128.w[0];
      rounding_correction (rnd_mode,
        		   is_inexact_lt_midpoint,
        		   is_inexact_gt_midpoint, is_midpoint_lt_even,
        		   is_midpoint_gt_even, 0, &P128, ptrfpsf);
      scale = ((P128.w[1] & MASK_EXP) >> 49) - 6176; // -1, 0, or +1
      // the number of digits in the significand is p34 = 34
      if (e4 + scale < expmin) {
        is_tiny = 1;
      }
    }
    ind = p34; // the number of decimal digits in the signifcand of res
    res.w[1] = p_sign | ((UINT64) (e4 + 6176) << 49) | R128.w[1]; // RN
    res.w[0] = R128.w[0];
    // Note: res is correct only if expmin <= e4 <= expmax
    // set the inexact flag after rounding with bounded exponent, if any
  }
  // at this point we have the result rounded with unbounded exponent in
  // res and we know its tininess:
  // res = (-1)^p_sign * significand * 10^e4, 
  // where q (significand) = ind <= p34
  // Note: res is correct only if expmin <= e4 <= expmax

  // check for overflow if RN
  if (rnd_mode == ROUNDING_TO_NEAREST && (ind + e4) > (p34 + expmax)) {
    res.w[1] = p_sign | 0x7800000000000000ull;
    res.w[0] = 0x0000000000000000ull;
    *ptrres = res;
    *ptrfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
    return; // BID_RETURN (res)
  } // else not overflow or not RN, so continue

  // if (e4 >= expmin) we have the result rounded with bounded exponent
  if (e4 < expmin) {
    x0 = expmin - e4; // x0 >= 1; the number of digits to chop off of res
    // where the result rounded [at most] once is
    //   (-1)^p_sign * significand_res * 10^e4

    // avoid double rounding error
    is_inexact_lt_midpoint0 = is_inexact_lt_midpoint;
    is_inexact_gt_midpoint0 = is_inexact_gt_midpoint;
    is_midpoint_lt_even0 = is_midpoint_lt_even;
    is_midpoint_gt_even0 = is_midpoint_gt_even;
    is_inexact_lt_midpoint = 0;
    is_inexact_gt_midpoint = 0;
    is_midpoint_lt_even = 0;
    is_midpoint_gt_even = 0;

    if (x0 > ind) {
      // nothing is left of res when moving the decimal point left x0 digits
      is_inexact_lt_midpoint = 1;
      res.w[1] = p_sign | 0x0000000000000000ull;
      res.w[0] = 0x0000000000000000ull;
      e4 = expmin;
    } else if (x0 == ind) { // 1 <= x0 = ind <= p34 = 34
      // this is <, =, or > 1/2 ulp
      // compare the ind-digit value in the significand of res with
      // 1/2 ulp = 5*10^(ind-1), i.e. determine whether it is 
      // less than, equal to, or greater than 1/2 ulp (significand of res)
      R128.w[1] = res.w[1] & MASK_COEFF;
      R128.w[0] = res.w[0];
      if (ind <= 19) {
        if (R128.w[0] < midpoint64[ind - 1]) { // < 1/2 ulp
          lt_half_ulp = 1;
          is_inexact_lt_midpoint = 1;
        } else if (R128.w[0] == midpoint64[ind - 1]) { // = 1/2 ulp
          eq_half_ulp = 1;
          is_midpoint_gt_even = 1;
        } else { // > 1/2 ulp
          // gt_half_ulp = 1;
          is_inexact_gt_midpoint = 1;
        }
      } else { // if (ind <= 38) {
        if (R128.w[1] < midpoint128[ind - 20].w[1] || 
            (R128.w[1] == midpoint128[ind - 20].w[1] && 
            R128.w[0] < midpoint128[ind - 20].w[0])) { // < 1/2 ulp
          lt_half_ulp = 1;
          is_inexact_lt_midpoint = 1;
        } else if (R128.w[1] == midpoint128[ind - 20].w[1] && 
            R128.w[0] == midpoint128[ind - 20].w[0]) { // = 1/2 ulp
          eq_half_ulp = 1;
          is_midpoint_gt_even = 1;
        } else { // > 1/2 ulp
          // gt_half_ulp = 1;
          is_inexact_gt_midpoint = 1;
        }
      }
      if (lt_half_ulp || eq_half_ulp) {
        // res = +0.0 * 10^expmin
        res.w[1] = 0x0000000000000000ull;
        res.w[0] = 0x0000000000000000ull;
      } else { // if (gt_half_ulp)
        // res = +1 * 10^expmin
        res.w[1] = 0x0000000000000000ull;
        res.w[0] = 0x0000000000000001ull;
      }
      res.w[1] = p_sign | res.w[1];
      e4 = expmin;
    } else { // if (1 <= x0 <= ind - 1 <= 33)
      // round the ind-digit result to ind - x0 digits

      if (ind <= 18) { // 2 <= ind <= 18
        round64_2_18 (ind, x0, res.w[0], &R64, &incr_exp,
        	      &is_midpoint_lt_even, &is_midpoint_gt_even,
        	      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
        res.w[1] = 0x0;
        res.w[0] = R64;
      } else if (ind <= 38) {
        P128.w[1] = res.w[1] & MASK_COEFF;
        P128.w[0] = res.w[0];
        round128_19_38 (ind, x0, P128, &res, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
      }
      e4 = e4 + x0; // expmin
      // we want the exponent to be expmin, so if incr_exp = 1 then
      // multiply the rounded result by 10 - it will still fit in 113 bits
      if (incr_exp) {
        // 64 x 128 -> 128
        P128.w[1] = res.w[1] & MASK_COEFF;
        P128.w[0] = res.w[0];
        __mul_64x128_to_128 (res, ten2k64[1], P128);
      }
      res.w[1] =
        p_sign | ((UINT64) (e4 + 6176) << 49) | (res.w[1] & MASK_COEFF);
      // avoid a double rounding error
      if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
          is_midpoint_lt_even) { // double rounding error upward
        // res = res - 1
        res.w[0]--;
        if (res.w[0] == 0xffffffffffffffffull)
          res.w[1]--;
        // Note: a double rounding error upward is not possible; for this
        // the result after the first rounding would have to be 99...95
        // (35 digits in all), possibly followed by a number of zeros; this
        // is not possible in Cases (2)-(6) or (15)-(17) which may get here
        is_midpoint_lt_even = 0;
        is_inexact_lt_midpoint = 1;
      } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
          is_midpoint_gt_even) { // double rounding error downward
        // res = res + 1
        res.w[0]++;
        if (res.w[0] == 0)
          res.w[1]++;
        is_midpoint_gt_even = 0;
        is_inexact_gt_midpoint = 1;
      } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	 !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
        // if this second rounding was exact the result may still be 
        // inexact because of the first rounding
        if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
          is_inexact_gt_midpoint = 1;
        }
        if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
          is_inexact_lt_midpoint = 1;
        }
      } else if (is_midpoint_gt_even &&
        	 (is_inexact_gt_midpoint0 || is_midpoint_lt_even0)) {
        // pulled up to a midpoint
        is_inexact_lt_midpoint = 1;
        is_inexact_gt_midpoint = 0;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;
      } else if (is_midpoint_lt_even &&
        	 (is_inexact_lt_midpoint0 || is_midpoint_gt_even0)) {
        // pulled down to a midpoint
        is_inexact_lt_midpoint = 0;
        is_inexact_gt_midpoint = 1;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;
      } else {
        ;
      }
    }
  }
  // res contains the correct result
  // apply correction if not rounding to nearest
  if (rnd_mode != ROUNDING_TO_NEAREST) {
    rounding_correction (rnd_mode,
        		 is_inexact_lt_midpoint, is_inexact_gt_midpoint,
        		 is_midpoint_lt_even, is_midpoint_gt_even,
        		 e4, &res, ptrfpsf);
  }
  if (is_midpoint_lt_even || is_midpoint_gt_even ||
      is_inexact_lt_midpoint || is_inexact_gt_midpoint) {
    // set the inexact flag
    *ptrfpsf |= INEXACT_EXCEPTION;
    if (is_tiny)
      *ptrfpsf |= UNDERFLOW_EXCEPTION;
  }

  *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
  *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
  *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
  *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
  *ptrres = res;
  return;
}


#if DECIMAL_CALL_BY_REFERENCE
static void
bid128_ext_fma (int *ptr_is_midpoint_lt_even,
        	int *ptr_is_midpoint_gt_even,
        	int *ptr_is_inexact_lt_midpoint,
        	int *ptr_is_inexact_gt_midpoint, UINT128 * pres,
        	UINT128 * px, UINT128 * py,
        	UINT128 *
        	pz _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
        	_EXC_INFO_PARAM) {
  UINT128 x = *px, y = *py, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
static UINT128
bid128_ext_fma (int *ptr_is_midpoint_lt_even,
        	int *ptr_is_midpoint_gt_even,
        	int *ptr_is_inexact_lt_midpoint,
        	int *ptr_is_inexact_gt_midpoint, UINT128 x, UINT128 y,
        	UINT128 z _RND_MODE_PARAM _EXC_FLAGS_PARAM
        	_EXC_MASKS_PARAM _EXC_INFO_PARAM) {
#endif

  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT64 x_sign, y_sign, z_sign, p_sign, tmp_sign;
  UINT64 x_exp = 0, y_exp = 0, z_exp = 0, p_exp;
  int true_p_exp;
  UINT128 C1, C2, C3;
  UINT256 C4;
  int q1 = 0, q2 = 0, q3 = 0, q4;
  int e1, e2, e3, e4;
  int scale, ind, delta, x0;
  int p34 = P34; // used to modify the limit on the number of digits
  BID_UI64DOUBLE tmp;
  int x_nr_bits, y_nr_bits, z_nr_bits;
  unsigned int save_fpsf;
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
  int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  int is_midpoint_lt_even0 = 0, is_midpoint_gt_even0 = 0;
  int is_inexact_lt_midpoint0 = 0, is_inexact_gt_midpoint0 = 0;
  int incr_exp = 0;
  int lsb;
  int lt_half_ulp = 0;
  int eq_half_ulp = 0;
  int gt_half_ulp = 0;
  int is_tiny = 0;
  UINT64 R64, tmp64;
  UINT128 P128, R128;
  UINT192 P192, R192;
  UINT256 R256;

  // the following are based on the table of special cases for fma; the NaN
  // behavior is similar to that of the IA-64 Architecture fma 

  // identify cases where at least one operand is NaN

  BID_SWAP128 (x);
  BID_SWAP128 (y);
  BID_SWAP128 (z);
  if ((y.w[1] & MASK_NAN) == MASK_NAN) { // y is NAN
    // if x = {0, f, inf, NaN}, y = NaN, z = {0, f, inf, NaN} then res = Q (y)
    // check first for non-canonical NaN payload
    if (((y.w[1] & 0x00003fffffffffffull) > 0x0000314dc6448d93ull) ||
        (((y.w[1] & 0x00003fffffffffffull) == 0x0000314dc6448d93ull) &&
         (y.w[0] > 0x38c15b09ffffffffull))) {
      y.w[1] = y.w[1] & 0xffffc00000000000ull;
      y.w[0] = 0x0ull;
    }
    if ((y.w[1] & MASK_SNAN) == MASK_SNAN) { // y is SNAN
      // set invalid flag
      *pfpsf |= INVALID_EXCEPTION;
      // return quiet (y)
      res.w[1] = y.w[1] & 0xfc003fffffffffffull; // clear out also G[6]-G[16]
      res.w[0] = y.w[0];
    } else { // y is QNaN
      // return y
      res.w[1] = y.w[1] & 0xfc003fffffffffffull; // clear out G[6]-G[16]
      res.w[0] = y.w[0];
      // if z = SNaN or x = SNaN signal invalid exception
      if ((z.w[1] & MASK_SNAN) == MASK_SNAN ||
          (x.w[1] & MASK_SNAN) == MASK_SNAN) {
        // set invalid flag
        *pfpsf |= INVALID_EXCEPTION;
      }
    }
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  } else if ((z.w[1] & MASK_NAN) == MASK_NAN) { // z is NAN
    // if x = {0, f, inf, NaN}, y = {0, f, inf}, z = NaN then res = Q (z)
    // check first for non-canonical NaN payload
    if (((z.w[1] & 0x00003fffffffffffull) > 0x0000314dc6448d93ull) ||
        (((z.w[1] & 0x00003fffffffffffull) == 0x0000314dc6448d93ull) &&
         (z.w[0] > 0x38c15b09ffffffffull))) {
      z.w[1] = z.w[1] & 0xffffc00000000000ull;
      z.w[0] = 0x0ull;
    }
    if ((z.w[1] & MASK_SNAN) == MASK_SNAN) { // z is SNAN 
      // set invalid flag 
      *pfpsf |= INVALID_EXCEPTION;
      // return quiet (z) 
      res.w[1] = z.w[1] & 0xfc003fffffffffffull; // clear out also G[6]-G[16]
      res.w[0] = z.w[0];
    } else { // z is QNaN 
      // return z  
      res.w[1] = z.w[1] & 0xfc003fffffffffffull; // clear out G[6]-G[16]
      res.w[0] = z.w[0];
      // if x = SNaN signal invalid exception
      if ((x.w[1] & MASK_SNAN) == MASK_SNAN) {
        // set invalid flag
        *pfpsf |= INVALID_EXCEPTION;
      }
    }
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  } else if ((x.w[1] & MASK_NAN) == MASK_NAN) { // x is NAN
    // if x = NaN, y = {0, f, inf}, z = {0, f, inf} then res = Q (x)
    // check first for non-canonical NaN payload
    if (((x.w[1] & 0x00003fffffffffffull) > 0x0000314dc6448d93ull) ||
        (((x.w[1] & 0x00003fffffffffffull) == 0x0000314dc6448d93ull) &&
         (x.w[0] > 0x38c15b09ffffffffull))) {
      x.w[1] = x.w[1] & 0xffffc00000000000ull;
      x.w[0] = 0x0ull;
    }
    if ((x.w[1] & MASK_SNAN) == MASK_SNAN) { // x is SNAN 
      // set invalid flag 
      *pfpsf |= INVALID_EXCEPTION;
      // return quiet (x) 
      res.w[1] = x.w[1] & 0xfc003fffffffffffull; // clear out also G[6]-G[16]
      res.w[0] = x.w[0];
    } else { // x is QNaN 
      // return x  
      res.w[1] = x.w[1] & 0xfc003fffffffffffull; // clear out G[6]-G[16]
      res.w[0] = x.w[0];
    }
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  }
  // x, y, z are 0, f, or inf but not NaN => unpack the arguments and check
  // for non-canonical values

  x_sign = x.w[1] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
  C1.w[1] = x.w[1] & MASK_COEFF;
  C1.w[0] = x.w[0];
  if ((x.w[1] & MASK_ANY_INF) != MASK_INF) { // x != inf
    // if x is not infinity check for non-canonical values - treated as zero
    if ((x.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) { // G0_G1=11
      // non-canonical
      x_exp = (x.w[1] << 2) & MASK_EXP; // biased and shifted left 49 bits
      C1.w[1] = 0; // significand high
      C1.w[0] = 0; // significand low
    } else { // G0_G1 != 11
      x_exp = x.w[1] & MASK_EXP; // biased and shifted left 49 bits
      if (C1.w[1] > 0x0001ed09bead87c0ull ||
          (C1.w[1] == 0x0001ed09bead87c0ull &&
           C1.w[0] > 0x378d8e63ffffffffull)) {
        // x is non-canonical if coefficient is larger than 10^34 -1
        C1.w[1] = 0;
        C1.w[0] = 0;
      } else { // canonical          
        ;
      }
    }
  }
  y_sign = y.w[1] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
  C2.w[1] = y.w[1] & MASK_COEFF;
  C2.w[0] = y.w[0];
  if ((y.w[1] & MASK_ANY_INF) != MASK_INF) { // y != inf
    // if y is not infinity check for non-canonical values - treated as zero
    if ((y.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) { // G0_G1=11
      // non-canonical
      y_exp = (y.w[1] << 2) & MASK_EXP; // biased and shifted left 49 bits
      C2.w[1] = 0; // significand high
      C2.w[0] = 0; // significand low 
    } else { // G0_G1 != 11
      y_exp = y.w[1] & MASK_EXP; // biased and shifted left 49 bits
      if (C2.w[1] > 0x0001ed09bead87c0ull ||
          (C2.w[1] == 0x0001ed09bead87c0ull &&
           C2.w[0] > 0x378d8e63ffffffffull)) {
        // y is non-canonical if coefficient is larger than 10^34 -1
        C2.w[1] = 0;
        C2.w[0] = 0;
      } else { // canonical
        ;
      }
    }
  }
  z_sign = z.w[1] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
  C3.w[1] = z.w[1] & MASK_COEFF;
  C3.w[0] = z.w[0];
  if ((z.w[1] & MASK_ANY_INF) != MASK_INF) { // z != inf
    // if z is not infinity check for non-canonical values - treated as zero
    if ((z.w[1] & 0x6000000000000000ull) == 0x6000000000000000ull) { // G0_G1=11
      // non-canonical
      z_exp = (z.w[1] << 2) & MASK_EXP; // biased and shifted left 49 bits
      C3.w[1] = 0; // significand high
      C3.w[0] = 0; // significand low 
    } else { // G0_G1 != 11
      z_exp = z.w[1] & MASK_EXP; // biased and shifted left 49 bits
      if (C3.w[1] > 0x0001ed09bead87c0ull ||
          (C3.w[1] == 0x0001ed09bead87c0ull &&
           C3.w[0] > 0x378d8e63ffffffffull)) {
        // z is non-canonical if coefficient is larger than 10^34 -1
        C3.w[1] = 0;
        C3.w[0] = 0;
      } else { // canonical
        ;
      }
    }
  }

  p_sign = x_sign ^ y_sign; // sign of the product

  // identify cases where at least one operand is infinity

  if ((x.w[1] & MASK_ANY_INF) == MASK_INF) { // x = inf
    if ((y.w[1] & MASK_ANY_INF) == MASK_INF) { // y = inf
      if ((z.w[1] & MASK_ANY_INF) == MASK_INF) { // z = inf
        if (p_sign == z_sign) {
          res.w[1] = z_sign | MASK_INF;
          res.w[0] = 0x0;
        } else {
          // return QNaN Indefinite
          res.w[1] = 0x7c00000000000000ull;
          res.w[0] = 0x0000000000000000ull;
          // set invalid flag
          *pfpsf |= INVALID_EXCEPTION;
        }
      } else { // z = 0 or z = f
        res.w[1] = p_sign | MASK_INF;
        res.w[0] = 0x0;
      }
    } else if (C2.w[1] != 0 || C2.w[0] != 0) { // y = f
      if ((z.w[1] & MASK_ANY_INF) == MASK_INF) { // z = inf
        if (p_sign == z_sign) {
          res.w[1] = z_sign | MASK_INF;
          res.w[0] = 0x0;
        } else {
          // return QNaN Indefinite 
          res.w[1] = 0x7c00000000000000ull;
          res.w[0] = 0x0000000000000000ull;
          // set invalid flag
          *pfpsf |= INVALID_EXCEPTION;
        }
      } else { // z = 0 or z = f
        res.w[1] = p_sign | MASK_INF;
        res.w[0] = 0x0;
      }
    } else { // y = 0
      // return QNaN Indefinite
      res.w[1] = 0x7c00000000000000ull;
      res.w[0] = 0x0000000000000000ull;
      // set invalid flag
      *pfpsf |= INVALID_EXCEPTION;
    }
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  } else if ((y.w[1] & MASK_ANY_INF) == MASK_INF) { // y = inf
    if ((z.w[1] & MASK_ANY_INF) == MASK_INF) { // z = inf
      // x = f, necessarily
      if ((p_sign != z_sign)
          || (C1.w[1] == 0x0ull && C1.w[0] == 0x0ull)) {
        // return QNaN Indefinite
        res.w[1] = 0x7c00000000000000ull;
        res.w[0] = 0x0000000000000000ull;
        // set invalid flag
        *pfpsf |= INVALID_EXCEPTION;
      } else {
        res.w[1] = z_sign | MASK_INF;
        res.w[0] = 0x0;
      }
    } else if (C1.w[1] == 0x0 && C1.w[0] == 0x0) { // x = 0
      // z = 0, f, inf
      // return QNaN Indefinite
      res.w[1] = 0x7c00000000000000ull;
      res.w[0] = 0x0000000000000000ull;
      // set invalid flag
      *pfpsf |= INVALID_EXCEPTION;
    } else {
      // x = f and z = 0, f, necessarily
      res.w[1] = p_sign | MASK_INF;
      res.w[0] = 0x0;
    }
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  } else if ((z.w[1] & MASK_ANY_INF) == MASK_INF) { // z = inf
    // x = 0, f and y = 0, f, necessarily
    res.w[1] = z_sign | MASK_INF;
    res.w[0] = 0x0;
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  }

  true_p_exp = (x_exp >> 49) - 6176 + (y_exp >> 49) - 6176;
  if (true_p_exp < -6176)
    p_exp = 0; // cannot be less than EXP_MIN
  else
    p_exp = (UINT64) (true_p_exp + 6176) << 49;

  if (((C1.w[1] == 0x0 && C1.w[0] == 0x0) || (C2.w[1] == 0x0 && C2.w[0] == 0x0)) && C3.w[1] == 0x0 && C3.w[0] == 0x0) { // (x = 0 or y = 0) and z = 0
    // the result is 0
    if (p_exp < z_exp)
      res.w[1] = p_exp; // preferred exponent
    else
      res.w[1] = z_exp; // preferred exponent
    if (p_sign == z_sign) {
      res.w[1] |= z_sign;
      res.w[0] = 0x0;
    } else { // x * y and z have opposite signs
      if (rnd_mode == ROUNDING_DOWN) {
        // res = -0.0
        res.w[1] |= MASK_SIGN;
        res.w[0] = 0x0;
      } else {
        // res = +0.0
        // res.w[1] |= 0x0;
        res.w[0] = 0x0;
      }
    }
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  }
  // from this point on, we may need to know the number of decimal digits
  // in the significands of x, y, z when x, y, z != 0

  if (C1.w[1] != 0 || C1.w[0] != 0) { // x = f (non-zero finite)
    // q1 = nr. of decimal digits in x
    // determine first the nr. of bits in x
    if (C1.w[1] == 0) {
      if (C1.w[0] >= 0x0020000000000000ull) { // x >= 2^53
        // split the 64-bit value in two 32-bit halves to avoid rounding errors
        if (C1.w[0] >= 0x0000000100000000ull) { // x >= 2^32
          tmp.d = (double) (C1.w[0] >> 32); // exact conversion
          x_nr_bits =
            33 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
        } else { // x < 2^32
          tmp.d = (double) (C1.w[0]); // exact conversion
          x_nr_bits =
            1 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
        }
      } else { // if x < 2^53
        tmp.d = (double) C1.w[0]; // exact conversion
        x_nr_bits =
          1 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
      }
    } else { // C1.w[1] != 0 => nr. bits = 64 + nr_bits (C1.w[1])
      tmp.d = (double) C1.w[1]; // exact conversion
      x_nr_bits =
        65 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
    }
    q1 = nr_digits[x_nr_bits - 1].digits;
    if (q1 == 0) {
      q1 = nr_digits[x_nr_bits - 1].digits1;
      if (C1.w[1] > nr_digits[x_nr_bits - 1].threshold_hi ||
          (C1.w[1] == nr_digits[x_nr_bits - 1].threshold_hi &&
           C1.w[0] >= nr_digits[x_nr_bits - 1].threshold_lo))
        q1++;
    }
  }

  if (C2.w[1] != 0 || C2.w[0] != 0) { // y = f (non-zero finite)
    if (C2.w[1] == 0) {
      if (C2.w[0] >= 0x0020000000000000ull) { // y >= 2^53
        // split the 64-bit value in two 32-bit halves to avoid rounding errors
        if (C2.w[0] >= 0x0000000100000000ull) { // y >= 2^32
          tmp.d = (double) (C2.w[0] >> 32); // exact conversion
          y_nr_bits =
            32 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
        } else { // y < 2^32
          tmp.d = (double) C2.w[0]; // exact conversion
          y_nr_bits =
            ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
        }
      } else { // if y < 2^53
        tmp.d = (double) C2.w[0]; // exact conversion
        y_nr_bits =
          ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
      }
    } else { // C2.w[1] != 0 => nr. bits = 64 + nr_bits (C2.w[1])
      tmp.d = (double) C2.w[1]; // exact conversion
      y_nr_bits =
        64 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
    }

    q2 = nr_digits[y_nr_bits].digits;
    if (q2 == 0) {
      q2 = nr_digits[y_nr_bits].digits1;
      if (C2.w[1] > nr_digits[y_nr_bits].threshold_hi ||
          (C2.w[1] == nr_digits[y_nr_bits].threshold_hi &&
           C2.w[0] >= nr_digits[y_nr_bits].threshold_lo))
        q2++;
    }
  }

  if (C3.w[1] != 0 || C3.w[0] != 0) { // z = f (non-zero finite)
    if (C3.w[1] == 0) {
      if (C3.w[0] >= 0x0020000000000000ull) { // z >= 2^53
        // split the 64-bit value in two 32-bit halves to avoid rounding errors
        if (C3.w[0] >= 0x0000000100000000ull) { // z >= 2^32
          tmp.d = (double) (C3.w[0] >> 32); // exact conversion
          z_nr_bits =
            32 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
        } else { // z < 2^32
          tmp.d = (double) C3.w[0]; // exact conversion
          z_nr_bits =
            ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
        }
      } else { // if z < 2^53
        tmp.d = (double) C3.w[0]; // exact conversion
        z_nr_bits =
          ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
      }
    } else { // C3.w[1] != 0 => nr. bits = 64 + nr_bits (C3.w[1])
      tmp.d = (double) C3.w[1]; // exact conversion
      z_nr_bits =
        64 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
    }

    q3 = nr_digits[z_nr_bits].digits;
    if (q3 == 0) {
      q3 = nr_digits[z_nr_bits].digits1;
      if (C3.w[1] > nr_digits[z_nr_bits].threshold_hi ||
          (C3.w[1] == nr_digits[z_nr_bits].threshold_hi &&
           C3.w[0] >= nr_digits[z_nr_bits].threshold_lo))
        q3++;
    }
  }

  if ((C1.w[1] == 0x0 && C1.w[0] == 0x0) ||
      (C2.w[1] == 0x0 && C2.w[0] == 0x0)) {
    // x = 0 or y = 0
    // z = f, necessarily; for 0 + z return z, with the preferred exponent
    // the result is z, but need to get the preferred exponent
    if (z_exp <= p_exp) { // the preferred exponent is z_exp
      res.w[1] = z_sign | (z_exp & MASK_EXP) | C3.w[1];
      res.w[0] = C3.w[0];
    } else { // if (p_exp < z_exp) the preferred exponent is p_exp
      // return (C3 * 10^scale) * 10^(z_exp - scale)
      // where scale = min (p34-q3, (z_exp-p_exp) >> 49)
      scale = p34 - q3;
      ind = (z_exp - p_exp) >> 49;
      if (ind < scale)
        scale = ind;
      if (scale == 0) {
        res.w[1] = z.w[1]; // & MASK_COEFF, which is redundant
        res.w[0] = z.w[0];
      } else if (q3 <= 19) { // z fits in 64 bits 
        if (scale <= 19) { // 10^scale fits in 64 bits
          // 64 x 64 C3.w[0] * ten2k64[scale]
          __mul_64x64_to_128MACH (res, C3.w[0], ten2k64[scale]);
        } else { // 10^scale fits in 128 bits
          // 64 x 128 C3.w[0] * ten2k128[scale - 20]
          __mul_128x64_to_128 (res, C3.w[0], ten2k128[scale - 20]);
        }
      } else { // z fits in 128 bits, but 10^scale must fit in 64 bits 
        // 64 x 128 ten2k64[scale] * C3
        __mul_128x64_to_128 (res, ten2k64[scale], C3);
      }
      // subtract scale from the exponent
      z_exp = z_exp - ((UINT64) scale << 49);
      res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
    }
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  } else {
    ; // continue with x = f, y = f, z = 0 or x = f, y = f, z = f
  }

  e1 = (x_exp >> 49) - 6176; // unbiased exponent of x 
  e2 = (y_exp >> 49) - 6176; // unbiased exponent of y 
  e3 = (z_exp >> 49) - 6176; // unbiased exponent of z
  e4 = e1 + e2; // unbiased exponent of the exact x * y

  // calculate C1 * C2 and its number of decimal digits, q4

  // the exact product has either q1 + q2 - 1 or q1 + q2 decimal digits
  // where 2 <= q1 + q2 <= 68
  // calculate C4 = C1 * C2 and determine q
  C4.w[3] = C4.w[2] = C4.w[1] = C4.w[0] = 0;
  if (q1 + q2 <= 19) { // if 2 <= q1 + q2 <= 19, C4 = C1 * C2 fits in 64 bits
    C4.w[0] = C1.w[0] * C2.w[0];
    // if C4 < 10^(q1+q2-1) then q4 = q1 + q2 - 1 else q4 = q1 + q2
    if (C4.w[0] < ten2k64[q1 + q2 - 1])
      q4 = q1 + q2 - 1; // q4 in [1, 18]
    else
      q4 = q1 + q2; // q4 in [2, 19]
    // length of C1 * C2 rounded up to a multiple of 64 bits is len = 64;
  } else if (q1 + q2 == 20) { // C4 = C1 * C2 fits in 64 or 128 bits
    // q1 <= 19 and q2 <= 19 so both C1 and C2 fit in 64 bits
    __mul_64x64_to_128MACH (C4, C1.w[0], C2.w[0]);
    // if C4 < 10^(q1+q2-1) = 10^19 then q4 = q1+q2-1 = 19 else q4 = q1+q2 = 20
    if (C4.w[1] == 0 && C4.w[0] < ten2k64[19]) { // 19 = q1+q2-1
      // length of C1 * C2 rounded up to a multiple of 64 bits is len = 64;
      q4 = 19; // 19 = q1 + q2 - 1
    } else {
      // if (C4.w[1] == 0)
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 64;
      // else
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 128;
      q4 = 20; // 20 = q1 + q2
    }
  } else if (q1 + q2 <= 38) { // 21 <= q1 + q2 <= 38
    // C4 = C1 * C2 fits in 64 or 128 bits
    // (64 bits possibly, but only when q1 + q2 = 21 and C4 has 20 digits)
    // at least one of C1, C2 has at most 19 decimal digits & fits in 64 bits
    if (q1 <= 19) {
      __mul_128x64_to_128 (C4, C1.w[0], C2);
    } else { // q2 <= 19
      __mul_128x64_to_128 (C4, C2.w[0], C1);
    }
    // if C4 < 10^(q1+q2-1) then q4 = q1 + q2 - 1 else q4 = q1 + q2
    if (C4.w[1] < ten2k128[q1 + q2 - 21].w[1] ||
        (C4.w[1] == ten2k128[q1 + q2 - 21].w[1] &&
         C4.w[0] < ten2k128[q1 + q2 - 21].w[0])) {
      // if (C4.w[1] == 0) // q4 = 20, necessarily
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 64;
      // else
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 128;
      q4 = q1 + q2 - 1; // q4 in [20, 37]
    } else {
      // length of C1 * C2 rounded up to a multiple of 64 bits is len = 128;
      q4 = q1 + q2; // q4 in [21, 38]
    }
  } else if (q1 + q2 == 39) { // C4 = C1 * C2 fits in 128 or 192 bits
    // both C1 and C2 fit in 128 bits (actually in 113 bits)
    // may replace this by 128x128_to192
    __mul_128x128_to_256 (C4, C1, C2); // C4.w[3] is 0
    // if C4 < 10^(q1+q2-1) = 10^38 then q4 = q1+q2-1 = 38 else q4 = q1+q2 = 39
    if (C4.w[2] == 0 && (C4.w[1] < ten2k128[18].w[1] ||
        		 (C4.w[1] == ten2k128[18].w[1]
        		  && C4.w[0] < ten2k128[18].w[0]))) {
      // 18 = 38 - 20 = q1+q2-1 - 20
      // length of C1 * C2 rounded up to a multiple of 64 bits is len = 128;
      q4 = 38; // 38 = q1 + q2 - 1
    } else {
      // if (C4.w[2] == 0)
      // length of C1 * C2 rounded up to a multiple of 64 bits is len = 128;
      // else
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 192;
      q4 = 39; // 39 = q1 + q2
    }
  } else if (q1 + q2 <= 57) { // 40 <= q1 + q2 <= 57
    // C4 = C1 * C2 fits in 128 or 192 bits
    // (128 bits possibly, but only when q1 + q2 = 40 and C4 has 39 digits)
    // both C1 and C2 fit in 128 bits (actually in 113 bits); at most one
    // may fit in 64 bits
    if (C1.w[1] == 0) { // C1 fits in 64 bits
      // __mul_64x128_full (REShi64, RESlo128, A64, B128)
      __mul_64x128_full (C4.w[2], C4, C1.w[0], C2);
    } else if (C2.w[1] == 0) { // C2 fits in 64 bits
      // __mul_64x128_full (REShi64, RESlo128, A64, B128)
      __mul_64x128_full (C4.w[2], C4, C2.w[0], C1);
    } else { // both C1 and C2 require 128 bits
      // may use __mul_128x128_to_192 (C4.w[2], C4.w[0], C2.w[0], C1);
      __mul_128x128_to_256 (C4, C1, C2); // C4.w[3] = 0
    }
    // if C4 < 10^(q1+q2-1) then q4 = q1 + q2 - 1 else q4 = q1 + q2
    if (C4.w[2] < ten2k256[q1 + q2 - 40].w[2] ||
        (C4.w[2] == ten2k256[q1 + q2 - 40].w[2] &&
         (C4.w[1] < ten2k256[q1 + q2 - 40].w[1] ||
          (C4.w[1] == ten2k256[q1 + q2 - 40].w[1] &&
           C4.w[0] < ten2k256[q1 + q2 - 40].w[0])))) {
      // if (C4.w[2] == 0) // q4 = 39, necessarily
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 128;
      // else
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 192;
      q4 = q1 + q2 - 1; // q4 in [39, 56]
    } else {
      // length of C1 * C2 rounded up to a multiple of 64 bits is len = 192;
      q4 = q1 + q2; // q4 in [40, 57]
    }
  } else if (q1 + q2 == 58) { // C4 = C1 * C2 fits in 192 or 256 bits
    // both C1 and C2 fit in 128 bits (actually in 113 bits); at most one
    // may fit in 64 bits
    if (C1.w[1] == 0) { // C1 * C2 will fit in 192 bits
      __mul_64x128_full (C4.w[2], C4, C1.w[0], C2); // may use 64x128_to_192
    } else if (C2.w[1] == 0) { // C1 * C2 will fit in 192 bits
      __mul_64x128_full (C4.w[2], C4, C2.w[0], C1); // may use 64x128_to_192
    } else { // C1 * C2 will fit in 192 bits or in 256 bits
      __mul_128x128_to_256 (C4, C1, C2);
    }
    // if C4 < 10^(q1+q2-1) = 10^57 then q4 = q1+q2-1 = 57 else q4 = q1+q2 = 58
    if (C4.w[3] == 0 && (C4.w[2] < ten2k256[18].w[2] ||
        		 (C4.w[2] == ten2k256[18].w[2]
        		  && (C4.w[1] < ten2k256[18].w[1]
        		      || (C4.w[1] == ten2k256[18].w[1]
        			  && C4.w[0] < ten2k256[18].w[0]))))) {
      // 18 = 57 - 39 = q1+q2-1 - 39
      // length of C1 * C2 rounded up to a multiple of 64 bits is len = 192;
      q4 = 57; // 57 = q1 + q2 - 1
    } else {
      // if (C4.w[3] == 0)
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 192;
      // else
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 256;
      q4 = 58; // 58 = q1 + q2
    }
  } else { // if 59 <= q1 + q2 <= 68
    // C4 = C1 * C2 fits in 192 or 256 bits
    // (192 bits possibly, but only when q1 + q2 = 59 and C4 has 58 digits)
    // both C1 and C2 fit in 128 bits (actually in 113 bits); none fits in
    // 64 bits
    // may use __mul_128x128_to_192 (C4.w[2], C4.w[0], C2.w[0], C1);
    __mul_128x128_to_256 (C4, C1, C2); // C4.w[3] = 0
    // if C4 < 10^(q1+q2-1) then q4 = q1 + q2 - 1 else q4 = q1 + q2
    if (C4.w[3] < ten2k256[q1 + q2 - 40].w[3] ||
        (C4.w[3] == ten2k256[q1 + q2 - 40].w[3] &&
         (C4.w[2] < ten2k256[q1 + q2 - 40].w[2] ||
          (C4.w[2] == ten2k256[q1 + q2 - 40].w[2] &&
           (C4.w[1] < ten2k256[q1 + q2 - 40].w[1] ||
            (C4.w[1] == ten2k256[q1 + q2 - 40].w[1] &&
             C4.w[0] < ten2k256[q1 + q2 - 40].w[0])))))) {
      // if (C4.w[3] == 0) // q4 = 58, necessarily
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 192;
      // else
      //   length of C1 * C2 rounded up to a multiple of 64 bits is len = 256;
      q4 = q1 + q2 - 1; // q4 in [58, 67]
    } else {
      // length of C1 * C2 rounded up to a multiple of 64 bits is len = 256;
      q4 = q1 + q2; // q4 in [59, 68]
    }
  }

  if (C3.w[1] == 0x0 && C3.w[0] == 0x0) { // x = f, y = f, z = 0
    save_fpsf = *pfpsf; // sticky bits - caller value must be preserved
    *pfpsf = 0;

    if (q4 > p34) {

      // truncate C4 to p34 digits into res
      // x = q4-p34, 1 <= x <= 34 because 35 <= q4 <= 68
      x0 = q4 - p34;
      if (q4 <= 38) {
        P128.w[1] = C4.w[1];
        P128.w[0] = C4.w[0];
        round128_19_38 (q4, x0, P128, &res, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
      } else if (q4 <= 57) { // 35 <= q4 <= 57
        P192.w[2] = C4.w[2];
        P192.w[1] = C4.w[1];
        P192.w[0] = C4.w[0];
        round192_39_57 (q4, x0, P192, &R192, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
        res.w[0] = R192.w[0];
        res.w[1] = R192.w[1];
      } else { // if (q4 <= 68)
        round256_58_76 (q4, x0, C4, &R256, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
        res.w[0] = R256.w[0];
        res.w[1] = R256.w[1];
      }
      e4 = e4 + x0;
      if (incr_exp) {
        e4 = e4 + 1;
      }
      q4 = p34;
      // res is now the coefficient of the result rounded to the destination 
      // precision, with unbounded exponent; the exponent is e4; q4=digits(res)
    } else { // if (q4 <= p34)
      // C4 * 10^e4 is the result rounded to the destination precision, with  
      // unbounded exponent (which is exact)

      if ((q4 + e4 <= p34 + expmax) && (e4 > expmax)) {
        // e4 is too large, but can be brought within range by scaling up C4
        scale = e4 - expmax; // 1 <= scale < P-q4 <= P-1 => 1 <= scale <= P-2
        // res = (C4 * 10^scale) * 10^expmax
        if (q4 <= 19) { // C4 fits in 64 bits
          if (scale <= 19) { // 10^scale fits in 64 bits
            // 64 x 64 C4.w[0] * ten2k64[scale]
            __mul_64x64_to_128MACH (res, C4.w[0], ten2k64[scale]);
          } else { // 10^scale fits in 128 bits
            // 64 x 128 C4.w[0] * ten2k128[scale - 20]
            __mul_128x64_to_128 (res, C4.w[0], ten2k128[scale - 20]);
          }
        } else { // C4 fits in 128 bits, but 10^scale must fit in 64 bits
          // 64 x 128 ten2k64[scale] * CC43
          __mul_128x64_to_128 (res, ten2k64[scale], C4);
        }
        e4 = e4 - scale; // expmax
        q4 = q4 + scale;
      } else {
        res.w[1] = C4.w[1];
        res.w[0] = C4.w[0];
      }
      // res is the coefficient of the result rounded to the destination 
      // precision, with unbounded exponent (it has q4 digits); the exponent 
      // is e4 (exact result)
    }

    // check for overflow
    if (q4 + e4 > p34 + expmax) {
      if (rnd_mode == ROUNDING_TO_NEAREST) {
        res.w[1] = p_sign | 0x7800000000000000ull; // +/-inf
        res.w[0] = 0x0000000000000000ull;
        *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
      } else {
        res.w[1] = p_sign | res.w[1];
        rounding_correction (rnd_mode,
        		     is_inexact_lt_midpoint,
        		     is_inexact_gt_midpoint,
        		     is_midpoint_lt_even, is_midpoint_gt_even,
        		     e4, &res, pfpsf);
      }
      *pfpsf |= save_fpsf;
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)
    }
    // check for underflow
    if (q4 + e4 < expmin + P34) {
      is_tiny = 1; // the result is tiny
      if (e4 < expmin) {
        // if e4 < expmin, we must truncate more of res
        x0 = expmin - e4; // x0 >= 1
        is_inexact_lt_midpoint0 = is_inexact_lt_midpoint;
        is_inexact_gt_midpoint0 = is_inexact_gt_midpoint;
        is_midpoint_lt_even0 = is_midpoint_lt_even;
        is_midpoint_gt_even0 = is_midpoint_gt_even;
        is_inexact_lt_midpoint = 0;
        is_inexact_gt_midpoint = 0;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;
        // the number of decimal digits in res is q4
        if (x0 < q4) { // 1 <= x0 <= q4-1 => round res to q4 - x0 digits
          if (q4 <= 18) { // 2 <= q4 <= 18, 1 <= x0 <= 17
            round64_2_18 (q4, x0, res.w[0], &R64, &incr_exp,
        		  &is_midpoint_lt_even, &is_midpoint_gt_even,
        		  &is_inexact_lt_midpoint,
        		  &is_inexact_gt_midpoint);
            if (incr_exp) {
              // R64 = 10^(q4-x0), 1 <= q4 - x0 <= q4 - 1, 1 <= q4 - x0 <= 17
              R64 = ten2k64[q4 - x0];
            }
            // res.w[1] = 0; (from above)
            res.w[0] = R64;
          } else { // if (q4 <= 34)
            // 19 <= q4 <= 38
            P128.w[1] = res.w[1];
            P128.w[0] = res.w[0];
            round128_19_38 (q4, x0, P128, &res, &incr_exp,
        		    &is_midpoint_lt_even, &is_midpoint_gt_even,
        		    &is_inexact_lt_midpoint,
        		    &is_inexact_gt_midpoint);
            if (incr_exp) {
              // increase coefficient by a factor of 10; this will be <= 10^33
              // R128 = 10^(q4-x0), 1 <= q4 - x0 <= q4 - 1, 1 <= q4 - x0 <= 37
              if (q4 - x0 <= 19) { // 1 <= q4 - x0 <= 19
        	// res.w[1] = 0;
        	res.w[0] = ten2k64[q4 - x0];
              } else { // 20 <= q4 - x0 <= 37
        	res.w[0] = ten2k128[q4 - x0 - 20].w[0];
        	res.w[1] = ten2k128[q4 - x0 - 20].w[1];
              }
            }
          }
          e4 = e4 + x0; // expmin 
        } else if (x0 == q4) {
          // the second rounding is for 0.d(0)d(1)...d(q4-1) * 10^emin
          // determine relationship with 1/2 ulp
          if (q4 <= 19) {
            if (res.w[0] < midpoint64[q4 - 1]) { // < 1/2 ulp
              lt_half_ulp = 1;
              is_inexact_lt_midpoint = 1;
            } else if (res.w[0] == midpoint64[q4 - 1]) { // = 1/2 ulp
              eq_half_ulp = 1;
              is_midpoint_gt_even = 1;
            } else { // > 1/2 ulp
              // gt_half_ulp = 1;
              is_inexact_gt_midpoint = 1;
            }
          } else { // if (q4 <= 34)
            if (res.w[1] < midpoint128[q4 - 20].w[1] || 
                (res.w[1] == midpoint128[q4 - 20].w[1] && 
                res.w[0] < midpoint128[q4 - 20].w[0])) { // < 1/2 ulp
              lt_half_ulp = 1;
              is_inexact_lt_midpoint = 1;
            } else if (res.w[1] == midpoint128[q4 - 20].w[1] && 
                res.w[0] == midpoint128[q4 - 20].w[0]) { // = 1/2 ulp
              eq_half_ulp = 1;
              is_midpoint_gt_even = 1;
            } else { // > 1/2 ulp
              // gt_half_ulp = 1;
              is_inexact_gt_midpoint = 1;
            }
          }
          if (lt_half_ulp || eq_half_ulp) {
            // res = +0.0 * 10^expmin
            res.w[1] = 0x0000000000000000ull;
            res.w[0] = 0x0000000000000000ull;
          } else { // if (gt_half_ulp)
            // res = +1 * 10^expmin
            res.w[1] = 0x0000000000000000ull;
            res.w[0] = 0x0000000000000001ull;
          }
          e4 = expmin;
        } else { // if (x0 > q4)
          // the second rounding is for 0.0...d(0)d(1)...d(q4-1) * 10^emin
          res.w[1] = 0;
          res.w[0] = 0;
          e4 = expmin;
          is_inexact_lt_midpoint = 1;
        }
        // avoid a double rounding error
        if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
            is_midpoint_lt_even) { // double rounding error upward
          // res = res - 1
          res.w[0]--;
          if (res.w[0] == 0xffffffffffffffffull)
            res.w[1]--;
          // Note: a double rounding error upward is not possible; for this
          // the result after the first rounding would have to be 99...95
          // (35 digits in all), possibly followed by a number of zeros; this
          // not possible for f * f + 0
          is_midpoint_lt_even = 0;
          is_inexact_lt_midpoint = 1;
        } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
            is_midpoint_gt_even) { // double rounding error downward
          // res = res + 1
          res.w[0]++;
          if (res.w[0] == 0)
            res.w[1]++;
          is_midpoint_gt_even = 0;
          is_inexact_gt_midpoint = 1;
        } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	   !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
          // if this second rounding was exact the result may still be 
          // inexact because of the first rounding
          if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
            is_inexact_gt_midpoint = 1;
          }
          if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
            is_inexact_lt_midpoint = 1;
          }
        } else if (is_midpoint_gt_even &&
        	   (is_inexact_gt_midpoint0 || is_midpoint_lt_even0)) {
          // pulled up to a midpoint
          is_inexact_lt_midpoint = 1;
          is_inexact_gt_midpoint = 0;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
        } else if (is_midpoint_lt_even &&
        	   (is_inexact_lt_midpoint0 || is_midpoint_gt_even0)) {
          // pulled down to a midpoint
          is_inexact_lt_midpoint = 0;
          is_inexact_gt_midpoint = 1;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
        } else {
          ;
        }
      } else { // if e4 >= emin then q4 < P and the result is tiny and exact
        if (e3 < e4) {
          // if (e3 < e4) the preferred exponent is e3
          // return (C4 * 10^scale) * 10^(e4 - scale)
          // where scale = min (p34-q4, (e4 - e3))
          scale = p34 - q4;
          ind = e4 - e3;
          if (ind < scale)
            scale = ind;
          if (scale == 0) {
            ; // res and e4 are unchanged
          } else if (q4 <= 19) { // C4 fits in 64 bits
            if (scale <= 19) { // 10^scale fits in 64 bits
              // 64 x 64 res.w[0] * ten2k64[scale]
              __mul_64x64_to_128MACH (res, res.w[0], ten2k64[scale]);
            } else { // 10^scale fits in 128 bits
              // 64 x 128 res.w[0] * ten2k128[scale - 20]
              __mul_128x64_to_128 (res, res.w[0], ten2k128[scale - 20]);
            }
          } else { // res fits in 128 bits, but 10^scale must fit in 64 bits
            // 64 x 128 ten2k64[scale] * C3
            __mul_128x64_to_128 (res, ten2k64[scale], res);
          }
          // subtract scale from the exponent
          e4 = e4 - scale;
        }
      }

      // check for inexact result
      if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
          is_midpoint_lt_even || is_midpoint_gt_even) {
        // set the inexact flag and the underflow flag
        *pfpsf |= INEXACT_EXCEPTION;
        *pfpsf |= UNDERFLOW_EXCEPTION;
      }
      res.w[1] = p_sign | ((UINT64) (e4 + 6176) << 49) | res.w[1];
      if (rnd_mode != ROUNDING_TO_NEAREST) {
        rounding_correction (rnd_mode,
        		     is_inexact_lt_midpoint,
        		     is_inexact_gt_midpoint,
        		     is_midpoint_lt_even, is_midpoint_gt_even,
        		     e4, &res, pfpsf);
      }
      *pfpsf |= save_fpsf;
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)
    }
    // no overflow, and no underflow for rounding to nearest
    res.w[1] = p_sign | ((UINT64) (e4 + 6176) << 49) | res.w[1];

    if (rnd_mode != ROUNDING_TO_NEAREST) {
      rounding_correction (rnd_mode,
        		   is_inexact_lt_midpoint,
        		   is_inexact_gt_midpoint,
        		   is_midpoint_lt_even, is_midpoint_gt_even,
        		   e4, &res, pfpsf);
      // if e4 = expmin && significand < 10^33 => result is tiny (for RD, RZ)
      if (e4 == expmin) {
        if ((res.w[1] & MASK_COEFF) < 0x0000314dc6448d93ull ||
            ((res.w[1] & MASK_COEFF) == 0x0000314dc6448d93ull &&
             res.w[0] < 0x38c15b0a00000000ull)) {
          is_tiny = 1;
        }
      }
    }

    if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
        is_midpoint_lt_even || is_midpoint_gt_even) {
      // set the inexact flag
      *pfpsf |= INEXACT_EXCEPTION;
      if (is_tiny)
        *pfpsf |= UNDERFLOW_EXCEPTION;
    }

    if ((*pfpsf & INEXACT_EXCEPTION) == 0) { // x * y is exact
      // need to ensure that the result has the preferred exponent
      p_exp = res.w[1] & MASK_EXP;
      if (z_exp < p_exp) { // the preferred exponent is z_exp
        // signficand of res in C3
        C3.w[1] = res.w[1] & MASK_COEFF;
        C3.w[0] = res.w[0];
        // the number of decimal digits of x * y is q4 <= 34
        // Note: the coefficient fits in 128 bits

        // return (C3 * 10^scale) * 10^(p_exp - scale)
        // where scale = min (p34-q4, (p_exp-z_exp) >> 49)
        scale = p34 - q4;
        ind = (p_exp - z_exp) >> 49;
        if (ind < scale)
          scale = ind;
        // subtract scale from the exponent
        p_exp = p_exp - ((UINT64) scale << 49);
        if (scale == 0) {
          ; // leave res unchanged
        } else if (q4 <= 19) { // x * y fits in 64 bits
          if (scale <= 19) { // 10^scale fits in 64 bits
            // 64 x 64 C3.w[0] * ten2k64[scale] 
            __mul_64x64_to_128MACH (res, C3.w[0], ten2k64[scale]);
          } else { // 10^scale fits in 128 bits 
            // 64 x 128 C3.w[0] * ten2k128[scale - 20]
            __mul_128x64_to_128 (res, C3.w[0], ten2k128[scale - 20]);
          }
          res.w[1] = p_sign | (p_exp & MASK_EXP) | res.w[1];
        } else { // x * y fits in 128 bits, but 10^scale must fit in 64 bits
          // 64 x 128 ten2k64[scale] * C3 
          __mul_128x64_to_128 (res, ten2k64[scale], C3);
          res.w[1] = p_sign | (p_exp & MASK_EXP) | res.w[1];
        }
      } // else leave the result as it is, because p_exp <= z_exp
    }
    *pfpsf |= save_fpsf;
    *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
    *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
    *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
    *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
    BID_SWAP128 (res);
    BID_RETURN (res)
  } // else we have f * f + f

  // continue with x = f, y = f, z = f

  delta = q3 + e3 - q4 - e4;
delta_ge_zero:
  if (delta >= 0) {

    if (p34 <= delta - 1 ||	// Case (1')
        (p34 == delta && e3 + 6176 < p34 - q3)) { // Case (1''A)
      // check for overflow, which can occur only in Case (1')
      if ((q3 + e3) > (p34 + expmax) && p34 <= delta - 1) {
        // e3 > expmax implies p34 <= delta-1 and e3 > expmax is a necessary
        // condition for (q3 + e3) > (p34 + expmax)
        if (rnd_mode == ROUNDING_TO_NEAREST) {
          res.w[1] = z_sign | 0x7800000000000000ull; // +/-inf
          res.w[0] = 0x0000000000000000ull;
          *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
        } else {
          if (p_sign == z_sign) {
            is_inexact_lt_midpoint = 1;
          } else {
            is_inexact_gt_midpoint = 1;
          }
          // q3 <= p34; if (q3 < p34) scale C3 up by 10^(p34-q3)
          scale = p34 - q3;
          if (scale == 0) {
            res.w[1] = z_sign | C3.w[1];
            res.w[0] = C3.w[0];
          } else {
            if (q3 <= 19) { // C3 fits in 64 bits
              if (scale <= 19) { // 10^scale fits in 64 bits
        	// 64 x 64 C3.w[0] * ten2k64[scale]
        	__mul_64x64_to_128MACH (res, C3.w[0], ten2k64[scale]);
              } else { // 10^scale fits in 128 bits
        	// 64 x 128 C3.w[0] * ten2k128[scale - 20]
        	__mul_128x64_to_128 (res, C3.w[0],
        			     ten2k128[scale - 20]);
              }
            } else { // C3 fits in 128 bits, but 10^scale must fit in 64 bits
              // 64 x 128 ten2k64[scale] * C3
              __mul_128x64_to_128 (res, ten2k64[scale], C3);
            }
            // the coefficient in res has q3 + scale = p34 digits
          }
          e3 = e3 - scale;
          res.w[1] = z_sign | res.w[1];
          rounding_correction (rnd_mode,
        		       is_inexact_lt_midpoint,
        		       is_inexact_gt_midpoint,
        		       is_midpoint_lt_even, is_midpoint_gt_even,
        		       e3, &res, pfpsf);
        }
        *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
        *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
        *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
        *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
        BID_SWAP128 (res);
        BID_RETURN (res)
      }
      // res = z
      if (q3 < p34) { // the preferred exponent is z_exp - (p34 - q3)
        // return (C3 * 10^scale) * 10^(z_exp - scale)
        // where scale = min (p34-q3, z_exp-EMIN)
        scale = p34 - q3;
        ind = e3 + 6176;
        if (ind < scale)
          scale = ind;
        if (scale == 0) {
          res.w[1] = C3.w[1];
          res.w[0] = C3.w[0];
        } else if (q3 <= 19) { // z fits in 64 bits
          if (scale <= 19) { // 10^scale fits in 64 bits
            // 64 x 64 C3.w[0] * ten2k64[scale]
            __mul_64x64_to_128MACH (res, C3.w[0], ten2k64[scale]);
          } else { // 10^scale fits in 128 bits
            // 64 x 128 C3.w[0] * ten2k128[scale - 20]
            __mul_128x64_to_128 (res, C3.w[0], ten2k128[scale - 20]);
          }
        } else { // z fits in 128 bits, but 10^scale must fit in 64 bits
          // 64 x 128 ten2k64[scale] * C3
          __mul_128x64_to_128 (res, ten2k64[scale], C3);
        }
        // the coefficient in res has q3 + scale digits
        // subtract scale from the exponent
        z_exp = z_exp - ((UINT64) scale << 49);
        e3 = e3 - scale;
        res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
        if (scale + q3 < p34)
          *pfpsf |= UNDERFLOW_EXCEPTION;
      } else {
        scale = 0;
        res.w[1] = z_sign | ((UINT64) (e3 + 6176) << 49) | C3.w[1];
        res.w[0] = C3.w[0];
      }

      // use the following to avoid double rounding errors when operating on
      // mixed formats in rounding to nearest, and for correcting the result
      // if not rounding to nearest
      if ((p_sign != z_sign) && (delta == (q3 + scale + 1))) {
        // there is a gap of exactly one digit between the scaled C3 and C4
        // C3 * 10^ scale = 10^(q3+scale-1) <=> C3 = 10^(q3-1) is special case
        if ((q3 <= 19 && C3.w[0] != ten2k64[q3 - 1]) ||
            (q3 == 20 && (C3.w[1] != 0 || C3.w[0] != ten2k64[19])) ||
            (q3 >= 21 && (C3.w[1] != ten2k128[q3 - 21].w[1] ||
        		  C3.w[0] != ten2k128[q3 - 21].w[0]))) {
          // C3 * 10^ scale != 10^(q3-1)
          // if ((res.w[1] & MASK_COEFF) != 0x0000314dc6448d93ull ||
          // res.w[0] != 0x38c15b0a00000000ull) { // C3 * 10^scale != 10^33
          is_inexact_gt_midpoint = 1; // if (z_sign), set as if for abs. value
        } else { // if C3 * 10^scale = 10^(q3+scale-1)
          // ok from above e3 = (z_exp >> 49) - 6176;
          // the result is always inexact
          if (q4 == 1) {
            R64 = C4.w[0];
          } else {
            // if q4 > 1 then truncate C4 from q4 digits to 1 digit; 
            // x = q4-1, 1 <= x <= 67 and check if this operation is exact
            if (q4 <= 18) { // 2 <= q4 <= 18
              round64_2_18 (q4, q4 - 1, C4.w[0], &R64, &incr_exp,
        		    &is_midpoint_lt_even, &is_midpoint_gt_even,
        		    &is_inexact_lt_midpoint,
        		    &is_inexact_gt_midpoint);
            } else if (q4 <= 38) {
              P128.w[1] = C4.w[1];
              P128.w[0] = C4.w[0];
              round128_19_38 (q4, q4 - 1, P128, &R128, &incr_exp,
        		      &is_midpoint_lt_even,
        		      &is_midpoint_gt_even,
        		      &is_inexact_lt_midpoint,
        		      &is_inexact_gt_midpoint);
              R64 = R128.w[0]; // one decimal digit
            } else if (q4 <= 57) {
              P192.w[2] = C4.w[2];
              P192.w[1] = C4.w[1];
              P192.w[0] = C4.w[0];
              round192_39_57 (q4, q4 - 1, P192, &R192, &incr_exp,
        		      &is_midpoint_lt_even,
        		      &is_midpoint_gt_even,
        		      &is_inexact_lt_midpoint,
        		      &is_inexact_gt_midpoint);
              R64 = R192.w[0]; // one decimal digit
            } else { // if (q4 <= 68)
              round256_58_76 (q4, q4 - 1, C4, &R256, &incr_exp,
        		      &is_midpoint_lt_even,
        		      &is_midpoint_gt_even,
        		      &is_inexact_lt_midpoint,
        		      &is_inexact_gt_midpoint);
              R64 = R256.w[0]; // one decimal digit
            }
            if (incr_exp) {
              R64 = 10;
            }
          }
          if (q4 == 1 && C4.w[0] == 5) {
            is_inexact_lt_midpoint = 0;
            is_inexact_gt_midpoint = 0;
            is_midpoint_lt_even = 1;
            is_midpoint_gt_even = 0;
          } else if ((e3 == expmin) ||
        	     R64 < 5 || (R64 == 5 && is_inexact_gt_midpoint)) {
            // result does not change
            is_inexact_lt_midpoint = 0;
            is_inexact_gt_midpoint = 1;
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 0;
          } else {
            is_inexact_lt_midpoint = 1;
            is_inexact_gt_midpoint = 0;
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 0;
            // result decremented is 10^(q3+scale) - 1
            if ((q3 + scale) <= 19) {
              res.w[1] = 0;
              res.w[0] = ten2k64[q3 + scale];
            } else { // if ((q3 + scale + 1) <= 35)
              res.w[1] = ten2k128[q3 + scale - 20].w[1];
              res.w[0] = ten2k128[q3 + scale - 20].w[0];
            }
            res.w[0] = res.w[0] - 1; // borrow never occurs
            z_exp = z_exp - EXP_P1;
            e3 = e3 - 1;
            res.w[1] = z_sign | ((UINT64) (e3 + 6176) << 49) | res.w[1];
          }
          if (e3 == expmin) {
            if (R64 < 5 || (R64 == 5 && !is_inexact_lt_midpoint)) {
              ; // result not tiny (in round-to-nearest mode)
            } else {
              *pfpsf |= UNDERFLOW_EXCEPTION;
            }
          }
        } // end 10^(q3+scale-1)
        // set the inexact flag
        *pfpsf |= INEXACT_EXCEPTION;
      } else {
        if (p_sign == z_sign) {
          // if (z_sign), set as if for absolute value
          is_inexact_lt_midpoint = 1;
        } else { // if (p_sign != z_sign)
          // if (z_sign), set as if for absolute value
          is_inexact_gt_midpoint = 1;
        }
        *pfpsf |= INEXACT_EXCEPTION;
      }
      // the result is always inexact => set the inexact flag
      // Determine tininess:
      //    if (exp > expmin)
      //      the result is not tiny
      //    else // if exp = emin
      //      if (q3 + scale < p34)
      //        the result is tiny
      //      else // if (q3 + scale = p34)
      //        if (C3 * 10^scale > 10^33)
      //          the result is not tiny
      //        else // if C3 * 10^scale = 10^33
      //          if (xy * z > 0)
      //            the result is not tiny
      //          else // if (xy * z < 0)
      //            if (z > 0)
      //              if rnd_mode != RP
      //                the result is tiny
      //              else // if RP
      //                the result is not tiny
      //            else // if (z < 0)
      //              if rnd_mode != RM
      //                the result is tiny
      //              else // if RM
      //                the result is not tiny
      //              endif
      //            endif
      //          endif
      //        endif
      //      endif
      //    endif 
      if ((e3 == expmin && (q3 + scale) < p34) || 
          (e3 == expmin && (q3 + scale) == p34 && 
          (res.w[1] & MASK_COEFF) == 0x0000314dc6448d93ull &&	// 10^33_high
          res.w[0] == 0x38c15b0a00000000ull &&	// 10^33_low
          z_sign != p_sign && ((!z_sign && rnd_mode != ROUNDING_UP) || 
          (z_sign && rnd_mode != ROUNDING_DOWN)))) {
        *pfpsf |= UNDERFLOW_EXCEPTION;
      }
      if (rnd_mode != ROUNDING_TO_NEAREST) {
        rounding_correction (rnd_mode,
        		     is_inexact_lt_midpoint,
        		     is_inexact_gt_midpoint,
        		     is_midpoint_lt_even, is_midpoint_gt_even,
        		     e3, &res, pfpsf);
      }
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)

    } else if (p34 == delta) { // Case (1''B)

      // because Case (1''A) was treated above, e3 + 6176 >= p34 - q3
      // and C3 can be scaled up to p34 digits if needed

      // scale C3 to p34 digits if needed
      scale = p34 - q3; // 0 <= scale <= p34 - 1
      if (scale == 0) {
        res.w[1] = C3.w[1];
        res.w[0] = C3.w[0];
      } else if (q3 <= 19) { // z fits in 64 bits
        if (scale <= 19) { // 10^scale fits in 64 bits
          // 64 x 64 C3.w[0] * ten2k64[scale]
          __mul_64x64_to_128MACH (res, C3.w[0], ten2k64[scale]);
        } else { // 10^scale fits in 128 bits
          // 64 x 128 C3.w[0] * ten2k128[scale - 20]
          __mul_128x64_to_128 (res, C3.w[0], ten2k128[scale - 20]);
        }
      } else { // z fits in 128 bits, but 10^scale must fit in 64 bits
        // 64 x 128 ten2k64[scale] * C3
        __mul_128x64_to_128 (res, ten2k64[scale], C3);
      }
      // subtract scale from the exponent
      z_exp = z_exp - ((UINT64) scale << 49);
      e3 = e3 - scale;
      // now z_sign, z_exp, and res correspond to a z scaled to p34 = 34 digits

      // determine whether x * y is less than, equal to, or greater than 
      // 1/2 ulp (z)
      if (q4 <= 19) {
        if (C4.w[0] < midpoint64[q4 - 1]) { // < 1/2 ulp
          lt_half_ulp = 1;
        } else if (C4.w[0] == midpoint64[q4 - 1]) { // = 1/2 ulp
          eq_half_ulp = 1;
        } else { // > 1/2 ulp
          gt_half_ulp = 1;
        }
      } else if (q4 <= 38) {
        if (C4.w[2] == 0 && (C4.w[1] < midpoint128[q4 - 20].w[1] || 
            (C4.w[1] == midpoint128[q4 - 20].w[1] && 
            C4.w[0] < midpoint128[q4 - 20].w[0]))) { // < 1/2 ulp
          lt_half_ulp = 1;
        } else if (C4.w[2] == 0 && C4.w[1] == midpoint128[q4 - 20].w[1] && 
            C4.w[0] == midpoint128[q4 - 20].w[0]) { // = 1/2 ulp
          eq_half_ulp = 1;
        } else { // > 1/2 ulp
          gt_half_ulp = 1;
        }
      } else if (q4 <= 58) {
        if (C4.w[3] == 0 && (C4.w[2] < midpoint192[q4 - 39].w[2] || 
            (C4.w[2] == midpoint192[q4 - 39].w[2] && 
            C4.w[1] < midpoint192[q4 - 39].w[1]) || 
            (C4.w[2] == midpoint192[q4 - 39].w[2] && 
            C4.w[1] == midpoint192[q4 - 39].w[1] && 
            C4.w[0] < midpoint192[q4 - 39].w[0]))) { // < 1/2 ulp
          lt_half_ulp = 1;
        } else if (C4.w[3] == 0 && C4.w[2] == midpoint192[q4 - 39].w[2] && 
            C4.w[1] == midpoint192[q4 - 39].w[1] && 
            C4.w[0] == midpoint192[q4 - 39].w[0]) { // = 1/2 ulp
          eq_half_ulp = 1;
        } else { // > 1/2 ulp
          gt_half_ulp = 1;
        }
      } else {
        if (C4.w[3] < midpoint256[q4 - 59].w[3] || 
            (C4.w[3] == midpoint256[q4 - 59].w[3] && 
            C4.w[2] < midpoint256[q4 - 59].w[2]) || 
            (C4.w[3] == midpoint256[q4 - 59].w[3] && 
            C4.w[2] == midpoint256[q4 - 59].w[2] && 
            C4.w[1] < midpoint256[q4 - 59].w[1]) || 
            (C4.w[3] == midpoint256[q4 - 59].w[3] && 
            C4.w[2] == midpoint256[q4 - 59].w[2] && 
            C4.w[1] == midpoint256[q4 - 59].w[1] && 
            C4.w[0] < midpoint256[q4 - 59].w[0])) { // < 1/2 ulp
          lt_half_ulp = 1;
        } else if (C4.w[3] == midpoint256[q4 - 59].w[3] && 
            C4.w[2] == midpoint256[q4 - 59].w[2] && 
            C4.w[1] == midpoint256[q4 - 59].w[1] && 
            C4.w[0] == midpoint256[q4 - 59].w[0]) { // = 1/2 ulp
          eq_half_ulp = 1;
        } else { // > 1/2 ulp
          gt_half_ulp = 1;
        }
      }

      if (p_sign == z_sign) {
        if (lt_half_ulp) {
          res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
          // use the following to avoid double rounding errors when operating on
          // mixed formats in rounding to nearest
          is_inexact_lt_midpoint = 1; // if (z_sign), as if for absolute value
        } else if ((eq_half_ulp && (res.w[0] & 0x01)) || gt_half_ulp) {
          // add 1 ulp to the significand
          res.w[0]++;
          if (res.w[0] == 0x0ull)
            res.w[1]++;
          // check for rounding overflow, when coeff == 10^34
          if ((res.w[1] & MASK_COEFF) == 0x0001ed09bead87c0ull && 
              res.w[0] == 0x378d8e6400000000ull) { // coefficient = 10^34
            e3 = e3 + 1;
            // coeff = 10^33
            z_exp = ((UINT64) (e3 + 6176) << 49) & MASK_EXP;
            res.w[1] = 0x0000314dc6448d93ull;
            res.w[0] = 0x38c15b0a00000000ull;
          }
          // end add 1 ulp
          res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
          if (eq_half_ulp) {
            is_midpoint_lt_even = 1; // if (z_sign), as if for absolute value
          } else {
            is_inexact_gt_midpoint = 1; // if (z_sign), as if for absolute value
          }
        } else { // if (eq_half_ulp && !(res.w[0] & 0x01))
          // leave unchanged 
          res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
          is_midpoint_gt_even = 1; // if (z_sign), as if for absolute value
        }
        // the result is always inexact, and never tiny
        // set the inexact flag
        *pfpsf |= INEXACT_EXCEPTION;
        // check for overflow
        if (e3 > expmax && rnd_mode == ROUNDING_TO_NEAREST) {
          res.w[1] = z_sign | 0x7800000000000000ull; // +/-inf
          res.w[0] = 0x0000000000000000ull;
          *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
          *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
          *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
          *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
          *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
          BID_SWAP128 (res);
          BID_RETURN (res)
        }
        if (rnd_mode != ROUNDING_TO_NEAREST) {
          rounding_correction (rnd_mode,
        		       is_inexact_lt_midpoint,
        		       is_inexact_gt_midpoint,
        		       is_midpoint_lt_even, is_midpoint_gt_even,
        		       e3, &res, pfpsf);
          z_exp = res.w[1] & MASK_EXP;
        }
      } else { // if (p_sign != z_sign)
        // consider two cases, because C3 * 10^scale = 10^33 is a special case
        if (res.w[1] != 0x0000314dc6448d93ull || 
            res.w[0] != 0x38c15b0a00000000ull) { // C3 * 10^scale != 10^33
          if (lt_half_ulp) {
            res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
            // use the following to avoid double rounding errors when operating
            // on mixed formats in rounding to nearest
            is_inexact_gt_midpoint = 1; // if (z_sign), as if for absolute value
          } else if ((eq_half_ulp && (res.w[0] & 0x01)) || gt_half_ulp) {
            // subtract 1 ulp from the significand
            res.w[0]--;
            if (res.w[0] == 0xffffffffffffffffull)
              res.w[1]--;
            res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
            if (eq_half_ulp) {
              is_midpoint_gt_even = 1; // if (z_sign), as if for absolute value
            } else {
              is_inexact_lt_midpoint = 1; //if(z_sign), as if for absolute value
            }
          } else { // if (eq_half_ulp && !(res.w[0] & 0x01))
            // leave unchanged
            res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
            is_midpoint_lt_even = 1; // if (z_sign), as if for absolute value
          }
          // the result is always inexact, and never tiny
          // check for overflow for RN
          if (e3 > expmax) {
            if (rnd_mode == ROUNDING_TO_NEAREST) {
              res.w[1] = z_sign | 0x7800000000000000ull; // +/-inf
              res.w[0] = 0x0000000000000000ull;
              *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
            } else {
              rounding_correction (rnd_mode,
        			   is_inexact_lt_midpoint,
        			   is_inexact_gt_midpoint,
        			   is_midpoint_lt_even,
        			   is_midpoint_gt_even, e3, &res,
        			   pfpsf);
            }
            *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
            *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
            *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
            *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
            BID_SWAP128 (res);
            BID_RETURN (res)
          }
          // set the inexact flag
          *pfpsf |= INEXACT_EXCEPTION;
          if (rnd_mode != ROUNDING_TO_NEAREST) {
            rounding_correction (rnd_mode,
        			 is_inexact_lt_midpoint,
        			 is_inexact_gt_midpoint,
        			 is_midpoint_lt_even,
        			 is_midpoint_gt_even, e3, &res, pfpsf);
          }
          z_exp = res.w[1] & MASK_EXP;
        } else { // if C3 * 10^scale = 10^33
          e3 = (z_exp >> 49) - 6176;
          if (e3 > expmin) {
            // the result is exact if exp > expmin and C4 = d*10^(q4-1), 
            // where d = 1, 2, 3, ..., 9; it could be tiny too, but exact
            if (q4 == 1) {
              // if q4 = 1 the result is exact
              // result coefficient = 10^34 - C4
              res.w[1] = 0x0001ed09bead87c0ull;
              res.w[0] = 0x378d8e6400000000ull - C4.w[0];
              z_exp = z_exp - EXP_P1;
              e3 = e3 - 1;
              res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
            } else {
              // if q4 > 1 then truncate C4 from q4 digits to 1 digit; 
              // x = q4-1, 1 <= x <= 67 and check if this operation is exact
              if (q4 <= 18) { // 2 <= q4 <= 18
        	round64_2_18 (q4, q4 - 1, C4.w[0], &R64, &incr_exp,
        		      &is_midpoint_lt_even,
        		      &is_midpoint_gt_even,
        		      &is_inexact_lt_midpoint,
        		      &is_inexact_gt_midpoint);
              } else if (q4 <= 38) {
        	P128.w[1] = C4.w[1];
        	P128.w[0] = C4.w[0];
        	round128_19_38 (q4, q4 - 1, P128, &R128, &incr_exp,
        			&is_midpoint_lt_even,
        			&is_midpoint_gt_even,
        			&is_inexact_lt_midpoint,
        			&is_inexact_gt_midpoint);
        	R64 = R128.w[0]; // one decimal digit
              } else if (q4 <= 57) {
        	P192.w[2] = C4.w[2];
        	P192.w[1] = C4.w[1];
        	P192.w[0] = C4.w[0];
        	round192_39_57 (q4, q4 - 1, P192, &R192, &incr_exp,
        			&is_midpoint_lt_even,
        			&is_midpoint_gt_even,
        			&is_inexact_lt_midpoint,
        			&is_inexact_gt_midpoint);
        	R64 = R192.w[0]; // one decimal digit
              } else { // if (q4 <= 68)
        	round256_58_76 (q4, q4 - 1, C4, &R256, &incr_exp,
        			&is_midpoint_lt_even,
        			&is_midpoint_gt_even,
        			&is_inexact_lt_midpoint,
        			&is_inexact_gt_midpoint);
        	R64 = R256.w[0]; // one decimal digit
              }
              if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	  !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
        	// the result is exact: 10^34 - R64
        	// incr_exp = 0 with certainty
        	z_exp = z_exp - EXP_P1;
        	e3 = e3 - 1;
        	res.w[1] =
        	  z_sign | (z_exp & MASK_EXP) | 0x0001ed09bead87c0ull;
        	res.w[0] = 0x378d8e6400000000ull - R64;
              } else {
        	// We want R64 to be the top digit of C4, but we actually 
        	// obtained (C4 * 10^(-q4+1))RN; a correction may be needed,
        	// because the top digit is (C4 * 10^(-q4+1))RZ
        	// however, if incr_exp = 1 then R64 = 10 with certainty
        	if (incr_exp) {
        	  R64 = 10;
        	}
        	// the result is inexact as C4 has more than 1 significant digit
        	// and C3 * 10^scale = 10^33
        	// example of case that is treated here:
        	// 100...0 * 10^e3 - 0.41 * 10^e3 =
        	// 0999...9.59 * 10^e3 -> rounds to 99...96*10^(e3-1)
        	// note that (e3 > expmin}
        	// in order to round, subtract R64 from 10^34 and then compare
        	// C4 - R64 * 10^(q4-1) with 1/2 ulp
        	// calculate 10^34 - R64
        	res.w[1] = 0x0001ed09bead87c0ull;
        	res.w[0] = 0x378d8e6400000000ull - R64;
        	z_exp = z_exp - EXP_P1; // will be OR-ed with sign & significand
        	// calculate C4 - R64 * 10^(q4-1); this is a rare case and
        	// R64 is small, 1 <= R64 <= 9
        	e3 = e3 - 1;
        	if (is_inexact_lt_midpoint) {
        	  is_inexact_lt_midpoint = 0;
        	  is_inexact_gt_midpoint = 1;
        	} else if (is_inexact_gt_midpoint) {
        	  is_inexact_gt_midpoint = 0;
        	  is_inexact_lt_midpoint = 1;
        	} else if (is_midpoint_lt_even) {
        	  is_midpoint_lt_even = 0;
        	  is_midpoint_gt_even = 1;
        	} else if (is_midpoint_gt_even) {
        	  is_midpoint_gt_even = 0;
        	  is_midpoint_lt_even = 1;
        	} else {
        	  ;
        	}
        	// the result is always inexact, and never tiny
        	// check for overflow for RN
        	if (e3 > expmax) {
        	  if (rnd_mode == ROUNDING_TO_NEAREST) {
        	    res.w[1] = z_sign | 0x7800000000000000ull; // +/-inf
        	    res.w[0] = 0x0000000000000000ull;
        	    *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
        	  } else {
        	    rounding_correction (rnd_mode,
        				 is_inexact_lt_midpoint,
        				 is_inexact_gt_midpoint,
        				 is_midpoint_lt_even,
        				 is_midpoint_gt_even, e3, &res,
        				 pfpsf);
        	  }
        	  *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
        	  *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
        	  *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
        	  *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
        	  BID_SWAP128 (res);
        	  BID_RETURN (res)
        	}
        	// set the inexact flag
        	*pfpsf |= INEXACT_EXCEPTION;
        	res.w[1] =
        	  z_sign | ((UINT64) (e3 + 6176) << 49) | res.w[1];
        	if (rnd_mode != ROUNDING_TO_NEAREST) {
        	  rounding_correction (rnd_mode,
        			       is_inexact_lt_midpoint,
        			       is_inexact_gt_midpoint,
        			       is_midpoint_lt_even,
        			       is_midpoint_gt_even, e3, &res,
        			       pfpsf);
        	}
        	z_exp = res.w[1] & MASK_EXP;
              } // end result is inexact
            } // end q4 > 1
          } else { // if (e3 = emin)
            // if e3 = expmin the result is also tiny (the condition for
            // tininess is C4 > 050...0 [q4 digits] which is met because
            // the msd of C4 is not zero)
            // the result is tiny and inexact in all rounding modes;
            // it is either 100...0 or 0999...9 (use lt_half_ulp, eq_half_ulp, 
            // gt_half_ulp to calculate)
            // if (lt_half_ulp || eq_half_ulp) res = 10^33 stays unchanged

            // p_sign != z_sign so swap gt_half_ulp and lt_half_ulp
            if (gt_half_ulp) { // res = 10^33 - 1
              res.w[1] = 0x0000314dc6448d93ull;
              res.w[0] = 0x38c15b09ffffffffull;
            } else {
              res.w[1] = 0x0000314dc6448d93ull;
              res.w[0] = 0x38c15b0a00000000ull;
            }
            res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
            *pfpsf |= UNDERFLOW_EXCEPTION; // inexact is set later

            if (eq_half_ulp) {
              is_midpoint_lt_even = 1; // if (z_sign), as if for absolute value
            } else if (lt_half_ulp) {
              is_inexact_gt_midpoint = 1; //if(z_sign), as if for absolute value
            } else { // if (gt_half_ulp)
              is_inexact_lt_midpoint = 1; //if(z_sign), as if for absolute value
            }

            if (rnd_mode != ROUNDING_TO_NEAREST) {
              rounding_correction (rnd_mode,
                  is_inexact_lt_midpoint,
                  is_inexact_gt_midpoint,
                  is_midpoint_lt_even,
                  is_midpoint_gt_even, e3, &res,
                  pfpsf);
              z_exp = res.w[1] & MASK_EXP;
            }
          } // end e3 = emin
          // set the inexact flag (if the result was not exact)
          if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
              is_midpoint_lt_even || is_midpoint_gt_even)
            *pfpsf |= INEXACT_EXCEPTION;
        } // end 10^33
      } // end if (p_sign != z_sign)
      res.w[1] = z_sign | (z_exp & MASK_EXP) | res.w[1];
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)

    } else if (((q3 <= delta && delta < p34 && p34 < delta + q4) || // Case (2)
        (q3 <= delta && delta + q4 <= p34) || // Case (3)
        (delta < q3 && p34 < delta + q4) || // Case (4)
        (delta < q3 && q3 <= delta + q4 && delta + q4 <= p34) || // Case (5)
        (delta + q4 < q3)) && // Case (6)
        !(delta <= 1 && p_sign != z_sign)) { // Case (2), (3), (4), (5) or (6)

      // the result has the sign of z

      if ((q3 <= delta && delta < p34 && p34 < delta + q4) || // Case (2)
          (delta < q3 && p34 < delta + q4)) { // Case (4)
        // round first the sum x * y + z with unbounded exponent
        // scale C3 up by scale = p34 - q3, 1 <= scale <= p34-1, 
        // 1 <= scale <= 33
        // calculate res = C3 * 10^scale
        scale = p34 - q3;
        x0 = delta + q4 - p34;
      } else if (delta + q4 < q3) { // Case (6)
        // make Case (6) look like Case (3) or Case (5) with scale = 0
        // by scaling up C4 by 10^(q3 - delta - q4) 
        scale = q3 - delta - q4; // 1 <= scale <= 33
        if (q4 <= 19) { // 1 <= scale <= 19; C4 fits in 64 bits
          if (scale <= 19) { // 10^scale fits in 64 bits
            // 64 x 64 C4.w[0] * ten2k64[scale]
            __mul_64x64_to_128MACH (P128, C4.w[0], ten2k64[scale]);
          } else { // 10^scale fits in 128 bits
            // 64 x 128 C4.w[0] * ten2k128[scale - 20]
            __mul_128x64_to_128 (P128, C4.w[0], ten2k128[scale - 20]);
          }
        } else { // C4 fits in 128 bits, but 10^scale must fit in 64 bits
          // 64 x 128 ten2k64[scale] * C4
          __mul_128x64_to_128 (P128, ten2k64[scale], C4);
        }
        C4.w[0] = P128.w[0];
        C4.w[1] = P128.w[1];
        // e4 does not need adjustment, as it is not used from this point on
        scale = 0;
        x0 = 0;
        // now Case (6) looks like Case (3) or Case (5) with scale = 0 
      } else { // if Case (3) or Case (5)
        // Note: Case (3) is similar to Case (2), but scale differs and the
        // result is exact, unless it is tiny (so x0 = 0 when calculating the
        // result with unbounded exponent)

        // calculate first the sum x * y + z with unbounded exponent (exact)
        // scale C3 up by scale = delta + q4 - q3, 1 <= scale <= p34-1,
        // 1 <= scale <= 33
        // calculate res = C3 * 10^scale
        scale = delta + q4 - q3;
        x0 = 0;
        // Note: the comments which follow refer [mainly] to Case (2)]
      }

    case2_repeat:
      if (scale == 0) { // this could happen e.g. if we return to case2_repeat
        // or in Case (4)
        res.w[1] = C3.w[1];
        res.w[0] = C3.w[0];
      } else if (q3 <= 19) { // 1 <= scale <= 19; z fits in 64 bits
        if (scale <= 19) { // 10^scale fits in 64 bits
          // 64 x 64 C3.w[0] * ten2k64[scale]
          __mul_64x64_to_128MACH (res, C3.w[0], ten2k64[scale]);
        } else { // 10^scale fits in 128 bits
          // 64 x 128 C3.w[0] * ten2k128[scale - 20]
          __mul_128x64_to_128 (res, C3.w[0], ten2k128[scale - 20]);
        }
      } else { // z fits in 128 bits, but 10^scale must fit in 64 bits
        // 64 x 128 ten2k64[scale] * C3
        __mul_128x64_to_128 (res, ten2k64[scale], C3);
      }
      // e3 is already calculated
      e3 = e3 - scale;
      // now res = C3 * 10^scale and e3 = e3 - scale
      // Note: C3 * 10^scale could be 10^34 if we returned to case2_repeat
      // because the result was too small

      // round C4 to nearest to q4 - x0 digits, where x0 = delta + q4 - p34,
      // 1 <= x0 <= min (q4 - 1, 2 * p34 - 1) <=> 1 <= x0 <= min (q4 - 1, 67)
      // Also: 1 <= q4 - x0 <= p34 -1 => 1 <= q4 - x0 <= 33 (so the result of
      // the rounding fits in 128 bits!)
      // x0 = delta + q4 - p34 (calculated before reaching case2_repeat)
      // because q3 + q4 - x0 <= P => x0 >= q3 + q4 - p34
      if (x0 == 0) { // this could happen only if we return to case2_repeat, or
        // for Case (3) or Case (6)
        R128.w[1] = C4.w[1];
        R128.w[0] = C4.w[0];
      } else if (q4 <= 18) {
        // 2 <= q4 <= 18, max(1, q3+q4-p34) <= x0 <= q4 - 1, 1 <= x0 <= 17
        round64_2_18 (q4, x0, C4.w[0], &R64, &incr_exp,
            &is_midpoint_lt_even, &is_midpoint_gt_even,
            &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
        if (incr_exp) {
          // R64 = 10^(q4-x0), 1 <= q4 - x0 <= q4 - 1, 1 <= q4 - x0 <= 17
          R64 = ten2k64[q4 - x0];
        }
        R128.w[1] = 0;
        R128.w[0] = R64;
      } else if (q4 <= 38) {
        // 19 <= q4 <= 38, max(1, q3+q4-p34) <= x0 <= q4 - 1, 1 <= x0 <= 37
        P128.w[1] = C4.w[1];
        P128.w[0] = C4.w[0];
        round128_19_38 (q4, x0, P128, &R128, &incr_exp,
            &is_midpoint_lt_even, &is_midpoint_gt_even,
            &is_inexact_lt_midpoint,
            &is_inexact_gt_midpoint);
        if (incr_exp) {
          // R128 = 10^(q4-x0), 1 <= q4 - x0 <= q4 - 1, 1 <= q4 - x0 <= 37
          if (q4 - x0 <= 19) { // 1 <= q4 - x0 <= 19
            R128.w[0] = ten2k64[q4 - x0];
            // R128.w[1] stays 0
          } else { // 20 <= q4 - x0 <= 37
            R128.w[0] = ten2k128[q4 - x0 - 20].w[0];
            R128.w[1] = ten2k128[q4 - x0 - 20].w[1];
          }
        }
      } else if (q4 <= 57) {
        // 38 <= q4 <= 57, max(1, q3+q4-p34) <= x0 <= q4 - 1, 5 <= x0 <= 56
        P192.w[2] = C4.w[2];
        P192.w[1] = C4.w[1];
        P192.w[0] = C4.w[0];
        round192_39_57 (q4, x0, P192, &R192, &incr_exp,
            &is_midpoint_lt_even, &is_midpoint_gt_even,
            &is_inexact_lt_midpoint,
            &is_inexact_gt_midpoint);
        // R192.w[2] is always 0
        if (incr_exp) {
          // R192 = 10^(q4-x0), 1 <= q4 - x0 <= q4 - 5, 1 <= q4 - x0 <= 52
          if (q4 - x0 <= 19) { // 1 <= q4 - x0 <= 19
            R192.w[0] = ten2k64[q4 - x0];
            // R192.w[1] stays 0
            // R192.w[2] stays 0
          } else { // 20 <= q4 - x0 <= 33
            R192.w[0] = ten2k128[q4 - x0 - 20].w[0];
            R192.w[1] = ten2k128[q4 - x0 - 20].w[1];
            // R192.w[2] stays 0
          }
        }
        R128.w[1] = R192.w[1];
        R128.w[0] = R192.w[0];
      } else {
        // 58 <= q4 <= 68, max(1, q3+q4-p34) <= x0 <= q4 - 1, 25 <= x0 <= 67
        round256_58_76 (q4, x0, C4, &R256, &incr_exp,
            &is_midpoint_lt_even, &is_midpoint_gt_even,
            &is_inexact_lt_midpoint,
            &is_inexact_gt_midpoint);
        // R256.w[3] and R256.w[2] are always 0
        if (incr_exp) {
          // R256 = 10^(q4-x0), 1 <= q4 - x0 <= q4 - 25, 1 <= q4 - x0 <= 43
          if (q4 - x0 <= 19) { // 1 <= q4 - x0 <= 19  
            R256.w[0] = ten2k64[q4 - x0];
            // R256.w[1] stays 0
            // R256.w[2] stays 0
            // R256.w[3] stays 0
          } else { // 20 <= q4 - x0 <= 33 
            R256.w[0] = ten2k128[q4 - x0 - 20].w[0];
            R256.w[1] = ten2k128[q4 - x0 - 20].w[1];
            // R256.w[2] stays 0
            // R256.w[3] stays 0
          }
        }
        R128.w[1] = R256.w[1];
        R128.w[0] = R256.w[0];
      }
      // now add C3 * 10^scale in res and the signed top (q4-x0) digits of C4,
      // rounded to nearest, which were copied into R128
      if (z_sign == p_sign) {
        lsb = res.w[0] & 0x01; // lsb of C3 * 10^scale
        // the sum can result in [up to] p34 or p34 + 1 digits
        res.w[0] = res.w[0] + R128.w[0];
        res.w[1] = res.w[1] + R128.w[1];
        if (res.w[0] < R128.w[0])
          res.w[1]++; // carry
        // if res > 10^34 - 1 need to increase x0 and decrease scale by 1
        if (res.w[1] > 0x0001ed09bead87c0ull ||
            (res.w[1] == 0x0001ed09bead87c0ull &&
             res.w[0] > 0x378d8e63ffffffffull)) {
          // avoid double rounding error
          is_inexact_lt_midpoint0 = is_inexact_lt_midpoint;
          is_inexact_gt_midpoint0 = is_inexact_gt_midpoint;
          is_midpoint_lt_even0 = is_midpoint_lt_even;
          is_midpoint_gt_even0 = is_midpoint_gt_even;
          is_inexact_lt_midpoint = 0;
          is_inexact_gt_midpoint = 0;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
          P128.w[1] = res.w[1];
          P128.w[0] = res.w[0];
          round128_19_38 (35, 1, P128, &res, &incr_exp,
              &is_midpoint_lt_even, &is_midpoint_gt_even,
              &is_inexact_lt_midpoint,
              &is_inexact_gt_midpoint);
          // incr_exp is 0 with certainty in this case
          // avoid a double rounding error
          if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
              is_midpoint_lt_even) { // double rounding error upward
            // res = res - 1
            res.w[0]--;
            if (res.w[0] == 0xffffffffffffffffull)
              res.w[1]--;
            // Note: a double rounding error upward is not possible; for this
            // the result after the first rounding would have to be 99...95
            // (35 digits in all), possibly followed by a number of zeros; this
            // not possible in Cases (2)-(6) or (15)-(17) which may get here
            is_midpoint_lt_even = 0;
            is_inexact_lt_midpoint = 1;
          } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
              is_midpoint_gt_even) { // double rounding error downward
            // res = res + 1
            res.w[0]++;
            if (res.w[0] == 0)
              res.w[1]++;
            is_midpoint_gt_even = 0;
            is_inexact_gt_midpoint = 1;
          } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	     !is_inexact_lt_midpoint
        	     && !is_inexact_gt_midpoint) {
            // if this second rounding was exact the result may still be 
            // inexact because of the first rounding
            if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
              is_inexact_gt_midpoint = 1;
            }
            if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
              is_inexact_lt_midpoint = 1;
            }
          } else if (is_midpoint_gt_even &&
        	     (is_inexact_gt_midpoint0
        	      || is_midpoint_lt_even0)) {
            // pulled up to a midpoint
            is_inexact_lt_midpoint = 1;
            is_inexact_gt_midpoint = 0;
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 0;
          } else if (is_midpoint_lt_even &&
        	     (is_inexact_lt_midpoint0
        	      || is_midpoint_gt_even0)) {
            // pulled down to a midpoint
            is_inexact_lt_midpoint = 0;
            is_inexact_gt_midpoint = 1;
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 0;
          } else {
            ;
          }
          // adjust exponent
          e3 = e3 + 1;
          if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
              !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
            if (is_midpoint_lt_even0 || is_midpoint_gt_even0 ||
        	is_inexact_lt_midpoint0 || is_inexact_gt_midpoint0) {
              is_inexact_lt_midpoint = 1;
            }
          }
        } else {
          // this is the result rounded with unbounded exponent, unless a
          // correction is needed
          res.w[1] = res.w[1] & MASK_COEFF;
          if (lsb == 1) {
            if (is_midpoint_gt_even) {
              // res = res + 1
              is_midpoint_gt_even = 0;
              is_midpoint_lt_even = 1;
              res.w[0]++;
              if (res.w[0] == 0x0)
        	res.w[1]++;
              // check for rounding overflow
              if (res.w[1] == 0x0001ed09bead87c0ull &&
        	  res.w[0] == 0x378d8e6400000000ull) {
        	// res = 10^34 => rounding overflow
        	res.w[1] = 0x0000314dc6448d93ull;
        	res.w[0] = 0x38c15b0a00000000ull; // 10^33
        	e3++;
              }
            } else if (is_midpoint_lt_even) {
              // res = res - 1
              is_midpoint_lt_even = 0;
              is_midpoint_gt_even = 1;
              res.w[0]--;
              if (res.w[0] == 0xffffffffffffffffull)
        	res.w[1]--;
              // if the result is pure zero, the sign depends on the rounding 
              // mode (x*y and z had opposite signs)
              if (res.w[1] == 0x0ull && res.w[0] == 0x0ull) {
        	if (rnd_mode != ROUNDING_DOWN)
        	  z_sign = 0x0000000000000000ull;
        	else
        	  z_sign = 0x8000000000000000ull;
        	// the exponent is max (e3, expmin)
        	res.w[1] = 0x0;
        	res.w[0] = 0x0;
        	*ptr_is_midpoint_lt_even = is_midpoint_lt_even;
        	*ptr_is_midpoint_gt_even = is_midpoint_gt_even;
        	*ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
        	*ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
        	BID_SWAP128 (res);
        	BID_RETURN (res)
              }
            } else {
              ;
            }
          }
        }
      } else { // if (z_sign != p_sign)
        lsb = res.w[0] & 0x01; // lsb of C3 * 10^scale; R128 contains rounded C4
        // used to swap rounding indicators if p_sign != z_sign
        // the sum can result in [up to] p34 or p34 - 1 digits
        tmp64 = res.w[0];
        res.w[0] = res.w[0] - R128.w[0];
        res.w[1] = res.w[1] - R128.w[1];
        if (res.w[0] > tmp64)
          res.w[1]--; // borrow
        // if res < 10^33 and exp > expmin need to decrease x0 and 
        // increase scale by 1
        if (e3 > expmin && ((res.w[1] < 0x0000314dc6448d93ull ||
        		     (res.w[1] == 0x0000314dc6448d93ull &&
        		      res.w[0] < 0x38c15b0a00000000ull)) ||
        		    (is_inexact_lt_midpoint
        		     && res.w[1] == 0x0000314dc6448d93ull
        		     && res.w[0] == 0x38c15b0a00000000ull))
            && x0 >= 1) {
          x0 = x0 - 1;
          // first restore e3, otherwise it will be too small
          e3 = e3 + scale;
          scale = scale + 1;
          is_inexact_lt_midpoint = 0;
          is_inexact_gt_midpoint = 0;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
          incr_exp = 0;
          goto case2_repeat;
        }
        // else this is the result rounded with unbounded exponent;
        // because the result has opposite sign to that of C4 which was 
        // rounded, need to change the rounding indicators
        if (is_inexact_lt_midpoint) {
          is_inexact_lt_midpoint = 0;
          is_inexact_gt_midpoint = 1;
        } else if (is_inexact_gt_midpoint) {
          is_inexact_gt_midpoint = 0;
          is_inexact_lt_midpoint = 1;
        } else if (lsb == 0) {
          if (is_midpoint_lt_even) {
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 1;
          } else if (is_midpoint_gt_even) {
            is_midpoint_gt_even = 0;
            is_midpoint_lt_even = 1;
          } else {
            ;
          }
        } else if (lsb == 1) {
          if (is_midpoint_lt_even) {
            // res = res + 1
            res.w[0]++;
            if (res.w[0] == 0x0)
              res.w[1]++;
            // check for rounding overflow
            if (res.w[1] == 0x0001ed09bead87c0ull &&
        	res.w[0] == 0x378d8e6400000000ull) {
              // res = 10^34 => rounding overflow
              res.w[1] = 0x0000314dc6448d93ull;
              res.w[0] = 0x38c15b0a00000000ull; // 10^33
              e3++;
            }
          } else if (is_midpoint_gt_even) {
            // res = res - 1
            res.w[0]--;
            if (res.w[0] == 0xffffffffffffffffull)
              res.w[1]--;
            // if the result is pure zero, the sign depends on the rounding 
            // mode (x*y and z had opposite signs)
            if (res.w[1] == 0x0ull && res.w[0] == 0x0ull) {
              if (rnd_mode != ROUNDING_DOWN)
        	z_sign = 0x0000000000000000ull;
              else
        	z_sign = 0x8000000000000000ull;
              // the exponent is max (e3, expmin)
              res.w[1] = 0x0;
              res.w[0] = 0x0;
              *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
              *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
              *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
              *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
              BID_SWAP128 (res);
              BID_RETURN (res)
            }
          } else {
            ;
          }
        } else {
          ;
        }
      }
      // check for underflow
      if (e3 == expmin) { // and if significand < 10^33 => result is tiny
        if ((res.w[1] & MASK_COEFF) < 0x0000314dc6448d93ull ||
            ((res.w[1] & MASK_COEFF) == 0x0000314dc6448d93ull &&
             res.w[0] < 0x38c15b0a00000000ull)) {
          is_tiny = 1;
        }
      } else if (e3 < expmin) {
        // the result is tiny, so we must truncate more of res
        is_tiny = 1;
        x0 = expmin - e3;
        is_inexact_lt_midpoint0 = is_inexact_lt_midpoint;
        is_inexact_gt_midpoint0 = is_inexact_gt_midpoint;
        is_midpoint_lt_even0 = is_midpoint_lt_even;
        is_midpoint_gt_even0 = is_midpoint_gt_even;
        is_inexact_lt_midpoint = 0;
        is_inexact_gt_midpoint = 0;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;
        // determine the number of decimal digits in res
        if (res.w[1] == 0x0) {
          // between 1 and 19 digits
          for (ind = 1; ind <= 19; ind++) {
            if (res.w[0] < ten2k64[ind]) {
              break;
            }
          }
          // ind digits
        } else if (res.w[1] < ten2k128[0].w[1] ||
        	   (res.w[1] == ten2k128[0].w[1]
        	    && res.w[0] < ten2k128[0].w[0])) {
          // 20 digits
          ind = 20;
        } else { // between 21 and 38 digits
          for (ind = 1; ind <= 18; ind++) {
            if (res.w[1] < ten2k128[ind].w[1] ||
        	(res.w[1] == ten2k128[ind].w[1] &&
        	 res.w[0] < ten2k128[ind].w[0])) {
              break;
            }
          }
          // ind + 20 digits
          ind = ind + 20;
        }

        // at this point ind >= x0; because delta >= 2 on this path, the case
        // ind = x0 can occur only in Case (2) or case (3), when C3 has one
        // digit (q3 = 1) equal to 1 (C3 = 1), e3 is expmin (e3 = expmin), 
        // the signs of x * y and z are opposite, and through cancellation 
        // the most significant decimal digit in res has the weight
        // 10^(emin-1); however, it is clear that in this case the most
        // significant digit is 9, so the result before rounding is
        // 0.9... * 10^emin
        // Otherwise, ind > x0 because there are non-zero decimal digits in the
        // result with weight of at least 10^emin, and correction for underflow
        //  can be carried out using the round*_*_2_* () routines
        if (x0 == ind) { // the result before rounding is 0.9... * 10^emin
          res.w[1] = 0x0;
          res.w[0] = 0x1;
          is_inexact_gt_midpoint = 1;
        } else if (ind <= 18) { // check that 2 <= ind
          // 2 <= ind <= 18, 1 <= x0 <= 17
          round64_2_18 (ind, x0, res.w[0], &R64, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
          if (incr_exp) {
            // R64 = 10^(ind-x0), 1 <= ind - x0 <= ind - 1, 1 <= ind - x0 <= 17
            R64 = ten2k64[ind - x0];
          }
          res.w[1] = 0;
          res.w[0] = R64;
        } else if (ind <= 38) {
          // 19 <= ind <= 38
          P128.w[1] = res.w[1];
          P128.w[0] = res.w[0];
          round128_19_38 (ind, x0, P128, &res, &incr_exp,
        		  &is_midpoint_lt_even, &is_midpoint_gt_even,
        		  &is_inexact_lt_midpoint,
        		  &is_inexact_gt_midpoint);
          if (incr_exp) {
            // R128 = 10^(ind-x0), 1 <= ind - x0 <= ind - 1, 1 <= ind - x0 <= 37
            if (ind - x0 <= 19) { // 1 <= ind - x0 <= 19
              res.w[0] = ten2k64[ind - x0];
              // res.w[1] stays 0
            } else { // 20 <= ind - x0 <= 37
              res.w[0] = ten2k128[ind - x0 - 20].w[0];
              res.w[1] = ten2k128[ind - x0 - 20].w[1];
            }
          }
        }
        // avoid a double rounding error
        if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
            is_midpoint_lt_even) { // double rounding error upward
          // res = res - 1
          res.w[0]--;
          if (res.w[0] == 0xffffffffffffffffull)
            res.w[1]--;
          // Note: a double rounding error upward is not possible; for this
          // the result after the first rounding would have to be 99...95
          // (35 digits in all), possibly followed by a number of zeros; this
          // not possible in Cases (2)-(6) which may get here
          is_midpoint_lt_even = 0;
          is_inexact_lt_midpoint = 1;
        } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
            is_midpoint_gt_even) { // double rounding error downward
          // res = res + 1
          res.w[0]++;
          if (res.w[0] == 0)
            res.w[1]++;
          is_midpoint_gt_even = 0;
          is_inexact_gt_midpoint = 1;
        } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	   !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
          // if this second rounding was exact the result may still be 
          // inexact because of the first rounding
          if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
            is_inexact_gt_midpoint = 1;
          }
          if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
            is_inexact_lt_midpoint = 1;
          }
        } else if (is_midpoint_gt_even &&
        	   (is_inexact_gt_midpoint0 || is_midpoint_lt_even0)) {
          // pulled up to a midpoint
          is_inexact_lt_midpoint = 1;
          is_inexact_gt_midpoint = 0;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
        } else if (is_midpoint_lt_even &&
        	   (is_inexact_lt_midpoint0 || is_midpoint_gt_even0)) {
          // pulled down to a midpoint
          is_inexact_lt_midpoint = 0;
          is_inexact_gt_midpoint = 1;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
        } else {
          ;
        }
        // adjust exponent
        e3 = e3 + x0;
        if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
            !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
          if (is_midpoint_lt_even0 || is_midpoint_gt_even0 ||
              is_inexact_lt_midpoint0 || is_inexact_gt_midpoint0) {
            is_inexact_lt_midpoint = 1;
          }
        }
      } else {
        ; // not underflow
      }
      // check for inexact result
      if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
          is_midpoint_lt_even || is_midpoint_gt_even) {
        // set the inexact flag
        *pfpsf |= INEXACT_EXCEPTION;
        if (is_tiny)
          *pfpsf |= UNDERFLOW_EXCEPTION;
      }
      // now check for significand = 10^34 (may have resulted from going
      // back to case2_repeat)
      if (res.w[1] == 0x0001ed09bead87c0ull && 
          res.w[0] == 0x378d8e6400000000ull) { // if  res = 10^34
        res.w[1] = 0x0000314dc6448d93ull; // res = 10^33
        res.w[0] = 0x38c15b0a00000000ull;
        e3 = e3 + 1;
      }
      res.w[1] = z_sign | ((UINT64) (e3 + 6176) << 49) | res.w[1];
      // check for overflow
      if (rnd_mode == ROUNDING_TO_NEAREST && e3 > expmax) {
        res.w[1] = z_sign | 0x7800000000000000ull; // +/-inf
        res.w[0] = 0x0000000000000000ull;
        *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
      }
      if (rnd_mode != ROUNDING_TO_NEAREST) {
        rounding_correction (rnd_mode,
        		     is_inexact_lt_midpoint,
        		     is_inexact_gt_midpoint,
        		     is_midpoint_lt_even, is_midpoint_gt_even,
        		     e3, &res, pfpsf);
      }
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)

    } else {

      // we get here only if delta <= 1 in Cases (2), (3), (4), (5), or (6) and
      // the signs of x*y and z are opposite; in these cases massive
      // cancellation can occur, so it is better to scale either C3 or C4 and 
      // to perform the subtraction before rounding; rounding is performed 
      // next, depending on the number of decimal digits in the result and on 
      // the exponent value
      // Note: overlow is not possible in this case
      // this is similar to Cases (15), (16), and (17)

      if (delta + q4 < q3) { // from Case (6) 
        // Case (6) with 0<= delta <= 1 is similar to Cases (15), (16), and 
        // (17) if we swap (C3, C4), (q3, q4), (e3, e4), (z_sign, p_sign)
        // and call add_and_round; delta stays positive
        // C4.w[3] = 0 and C4.w[2] = 0, so swap just the low part of C4 with C3
        P128.w[1] = C3.w[1];
        P128.w[0] = C3.w[0];
        C3.w[1] = C4.w[1];
        C3.w[0] = C4.w[0];
        C4.w[1] = P128.w[1];
        C4.w[0] = P128.w[0];
        ind = q3;
        q3 = q4;
        q4 = ind;
        ind = e3;
        e3 = e4;
        e4 = ind;
        tmp_sign = z_sign;
        z_sign = p_sign;
        p_sign = tmp_sign;
      } else { // from Cases (2), (3), (4), (5)
        // In Cases (2), (3), (4), (5) with 0 <= delta <= 1 C3 has to be 
        // scaled up by q4 + delta - q3; this is the same as in Cases (15), 
        // (16), and (17) if we just change the sign of delta
        delta = -delta;
      }
      add_and_round (q3, q4, e4, delta, p34, z_sign, p_sign, C3, C4,
        	     rnd_mode, &is_midpoint_lt_even,
        	     &is_midpoint_gt_even, &is_inexact_lt_midpoint,
        	     &is_inexact_gt_midpoint, pfpsf, &res);
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)

    }

  } else { // if delta < 0

    delta = -delta;

    if (p34 < q4 && q4 <= delta) { // Case (7)

      // truncate C4 to p34 digits into res
      // x = q4-p34, 1 <= x <= 34 because 35 <= q4 <= 68
      x0 = q4 - p34;
      if (q4 <= 38) {
        P128.w[1] = C4.w[1];
        P128.w[0] = C4.w[0];
        round128_19_38 (q4, x0, P128, &res, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
      } else if (q4 <= 57) { // 35 <= q4 <= 57
        P192.w[2] = C4.w[2];
        P192.w[1] = C4.w[1];
        P192.w[0] = C4.w[0];
        round192_39_57 (q4, x0, P192, &R192, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
        res.w[0] = R192.w[0];
        res.w[1] = R192.w[1];
      } else { // if (q4 <= 68)
        round256_58_76 (q4, x0, C4, &R256, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
        res.w[0] = R256.w[0];
        res.w[1] = R256.w[1];
      }
      e4 = e4 + x0;
      if (incr_exp) {
        e4 = e4 + 1;
      }
      if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
          !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
        // if C4 rounded to p34 digits is exact then the result is inexact,
        // in a way that depends on the signs of x * y and z
        if (p_sign == z_sign) {
          is_inexact_lt_midpoint = 1;
        } else { // if (p_sign != z_sign)
          if (res.w[1] != 0x0000314dc6448d93ull || 
              res.w[0] != 0x38c15b0a00000000ull) { // res != 10^33
            is_inexact_gt_midpoint = 1;
          } else { // res = 10^33 and exact is a special case
            // if C3 < 1/2 ulp then res = 10^33 and is_inexact_gt_midpoint = 1
            // if C3 = 1/2 ulp then res = 10^33 and is_midpoint_lt_even = 1
            // if C3 > 1/2 ulp then res = 10^34-1 and is_inexact_lt_midpoint = 1
            // Note: ulp is really ulp/10 (after borrow which propagates to msd)
            if (delta > p34 + 1) { // C3 < 1/2
              // res = 10^33, unchanged
              is_inexact_gt_midpoint = 1;
            } else { // if (delta == p34 + 1)
              if (q3 <= 19) {
        	if (C3.w[0] < midpoint64[q3 - 1]) { // C3 < 1/2 ulp
        	  // res = 10^33, unchanged
        	  is_inexact_gt_midpoint = 1;
        	} else if (C3.w[0] == midpoint64[q3 - 1]) { // C3 = 1/2 ulp
        	  // res = 10^33, unchanged
        	  is_midpoint_lt_even = 1;
        	} else { // if (C3.w[0] > midpoint64[q3-1]), C3 > 1/2 ulp
        	  res.w[1] = 0x0001ed09bead87c0ull; // 10^34 - 1
        	  res.w[0] = 0x378d8e63ffffffffull;
        	  e4 = e4 - 1;
        	  is_inexact_lt_midpoint = 1;
        	}
              } else { // if (20 <= q3 <=34)
        	if (C3.w[1] < midpoint128[q3 - 20].w[1] || 
                    (C3.w[1] == midpoint128[q3 - 20].w[1] && 
                    C3.w[0] < midpoint128[q3 - 20].w[0])) { // C3 < 1/2 ulp
        	  // res = 10^33, unchanged
        	  is_inexact_gt_midpoint = 1;
        	} else if (C3.w[1] == midpoint128[q3 - 20].w[1] && 
                    C3.w[0] == midpoint128[q3 - 20].w[0]) { // C3 = 1/2 ulp
        	  // res = 10^33, unchanged
        	  is_midpoint_lt_even = 1;
        	} else { // if (C3 > midpoint128[q3-20]), C3 > 1/2 ulp
        	  res.w[1] = 0x0001ed09bead87c0ull; // 10^34 - 1
        	  res.w[0] = 0x378d8e63ffffffffull;
        	  e4 = e4 - 1;
        	  is_inexact_lt_midpoint = 1;
        	}
              }
            }
          }
        }
      } else if (is_midpoint_lt_even) {
        if (z_sign != p_sign) {
          // needs correction: res = res - 1
          res.w[0] = res.w[0] - 1;
          if (res.w[0] == 0xffffffffffffffffull)
            res.w[1]--;
          // if it is (10^33-1)*10^e4 then the corect result is 
          // (10^34-1)*10(e4-1)
          if (res.w[1] == 0x0000314dc6448d93ull &&
              res.w[0] == 0x38c15b09ffffffffull) {
            res.w[1] = 0x0001ed09bead87c0ull; // 10^34 - 1
            res.w[0] = 0x378d8e63ffffffffull;
            e4 = e4 - 1;
          }
          is_midpoint_lt_even = 0;
          is_inexact_lt_midpoint = 1;
        } else { // if (z_sign == p_sign)
          is_midpoint_lt_even = 0;
          is_inexact_gt_midpoint = 1;
        }
      } else if (is_midpoint_gt_even) {
        if (z_sign == p_sign) {
          // needs correction: res = res + 1 (cannot cross in the next binade)
          res.w[0] = res.w[0] + 1;
          if (res.w[0] == 0x0000000000000000ull)
            res.w[1]++;
          is_midpoint_gt_even = 0;
          is_inexact_gt_midpoint = 1;
        } else { // if (z_sign != p_sign)
          is_midpoint_gt_even = 0;
          is_inexact_lt_midpoint = 1;
        }
      } else {
        ; // the rounded result is already correct
      }
      // check for overflow
      if (rnd_mode == ROUNDING_TO_NEAREST && e4 > expmax) {
        res.w[1] = p_sign | 0x7800000000000000ull;
        res.w[0] = 0x0000000000000000ull;
        *pfpsf |= (OVERFLOW_EXCEPTION | INEXACT_EXCEPTION);
      } else { // no overflow or not RN
        p_exp = ((UINT64) (e4 + 6176) << 49);
        res.w[1] = p_sign | (p_exp & MASK_EXP) | res.w[1];
      }
      if (rnd_mode != ROUNDING_TO_NEAREST) {
        rounding_correction (rnd_mode,
        		     is_inexact_lt_midpoint,
        		     is_inexact_gt_midpoint,
        		     is_midpoint_lt_even, is_midpoint_gt_even,
        		     e4, &res, pfpsf);
      }
      if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
          is_midpoint_lt_even || is_midpoint_gt_even) {
        // set the inexact flag
        *pfpsf |= INEXACT_EXCEPTION;
      }
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)

    } else if ((q4 <= p34 && p34 <= delta) || // Case (8)
        (q4 <= delta && delta < p34 && p34 < delta + q3) || // Case (9)
        (q4 <= delta && delta + q3 <= p34) || // Case (10)
        (delta < q4 && q4 <= p34 && p34 < delta + q3) || // Case (13)
        (delta < q4 && q4 <= delta + q3 && delta + q3 <= p34) || // Case (14)
        (delta + q3 < q4 && q4 <= p34)) { // Case (18)

      // Case (8) is similar to Case (1), with C3 and C4 swapped
      // Case (9) is similar to Case (2), with C3 and C4 swapped
      // Case (10) is similar to Case (3), with C3 and C4 swapped
      // Case (13) is similar to Case (4), with C3 and C4 swapped
      // Case (14) is similar to Case (5), with C3 and C4 swapped
      // Case (18) is similar to Case (6), with C3 and C4 swapped

      // swap (C3, C4), (q3, q4), (e3, 34), (z_sign, p_sign), (z_exp, p_exp)
      // and go back to delta_ge_zero
      // C4.w[3] = 0 and C4.w[2] = 0, so swap just the low part of C4 with C3
      P128.w[1] = C3.w[1];
      P128.w[0] = C3.w[0];
      C3.w[1] = C4.w[1];
      C3.w[0] = C4.w[0];
      C4.w[1] = P128.w[1];
      C4.w[0] = P128.w[0];
      ind = q3;
      q3 = q4;
      q4 = ind;
      ind = e3;
      e3 = e4;
      e4 = ind;
      tmp_sign = z_sign;
      z_sign = p_sign;
      p_sign = tmp_sign;
      tmp.ui64 = z_exp;
      z_exp = p_exp;
      p_exp = tmp.ui64;
      goto delta_ge_zero;

    } else if ((p34 <= delta && delta < q4 && q4 < delta + q3) || // Case (11)
               (delta < p34 && p34 < q4 && q4 < delta + q3)) { // Case (12)

      // round C3 to nearest to q3 - x0 digits, where x0 = e4 - e3,
      // 1 <= x0 <= q3 - 1 <= p34 - 1 
      x0 = e4 - e3; // or x0 = delta + q3 - q4
      if (q3 <= 18) { // 2 <= q3 <= 18
        round64_2_18 (q3, x0, C3.w[0], &R64, &incr_exp,
        	      &is_midpoint_lt_even, &is_midpoint_gt_even,
        	      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
        // C3.w[1] = 0;
        C3.w[0] = R64;
      } else if (q3 <= 38) {
        round128_19_38 (q3, x0, C3, &R128, &incr_exp,
        		&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint);
        C3.w[1] = R128.w[1];
        C3.w[0] = R128.w[0];
      }
      // the rounded result has q3 - x0 digits
      // we want the exponent to be e4, so if incr_exp = 1 then
      // multiply the rounded result by 10 - it will still fit in 113 bits
      if (incr_exp) {
        // 64 x 128 -> 128
        P128.w[1] = C3.w[1];
        P128.w[0] = C3.w[0];
        __mul_64x128_to_128 (C3, ten2k64[1], P128);
      }
      e3 = e3 + x0; // this is e4
      // now add/subtract the 256-bit C4 and the new (and shorter) 128-bit C3; 
      // the result will have the sign of x * y; the exponent is e4
      R256.w[3] = 0;
      R256.w[2] = 0;
      R256.w[1] = C3.w[1];
      R256.w[0] = C3.w[0];
      if (p_sign == z_sign) { // R256 = C4 + R256
        add256 (C4, R256, &R256);
      } else { // if (p_sign != z_sign) { // R256 = C4 - R256
        sub256 (C4, R256, &R256); // the result cannot be pure zero
        // because the result has opposite sign to that of R256 which was 
        // rounded, need to change the rounding indicators
        lsb = C4.w[0] & 0x01;
        if (is_inexact_lt_midpoint) {
          is_inexact_lt_midpoint = 0;
          is_inexact_gt_midpoint = 1;
        } else if (is_inexact_gt_midpoint) {
          is_inexact_gt_midpoint = 0;
          is_inexact_lt_midpoint = 1;
        } else if (lsb == 0) {
          if (is_midpoint_lt_even) {
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 1;
          } else if (is_midpoint_gt_even) {
            is_midpoint_gt_even = 0;
            is_midpoint_lt_even = 1;
          } else {
            ;
          }
        } else if (lsb == 1) {
          if (is_midpoint_lt_even) {
            // res = res + 1
            R256.w[0]++;
            if (R256.w[0] == 0x0) {
              R256.w[1]++;
              if (R256.w[1] == 0x0) {
        	R256.w[2]++;
        	if (R256.w[2] == 0x0) {
        	  R256.w[3]++;
        	}
              }
            }
            // no check for rounding overflow - R256 was a difference
          } else if (is_midpoint_gt_even) {
            // res = res - 1
            R256.w[0]--;
            if (R256.w[0] == 0xffffffffffffffffull) {
              R256.w[1]--;
              if (R256.w[1] == 0xffffffffffffffffull) {
        	R256.w[2]--;
        	if (R256.w[2] == 0xffffffffffffffffull) {
        	  R256.w[3]--;
        	}
              }
            }
          } else {
            ;
          }
        } else {
          ;
        }
      }
      // determine the number of decimal digits in R256
      ind = nr_digits256 (R256); // ind >= p34
      // if R256 is sum, then ind > p34; if R256 is a difference, then 
      // ind >= p34; this means that we can calculate the result rounded to
      // the destination precision, with unbounded exponent, starting from R256
      // and using the indicators from the rounding of C3 to avoid a double
      // rounding error 

      if (ind < p34) {
        ;
      } else if (ind == p34) {
        // the result rounded to the destination precision with 
        // unbounded exponent
        // is (-1)^p_sign * R256 * 10^e4
        res.w[1] = R256.w[1];
        res.w[0] = R256.w[0];
      } else { // if (ind > p34)
        // if more than P digits, round to nearest to P digits
        // round R256 to p34 digits
        x0 = ind - p34; // 1 <= x0 <= 34 as 35 <= ind <= 68
        // save C3 rounding indicators to help avoid double rounding error
        is_inexact_lt_midpoint0 = is_inexact_lt_midpoint;
        is_inexact_gt_midpoint0 = is_inexact_gt_midpoint;
        is_midpoint_lt_even0 = is_midpoint_lt_even;
        is_midpoint_gt_even0 = is_midpoint_gt_even;
        // initialize rounding indicators
        is_inexact_lt_midpoint = 0;
        is_inexact_gt_midpoint = 0;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;
        // round to p34 digits; the result fits in 113 bits
        if (ind <= 38) {
          P128.w[1] = R256.w[1];
          P128.w[0] = R256.w[0];
          round128_19_38 (ind, x0, P128, &R128, &incr_exp,
        		  &is_midpoint_lt_even, &is_midpoint_gt_even,
        		  &is_inexact_lt_midpoint,
        		  &is_inexact_gt_midpoint);
        } else if (ind <= 57) {
          P192.w[2] = R256.w[2];
          P192.w[1] = R256.w[1];
          P192.w[0] = R256.w[0];
          round192_39_57 (ind, x0, P192, &R192, &incr_exp,
        		  &is_midpoint_lt_even, &is_midpoint_gt_even,
        		  &is_inexact_lt_midpoint,
        		  &is_inexact_gt_midpoint);
          R128.w[1] = R192.w[1];
          R128.w[0] = R192.w[0];
        } else { // if (ind <= 68)
          round256_58_76 (ind, x0, R256, &R256, &incr_exp,
        		  &is_midpoint_lt_even, &is_midpoint_gt_even,
        		  &is_inexact_lt_midpoint,
        		  &is_inexact_gt_midpoint);
          R128.w[1] = R256.w[1];
          R128.w[0] = R256.w[0];
        }
        // the rounded result has p34 = 34 digits
        e4 = e4 + x0 + incr_exp;

        res.w[1] = R128.w[1];
        res.w[0] = R128.w[0];

        // avoid a double rounding error
        if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
            is_midpoint_lt_even) { // double rounding error upward
          // res = res - 1
          res.w[0]--;
          if (res.w[0] == 0xffffffffffffffffull)
            res.w[1]--;
          is_midpoint_lt_even = 0;
          is_inexact_lt_midpoint = 1;
          // Note: a double rounding error upward is not possible; for this
          // the result after the first rounding would have to be 99...95
          // (35 digits in all), possibly followed by a number of zeros; this
          // not possible in Cases (2)-(6) or (15)-(17) which may get here
          // if this is 10^33 - 1 make it 10^34 - 1 and decrement exponent
          if (res.w[1] == 0x0000314dc6448d93ull && 
            res.w[0] == 0x38c15b09ffffffffull) { // 10^33 - 1
            res.w[1] = 0x0001ed09bead87c0ull; // 10^34 - 1
            res.w[0] = 0x378d8e63ffffffffull;
            e4--;
          }
        } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
            is_midpoint_gt_even) { // double rounding error downward
          // res = res + 1 
          res.w[0]++;
          if (res.w[0] == 0)
            res.w[1]++;
          is_midpoint_gt_even = 0;
          is_inexact_gt_midpoint = 1;
        } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	   !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
          // if this second rounding was exact the result may still be
          // inexact because of the first rounding
          if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
            is_inexact_gt_midpoint = 1;
          }
          if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
            is_inexact_lt_midpoint = 1;
          }
        } else if (is_midpoint_gt_even &&
        	   (is_inexact_gt_midpoint0 || is_midpoint_lt_even0)) {
          // pulled up to a midpoint
          is_inexact_lt_midpoint = 1;
          is_inexact_gt_midpoint = 0;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
        } else if (is_midpoint_lt_even &&
        	   (is_inexact_lt_midpoint0 || is_midpoint_gt_even0)) {
          // pulled down to a midpoint
          is_inexact_lt_midpoint = 0;
          is_inexact_gt_midpoint = 1;
          is_midpoint_lt_even = 0;
          is_midpoint_gt_even = 0;
        } else {
          ;
        }
      }

      // determine tininess
      if (rnd_mode == ROUNDING_TO_NEAREST) {
        if (e4 < expmin) {
          is_tiny = 1; // for other rounding modes apply correction
        }
      } else {
        // for RM, RP, RZ, RA apply correction in order to determine tininess
        // but do not save the result; apply the correction to 
        // (-1)^p_sign * res * 10^0
        P128.w[1] = p_sign | 0x3040000000000000ull | res.w[1];
        P128.w[0] = res.w[0];
        rounding_correction (rnd_mode,
        		     is_inexact_lt_midpoint,
        		     is_inexact_gt_midpoint,
        		     is_midpoint_lt_even, is_midpoint_gt_even,
        		     0, &P128, pfpsf);
        scale = ((P128.w[1] & MASK_EXP) >> 49) - 6176; // -1, 0, or +1
        // the number of digits in the significand is p34 = 34
        if (e4 + scale < expmin) {
          is_tiny = 1;
        }
      }

      // the result rounded to the destination precision with unbounded exponent
      // is (-1)^p_sign * res * 10^e4
      res.w[1] = p_sign | ((UINT64) (e4 + 6176) << 49) | res.w[1]; // RN
      // res.w[0] unchanged;
      // Note: res is correct only if expmin <= e4 <= expmax
      ind = p34; // the number of decimal digits in the signifcand of res

      // at this point we have the result rounded with unbounded exponent in
      // res and we know its tininess:
      // res = (-1)^p_sign * significand * 10^e4, 
      // where q (significand) = ind = p34
      // Note: res is correct only if expmin <= e4 <= expmax

      // check for overflow if RN
      if (rnd_mode == ROUNDING_TO_NEAREST
          && (ind + e4) > (p34 + expmax)) {
        res.w[1] = p_sign | 0x7800000000000000ull;
        res.w[0] = 0x0000000000000000ull;
        *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
        *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
        *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
        *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
        *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
        BID_SWAP128 (res);
        BID_RETURN (res)
      } // else not overflow or not RN, so continue

      // from this point on this is similar to the last part of the computation
      // for Cases (15), (16), (17)

      // if (e4 >= expmin) we have the result rounded with bounded exponent
      if (e4 < expmin) {
        x0 = expmin - e4; // x0 >= 1; the number of digits to chop off of res
        // where the result rounded [at most] once is
        //   (-1)^p_sign * significand_res * 10^e4

        // avoid double rounding error
        is_inexact_lt_midpoint0 = is_inexact_lt_midpoint;
        is_inexact_gt_midpoint0 = is_inexact_gt_midpoint;
        is_midpoint_lt_even0 = is_midpoint_lt_even;
        is_midpoint_gt_even0 = is_midpoint_gt_even;
        is_inexact_lt_midpoint = 0;
        is_inexact_gt_midpoint = 0;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;

        if (x0 > ind) {
          // nothing is left of res when moving the decimal point left x0 digits
          is_inexact_lt_midpoint = 1;
          res.w[1] = p_sign | 0x0000000000000000ull;
          res.w[0] = 0x0000000000000000ull;
          e4 = expmin;
        } else if (x0 == ind) { // 1 <= x0 = ind <= p34 = 34
          // this is <, =, or > 1/2 ulp
          // compare the ind-digit value in the significand of res with
          // 1/2 ulp = 5*10^(ind-1), i.e. determine whether it is 
          // less than, equal to, or greater than 1/2 ulp (significand of res)
          R128.w[1] = res.w[1] & MASK_COEFF;
          R128.w[0] = res.w[0];
          if (ind <= 19) {
            if (R128.w[0] < midpoint64[ind - 1]) { // < 1/2 ulp
              lt_half_ulp = 1;
              is_inexact_lt_midpoint = 1;
            } else if (R128.w[0] == midpoint64[ind - 1]) { // = 1/2 ulp
              eq_half_ulp = 1;
              is_midpoint_gt_even = 1;
            } else { // > 1/2 ulp
              gt_half_ulp = 1;
              is_inexact_gt_midpoint = 1;
            }
          } else { // if (ind <= 38)
            if (R128.w[1] < midpoint128[ind - 20].w[1] || 
                (R128.w[1] == midpoint128[ind - 20].w[1] && 
                R128.w[0] < midpoint128[ind - 20].w[0])) { // < 1/2 ulp
              lt_half_ulp = 1;
              is_inexact_lt_midpoint = 1;
            } else if (R128.w[1] == midpoint128[ind - 20].w[1] && 
                R128.w[0] == midpoint128[ind - 20].w[0]) { // = 1/2 ulp
              eq_half_ulp = 1;
              is_midpoint_gt_even = 1;
            } else { // > 1/2 ulp
              gt_half_ulp = 1;
              is_inexact_gt_midpoint = 1;
            }
          }
          if (lt_half_ulp || eq_half_ulp) {
            // res = +0.0 * 10^expmin
            res.w[1] = 0x0000000000000000ull;
            res.w[0] = 0x0000000000000000ull;
          } else { // if (gt_half_ulp)
            // res = +1 * 10^expmin
            res.w[1] = 0x0000000000000000ull;
            res.w[0] = 0x0000000000000001ull;
          }
          res.w[1] = p_sign | res.w[1];
          e4 = expmin;
        } else { // if (1 <= x0 <= ind - 1 <= 33)
          // round the ind-digit result to ind - x0 digits

          if (ind <= 18) { // 2 <= ind <= 18
            round64_2_18 (ind, x0, res.w[0], &R64, &incr_exp,
        		  &is_midpoint_lt_even, &is_midpoint_gt_even,
        		  &is_inexact_lt_midpoint,
        		  &is_inexact_gt_midpoint);
            res.w[1] = 0x0;
            res.w[0] = R64;
          } else if (ind <= 38) {
            P128.w[1] = res.w[1] & MASK_COEFF;
            P128.w[0] = res.w[0];
            round128_19_38 (ind, x0, P128, &res, &incr_exp,
        		    &is_midpoint_lt_even, &is_midpoint_gt_even,
        		    &is_inexact_lt_midpoint,
        		    &is_inexact_gt_midpoint);
          }
          e4 = e4 + x0; // expmin
          // we want the exponent to be expmin, so if incr_exp = 1 then
          // multiply the rounded result by 10 - it will still fit in 113 bits
          if (incr_exp) {
            // 64 x 128 -> 128
            P128.w[1] = res.w[1] & MASK_COEFF;
            P128.w[0] = res.w[0];
            __mul_64x128_to_128 (res, ten2k64[1], P128);
          }
          res.w[1] =
            p_sign | ((UINT64) (e4 + 6176) << 49) | (res.
        					     w[1] & MASK_COEFF);
          // avoid a double rounding error
          if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
                is_midpoint_lt_even) { // double rounding error upward
            // res = res - 1
            res.w[0]--;
            if (res.w[0] == 0xffffffffffffffffull)
              res.w[1]--;
            // Note: a double rounding error upward is not possible; for this
            // the result after the first rounding would have to be 99...95
            // (35 digits in all), possibly followed by a number of zeros; this
            // not possible in this underflow case
            is_midpoint_lt_even = 0;
            is_inexact_lt_midpoint = 1;
          } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
                is_midpoint_gt_even) { // double rounding error downward
            // res = res + 1
            res.w[0]++;
            if (res.w[0] == 0)
              res.w[1]++;
            is_midpoint_gt_even = 0;
            is_inexact_gt_midpoint = 1;
          } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	     !is_inexact_lt_midpoint
        	     && !is_inexact_gt_midpoint) {
            // if this second rounding was exact the result may still be 
            // inexact because of the first rounding
            if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
              is_inexact_gt_midpoint = 1;
            }
            if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
              is_inexact_lt_midpoint = 1;
            }
          } else if (is_midpoint_gt_even &&
        	     (is_inexact_gt_midpoint0
        	      || is_midpoint_lt_even0)) {
            // pulled up to a midpoint
            is_inexact_lt_midpoint = 1;
            is_inexact_gt_midpoint = 0;
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 0;
          } else if (is_midpoint_lt_even &&
        	     (is_inexact_lt_midpoint0
        	      || is_midpoint_gt_even0)) {
            // pulled down to a midpoint
            is_inexact_lt_midpoint = 0;
            is_inexact_gt_midpoint = 1;
            is_midpoint_lt_even = 0;
            is_midpoint_gt_even = 0;
          } else {
            ;
          }
        }
      }
      // res contains the correct result
      // apply correction if not rounding to nearest
      if (rnd_mode != ROUNDING_TO_NEAREST) {
        rounding_correction (rnd_mode,
        		     is_inexact_lt_midpoint,
        		     is_inexact_gt_midpoint,
        		     is_midpoint_lt_even, is_midpoint_gt_even,
        		     e4, &res, pfpsf);
      }
      if (is_midpoint_lt_even || is_midpoint_gt_even ||
          is_inexact_lt_midpoint || is_inexact_gt_midpoint) {
        // set the inexact flag
        *pfpsf |= INEXACT_EXCEPTION;
        if (is_tiny)
          *pfpsf |= UNDERFLOW_EXCEPTION;
      }
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)

    } else if ((p34 <= delta && delta + q3 <= q4) || // Case (15)
        (delta < p34 && p34 < delta + q3 && delta + q3 <= q4) || //Case (16)
        (delta + q3 <= p34 && p34 < q4)) { // Case (17)

      // calculate first the result rounded to the destination precision, with
      // unbounded exponent

      add_and_round (q3, q4, e4, delta, p34, z_sign, p_sign, C3, C4,
              rnd_mode, &is_midpoint_lt_even,
              &is_midpoint_gt_even, &is_inexact_lt_midpoint,
              &is_inexact_gt_midpoint, pfpsf, &res);
      *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
      *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
      *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
      *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
      BID_SWAP128 (res);
      BID_RETURN (res)

    } else {
      ;
    }

  } // end if delta < 0

  *ptr_is_midpoint_lt_even = is_midpoint_lt_even;
  *ptr_is_midpoint_gt_even = is_midpoint_gt_even;
  *ptr_is_inexact_lt_midpoint = is_inexact_lt_midpoint;
  *ptr_is_inexact_gt_midpoint = is_inexact_gt_midpoint;
  BID_SWAP128 (res);
  BID_RETURN (res)

}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128_fma (UINT128 * pres, UINT128 * px, UINT128 * py, UINT128 * pz
            _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
            _EXC_INFO_PARAM) {
  UINT128 x = *px, y = *py, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128_fma (UINT128 x, UINT128 y, UINT128 z
            _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
            _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even, is_midpoint_gt_even,
    is_inexact_lt_midpoint, is_inexact_gt_midpoint;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };

#if DECIMAL_CALL_BY_REFERENCE
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, &x, &y, &z
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x, y,
        		z _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128ddd_fma (UINT128 * pres, UINT64 * px, UINT64 * py, UINT64 * pz
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
  UINT64 x = *px, y = *py, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128ddd_fma (UINT64 x, UINT64 y, UINT64 z
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 x1, y1, z1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&z1, &z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, &x1, &y1, &z1
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  z1 = bid64_to_bid128 (z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x1, y1,
        		z1 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128ddq_fma (UINT128 * pres, UINT64 * px, UINT64 * py, UINT128 * pz
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
  UINT64 x = *px, y = *py;
  UINT128 z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128ddq_fma (UINT64 x, UINT64 y, UINT128 z
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 x1, y1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, &x1, &y1, &z
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x1, y1,
        		z _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128dqd_fma (UINT128 * pres, UINT64 * px, UINT128 * py, UINT64 * pz
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
  UINT64 x = *px, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128dqd_fma (UINT64 x, UINT128 y, UINT64 z
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 x1, z1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&z1, &z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, &x1, py, &z1
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  z1 = bid64_to_bid128 (z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x1, y,
        		z1 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128dqq_fma (UINT128 * pres, UINT64 * px, UINT128 * py, UINT128 * pz
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
  UINT64 x = *px;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128dqq_fma (UINT64 x, UINT128 y, UINT128 z
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 x1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, &x1, py, pz
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x1, y,
        		z _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128qdd_fma (UINT128 * pres, UINT128 * px, UINT64 * py, UINT64 * pz
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
  UINT64 y = *py, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128qdd_fma (UINT128 x, UINT64 y, UINT64 z
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 y1, z1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&z1, &z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, px, &y1, &z1
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  z1 = bid64_to_bid128 (z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x, y1,
        		z1 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128qdq_fma (UINT128 * pres, UINT128 * px, UINT64 * py, UINT128 * pz
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
  UINT64 y = *py;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128qdq_fma (UINT128 x, UINT64 y, UINT128 z
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 y1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, px, &y1, pz
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x, y1,
        		z _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid128qqd_fma (UINT128 * pres, UINT128 * px, UINT128 * py, UINT64 * pz
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
  UINT64 z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT128
bid128qqd_fma (UINT128 x, UINT128 y, UINT64 z
               _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
               _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 z1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&z1, &z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        	  &is_inexact_lt_midpoint, &is_inexact_gt_midpoint,
        	  &res, px, py, &z1
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  z1 = bid64_to_bid128 (z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res = bid128_ext_fma (&is_midpoint_lt_even, &is_midpoint_gt_even,
        		&is_inexact_lt_midpoint,
        		&is_inexact_gt_midpoint, x, y,
        		z1 _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif
  BID_RETURN (res);
}

// Note: bid128qqq_fma is represented by bid128_fma

// Note: bid64ddd_fma is represented by bid64_fma

#if DECIMAL_CALL_BY_REFERENCE
void
bid64ddq_fma (UINT64 * pres, UINT64 * px, UINT64 * py, UINT128 * pz
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
  UINT64 x = *px, y = *py;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT64
bid64ddq_fma (UINT64 x, UINT64 y, UINT128 z
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
#endif
  UINT64 res1 = 0xbaddbaddbaddbaddull;
  UINT128 x1, y1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64qqq_fma (&res1, &x1, &y1, pz
        	_RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	_EXC_INFO_ARG);
#else
  x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res1 = bid64qqq_fma (x1, y1, z
        	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	       _EXC_INFO_ARG);
#endif
  BID_RETURN (res1);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid64dqd_fma (UINT64 * pres, UINT64 * px, UINT128 * py, UINT64 * pz
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
  UINT64 x = *px, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT64
bid64dqd_fma (UINT64 x, UINT128 y, UINT64 z
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
#endif
  UINT64 res1 = 0xbaddbaddbaddbaddull;
  UINT128 x1, z1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&z1, &z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64qqq_fma (&res1, &x1, py, &z1
        	_RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	_EXC_INFO_ARG);
#else
  x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  z1 = bid64_to_bid128 (z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res1 = bid64qqq_fma (x1, y, z1
        	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	       _EXC_INFO_ARG);
#endif
  BID_RETURN (res1);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid64dqq_fma (UINT64 * pres, UINT64 * px, UINT128 * py, UINT128 * pz
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
  UINT64 x = *px;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT64
bid64dqq_fma (UINT64 x, UINT128 y, UINT128 z
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
#endif
  UINT64 res1 = 0xbaddbaddbaddbaddull;
  UINT128 x1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&x1, &x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64qqq_fma (&res1, &x1, py, pz
        	_RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	_EXC_INFO_ARG);
#else
  x1 = bid64_to_bid128 (x _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res1 = bid64qqq_fma (x1, y, z
        	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	       _EXC_INFO_ARG);
#endif
  BID_RETURN (res1);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid64qdd_fma (UINT64 * pres, UINT128 * px, UINT64 * py, UINT64 * pz
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
  UINT64 y = *py, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT64
bid64qdd_fma (UINT128 x, UINT64 y, UINT64 z
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
#endif
  UINT64 res1 = 0xbaddbaddbaddbaddull;
  UINT128 y1, z1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64_to_bid128 (&z1, &z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64qqq_fma (&res1, px, &y1, &z1
        	_RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	_EXC_INFO_ARG);
#else
  y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  z1 = bid64_to_bid128 (z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res1 = bid64qqq_fma (x, y1, z1
        	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	       _EXC_INFO_ARG);
#endif
  BID_RETURN (res1);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid64qdq_fma (UINT64 * pres, UINT128 * px, UINT64 * py, UINT128 * pz
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
  UINT64 y = *py;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT64
bid64qdq_fma (UINT128 x, UINT64 y, UINT128 z
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
#endif
  UINT64 res1 = 0xbaddbaddbaddbaddull;
  UINT128 y1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&y1, &y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64qqq_fma (&res1, px, &y1, pz
        	_RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	_EXC_INFO_ARG);
#else
  y1 = bid64_to_bid128 (y _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res1 = bid64qqq_fma (x, y1, z
        	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	       _EXC_INFO_ARG);
#endif
  BID_RETURN (res1);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid64qqd_fma (UINT64 * pres, UINT128 * px, UINT128 * py, UINT64 * pz
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
  UINT64 z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT64
bid64qqd_fma (UINT128 x, UINT128 y, UINT64 z
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
#endif
  UINT64 res1 = 0xbaddbaddbaddbaddull;
  UINT128 z1;

#if DECIMAL_CALL_BY_REFERENCE
  bid64_to_bid128 (&z1, &z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  bid64qqq_fma (&res1, px, py, &z1
        	_RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	_EXC_INFO_ARG);
#else
  z1 = bid64_to_bid128 (z _EXC_FLAGS_ARG _EXC_MASKS_ARG _EXC_INFO_ARG);
  res1 = bid64qqq_fma (x, y, z1
        	       _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	       _EXC_INFO_ARG);
#endif
  BID_RETURN (res1);
}


#if DECIMAL_CALL_BY_REFERENCE
void
bid64qqq_fma (UINT64 * pres, UINT128 * px, UINT128 * py, UINT128 * pz
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
  UINT128 x = *px, y = *py, z = *pz;
#if !DECIMAL_GLOBAL_ROUNDING
  unsigned int rnd_mode = *prnd_mode;
#endif
#else
UINT64
bid64qqq_fma (UINT128 x, UINT128 y, UINT128 z
              _RND_MODE_PARAM _EXC_FLAGS_PARAM _EXC_MASKS_PARAM
              _EXC_INFO_PARAM) {
#endif
  int is_midpoint_lt_even0 = 0, is_midpoint_gt_even0 = 0,
    is_inexact_lt_midpoint0 = 0, is_inexact_gt_midpoint0 = 0;
  int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0,
    is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;
  int incr_exp;
  UINT128 res = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT128 res128 = { {0xbaddbaddbaddbaddull, 0xbaddbaddbaddbaddull} };
  UINT64 res1 = 0xbaddbaddbaddbaddull;
  unsigned int save_fpsf; // needed because of the call to bid128_ext_fma
  UINT64 sign;
  UINT64 exp;
  int unbexp;
  UINT128 C;
  BID_UI64DOUBLE tmp;
  int nr_bits;
  int q, x0;
  int scale;
  int lt_half_ulp = 0, eq_half_ulp = 0;

  // Note: for rounding modes other than RN or RA, the result can be obtained
  // by rounding first to BID128 and then to BID64

  save_fpsf = *pfpsf; // sticky bits - caller value must be preserved
  *pfpsf = 0;

#if DECIMAL_CALL_BY_REFERENCE
  bid128_ext_fma (&is_midpoint_lt_even0, &is_midpoint_gt_even0,
        	  &is_inexact_lt_midpoint0, &is_inexact_gt_midpoint0,
        	  &res, &x, &y, &z
        	  _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        	  _EXC_INFO_ARG);
#else
  res = bid128_ext_fma (&is_midpoint_lt_even0, &is_midpoint_gt_even0,
        		&is_inexact_lt_midpoint0,
        		&is_inexact_gt_midpoint0, x, y,
        		z _RND_MODE_ARG _EXC_FLAGS_ARG _EXC_MASKS_ARG
        		_EXC_INFO_ARG);
#endif

  if ((rnd_mode == ROUNDING_DOWN) || (rnd_mode == ROUNDING_UP) || 
      (rnd_mode == ROUNDING_TO_ZERO) || // no double rounding error is possible
      ((res.w[HIGH_128W] & MASK_NAN) == MASK_NAN) || //res=QNaN (cannot be SNaN)
      ((res.w[HIGH_128W] & MASK_ANY_INF) == MASK_INF)) { // result is infinity  
#if DECIMAL_CALL_BY_REFERENCE
    bid128_to_bid64 (&res1, &res _RND_MODE_ARG _EXC_FLAGS_ARG);
#else
    res1 = bid128_to_bid64 (res _RND_MODE_ARG _EXC_FLAGS_ARG);
#endif
    // determine the unbiased exponent of the result
    unbexp = ((res1 >> 53) & 0x3ff) - 398;

    // if subnormal, res1  must have exp = -398
    // if tiny and inexact set underflow and inexact status flags
    if (!((res1 & MASK_NAN) == MASK_NAN) &&	// res1 not NaN
        (unbexp == -398)
        && ((res1 & MASK_BINARY_SIG1) < 1000000000000000ull)
        && (is_inexact_lt_midpoint0 || is_inexact_gt_midpoint0
            || is_midpoint_lt_even0 || is_midpoint_gt_even0)) {
      // set the inexact flag and the underflow flag
      *pfpsf |= (INEXACT_EXCEPTION | UNDERFLOW_EXCEPTION);
    } else if (is_inexact_lt_midpoint0 || is_inexact_gt_midpoint0 ||
               is_midpoint_lt_even0 || is_midpoint_gt_even0) {
      // set the inexact flag and the underflow flag
      *pfpsf |= INEXACT_EXCEPTION;
    }

    *pfpsf |= save_fpsf;
    BID_RETURN (res1);
  } // else continue, and use rounding to nearest to round to 16 digits

  // at this point the result is rounded to nearest (even or away) to 34 digits
  // (or less if exact), and it is zero or finite non-zero canonical [sub]normal
  sign = res.w[HIGH_128W] & MASK_SIGN; // 0 for positive, MASK_SIGN for negative
  exp = res.w[HIGH_128W] & MASK_EXP; // biased and shifted left 49 bits
  unbexp = (exp >> 49) - 6176;
  C.w[1] = res.w[HIGH_128W] & MASK_COEFF;
  C.w[0] = res.w[LOW_128W];

  if ((C.w[1] == 0x0 && C.w[0] == 0x0) ||	// result is zero
      (unbexp <= (-398 - 35)) || (unbexp >= (369 + 16))) { 
      // clear under/overflow
#if DECIMAL_CALL_BY_REFERENCE
    bid128_to_bid64 (&res1, &res _RND_MODE_ARG _EXC_FLAGS_ARG);
#else
    res1 = bid128_to_bid64 (res _RND_MODE_ARG _EXC_FLAGS_ARG);
#endif
    *pfpsf |= save_fpsf;
    BID_RETURN (res1);
  } // else continue

  // -398 - 34 <= unbexp <= 369 + 15
  if (rnd_mode == ROUNDING_TIES_AWAY) {
    // apply correction, if needed, to make the result rounded to nearest-even
    if (is_midpoint_gt_even) {
      // res = res - 1
      res1--; // res1 is now even
    } // else the result is already correctly rounded to nearest-even
  }
  // at this point the result is finite, non-zero canonical normal or subnormal,
  // and in most cases overflow or underflow will not occur

  // determine the number of digits q in the result
  // q = nr. of decimal digits in x
  // determine first the nr. of bits in x
  if (C.w[1] == 0) {
    if (C.w[0] >= 0x0020000000000000ull) { // x >= 2^53
      // split the 64-bit value in two 32-bit halves to avoid rounding errors
      if (C.w[0] >= 0x0000000100000000ull) { // x >= 2^32
        tmp.d = (double) (C.w[0] >> 32); // exact conversion
        nr_bits =
          33 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
      } else { // x < 2^32
        tmp.d = (double) (C.w[0]); // exact conversion
        nr_bits =
          1 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
      }
    } else { // if x < 2^53
      tmp.d = (double) C.w[0]; // exact conversion
      nr_bits =
        1 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
    }
  } else { // C.w[1] != 0 => nr. bits = 64 + nr_bits (C.w[1])
    tmp.d = (double) C.w[1]; // exact conversion
    nr_bits =
      65 + ((((unsigned int) (tmp.ui64 >> 52)) & 0x7ff) - 0x3ff);
  }
  q = nr_digits[nr_bits - 1].digits;
  if (q == 0) {
    q = nr_digits[nr_bits - 1].digits1;
    if (C.w[1] > nr_digits[nr_bits - 1].threshold_hi ||
        (C.w[1] == nr_digits[nr_bits - 1].threshold_hi &&
         C.w[0] >= nr_digits[nr_bits - 1].threshold_lo))
      q++;
  }
  // if q > 16, round to nearest even to 16 digits (but for underflow it may 
  // have to be truncated even more)
  if (q > 16) {
    x0 = q - 16;
    if (q <= 18) {
      round64_2_18 (q, x0, C.w[0], &res1, &incr_exp,
        	    &is_midpoint_lt_even, &is_midpoint_gt_even,
        	    &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
    } else { // 19 <= q <= 34
      round128_19_38 (q, x0, C, &res128, &incr_exp,
        	      &is_midpoint_lt_even, &is_midpoint_gt_even,
        	      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
      res1 = res128.w[0]; // the result fits in 64 bits
    }
    unbexp = unbexp + x0;
    if (incr_exp)
      unbexp++;
    q = 16; // need to set in case denormalization is necessary
  } else {
    // the result does not require a second rounding (and it must have 
    // been exact in the first rounding, since q <= 16)
    res1 = C.w[0];
  }

  // avoid a double rounding error
  if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
      is_midpoint_lt_even) { // double rounding error upward
    // res = res - 1 
    res1--; // res1 becomes odd 
    is_midpoint_lt_even = 0;
    is_inexact_lt_midpoint = 1;
    if (res1 == 0x00038d7ea4c67fffull) { // 10^15 - 1
      res1 = 0x002386f26fc0ffffull; // 10^16 - 1 
      unbexp--;
    }
  } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
      is_midpoint_gt_even) { // double rounding error downward
    // res = res + 1
    res1++; // res1 becomes odd (so it cannot be 10^16)
    is_midpoint_gt_even = 0;
    is_inexact_gt_midpoint = 1;
  } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
             !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
    // if this second rounding was exact the result may still be 
    // inexact because of the first rounding
    if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
      is_inexact_gt_midpoint = 1;
    }
    if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
      is_inexact_lt_midpoint = 1;
    }
  } else if (is_midpoint_gt_even &&
             (is_inexact_gt_midpoint0 || is_midpoint_lt_even0)) {
    // pulled up to a midpoint 
    is_inexact_lt_midpoint = 1;
    is_inexact_gt_midpoint = 0;
    is_midpoint_lt_even = 0;
    is_midpoint_gt_even = 0;
  } else if (is_midpoint_lt_even &&
             (is_inexact_lt_midpoint0 || is_midpoint_gt_even0)) {
    // pulled down to a midpoint 
    is_inexact_lt_midpoint = 0;
    is_inexact_gt_midpoint = 1;
    is_midpoint_lt_even = 0;
    is_midpoint_gt_even = 0;
  } else {
    ;
  }
  // this is the result rounded correctly to nearest even, with unbounded exp. 

  // check for overflow
  if (q + unbexp > P16 + expmax16) {
    res1 = sign | 0x7800000000000000ull;
    *pfpsf |= (INEXACT_EXCEPTION | OVERFLOW_EXCEPTION);
    *pfpsf |= save_fpsf;
    BID_RETURN (res1)
  } else if (unbexp > expmax16) { // q + unbexp <= P16 + expmax16
    // not overflow; the result must be exact, and we can multiply res1 by
    // 10^(unbexp - expmax16) and the product will fit in 16 decimal digits
    scale = unbexp - expmax16;
    res1 = res1 * ten2k64[scale]; // res1 * 10^scale
    unbexp = expmax16; // unbexp - scale 
  } else {
    ; // continue
  }

  // check for underflow
  if (q + unbexp < P16 + expmin16) {
    if (unbexp < expmin16) {
      // we must truncate more of res
      x0 = expmin16 - unbexp; // x0 >= 1
      is_inexact_lt_midpoint0 = is_inexact_lt_midpoint;
      is_inexact_gt_midpoint0 = is_inexact_gt_midpoint;
      is_midpoint_lt_even0 = is_midpoint_lt_even;
      is_midpoint_gt_even0 = is_midpoint_gt_even;
      is_inexact_lt_midpoint = 0;
      is_inexact_gt_midpoint = 0;
      is_midpoint_lt_even = 0;
      is_midpoint_gt_even = 0;
      // the number of decimal digits in res1 is q
      if (x0 < q) { // 1 <= x0 <= q-1 => round res to q - x0 digits
        // 2 <= q <= 16, 1 <= x0 <= 15
        round64_2_18 (q, x0, res1, &res1, &incr_exp,
        	      &is_midpoint_lt_even, &is_midpoint_gt_even,
        	      &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
        if (incr_exp) {
          // res1 = 10^(q-x0), 1 <= q - x0 <= q - 1, 1 <= q - x0 <= 15
          res1 = ten2k64[q - x0];
        }
        unbexp = unbexp + x0; // expmin16
      } else if (x0 == q) {
        // the second rounding is for 0.d(0)d(1)...d(q-1) * 10^emin
        // determine relationship with 1/2 ulp
        // q <= 16
        if (res1 < midpoint64[q - 1]) { // < 1/2 ulp
          lt_half_ulp = 1;
          is_inexact_lt_midpoint = 1;
        } else if (res1 == midpoint64[q - 1]) { // = 1/2 ulp
          eq_half_ulp = 1;
          is_midpoint_gt_even = 1;
        } else { // > 1/2 ulp
          // gt_half_ulp = 1;
          is_inexact_gt_midpoint = 1;
        }
        if (lt_half_ulp || eq_half_ulp) {
          // res = +0.0 * 10^expmin16
          res1 = 0x0000000000000000ull;
        } else { // if (gt_half_ulp)
          // res = +1 * 10^expmin16
          res1 = 0x0000000000000001ull;
        }
        unbexp = expmin16;
      } else { // if (x0 > q)
        // the second rounding is for 0.0...d(0)d(1)...d(q-1) * 10^emin
        res1 = 0x0000000000000000ull;
        unbexp = expmin16;
        is_inexact_lt_midpoint = 1;
      }
      // avoid a double rounding error
      if ((is_inexact_gt_midpoint0 || is_midpoint_lt_even0) && 
          is_midpoint_lt_even) { // double rounding error upward
        // res = res - 1
        res1--; // res1 becomes odd
        is_midpoint_lt_even = 0;
        is_inexact_lt_midpoint = 1;
      } else if ((is_inexact_lt_midpoint0 || is_midpoint_gt_even0) && 
          is_midpoint_gt_even) { // double rounding error downward
        // res = res + 1
        res1++; // res1 becomes odd
        is_midpoint_gt_even = 0;
        is_inexact_gt_midpoint = 1;
      } else if (!is_midpoint_lt_even && !is_midpoint_gt_even &&
        	 !is_inexact_lt_midpoint && !is_inexact_gt_midpoint) {
        // if this rounding was exact the result may still be 
        // inexact because of the previous roundings
        if (is_inexact_gt_midpoint0 || is_midpoint_lt_even0) {
          is_inexact_gt_midpoint = 1;
        }
        if (is_inexact_lt_midpoint0 || is_midpoint_gt_even0) {
          is_inexact_lt_midpoint = 1;
        }
      } else if (is_midpoint_gt_even &&
        	 (is_inexact_gt_midpoint0 || is_midpoint_lt_even0)) {
        // pulled up to a midpoint
        is_inexact_lt_midpoint = 1;
        is_inexact_gt_midpoint = 0;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;
      } else if (is_midpoint_lt_even &&
        	 (is_inexact_lt_midpoint0 || is_midpoint_gt_even0)) {
        // pulled down to a midpoint
        is_inexact_lt_midpoint = 0;
        is_inexact_gt_midpoint = 1;
        is_midpoint_lt_even = 0;
        is_midpoint_gt_even = 0;
      } else {
        ;
      }
    }
    // else if unbexp >= emin then q < P (because q + unbexp < P16 + expmin16)
    // and the result is tiny and exact

    // check for inexact result
    if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
        is_midpoint_lt_even || is_midpoint_gt_even ||
        is_inexact_lt_midpoint0 || is_inexact_gt_midpoint0 ||
        is_midpoint_lt_even0 || is_midpoint_gt_even0) {
      // set the inexact flag and the underflow flag
      *pfpsf |= (INEXACT_EXCEPTION | UNDERFLOW_EXCEPTION);
    }
  } else if (is_inexact_lt_midpoint || is_inexact_gt_midpoint ||
             is_midpoint_lt_even || is_midpoint_gt_even) {
    *pfpsf |= INEXACT_EXCEPTION;
  }
  // this is the result rounded correctly to nearest, with bounded exponent

  if (rnd_mode == ROUNDING_TIES_AWAY && is_midpoint_gt_even) { // correction
    // res = res + 1
    res1++; // res1 is now odd
  } // else the result is already correct

  // assemble the result
  if (res1 < 0x0020000000000000ull) { // res < 2^53
    res1 = sign | ((UINT64) (unbexp + 398) << 53) | res1;
  } else { // res1 >= 2^53
    res1 = sign | MASK_STEERING_BITS |
      ((UINT64) (unbexp + 398) << 51) | (res1 & MASK_BINARY_SIG2);
  }
  *pfpsf |= save_fpsf;
  BID_RETURN (res1);
}
