// bdldfp_decimalimputil.h                                            -*-C++-*-

#ifndef INCLUDED_BDLDFP_DECIMALIMPUTIL
#define INCLUDED_BDLDFP_DECIMALIMPUTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id$")

//@PURPOSE: Provide a unified low-level interface for decimal floating point.
//
//@CLASSES:
//  bdldfp::DecimalImpUtil: Unified low-level decimal floating point functions.
//
//@SEE_ALSO: bdldfp_decimalimputil_inteldfp
//
//@DESCRIPTION: This component provides a namespace, `bdldfp::DecimalImpUtil`,
// containing primitive utilities used in the implementation of a decimal
// floating point type (e.g., see `bdldfp_decimal`).
//
///Usage
///-----
// This section shows the intended use of this component.
//
///Example 1: Constructing a Representation of a Value in Decimal
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// A common requirement for decimal floating point types is to be able to
// create a value from independent "coefficient" and "exponent" values, where
// the resulting decimal has the value `coefficient * 10 ^ exponent`.  In the
// following example we use such a `coefficient` and `exponent` to create
// `Decimal32`, `Decimal64`, and `Decimal128` values.
//
// First we define values representing the `coefficient` and `exponent` (note
// the result should be the value 42.5):
// ```
// int coefficient = 425; // Yet another name for significand
// int exponent    =  -1;
// ```
// Then we call `makeDecimal32`, `makeDecimal64`, and `makeDecimal128` to
// construct a `Decimal32`, `Decimal64`, and `Decimal128` respectively.
// ```
// bdldfp::DecimalImpUtil::ValueType32  d32 =
//           bdldfp::DecimalImpUtil::makeDecimalRaw32( coefficient, exponent);
// bdldfp::DecimalImpUtil::ValueType64  d64 =
//           bdldfp::DecimalImpUtil::makeDecimalRaw64( coefficient, exponent);
// bdldfp::DecimalImpUtil::ValueType128 d128 =
//           bdldfp::DecimalImpUtil::makeDecimalRaw128(coefficient, exponent);
//
// ASSERT(bdldfp::DecimalImpUtil::equal(
//                   bdldfp::DecimalImpUtil::binaryToDecimal32( 42.5), d32));
// ASSERT(bdldfp::DecimalImpUtil::equal(
//                   bdldfp::DecimalImpUtil::binaryToDecimal64( 42.5), d64));
// ASSERT(bdldfp::DecimalImpUtil::equal(
//                   bdldfp::DecimalImpUtil::binaryToDecimal128(42.5), d128));
// ```
//
///Example 2: Adding Two Decimal Floating Point Values
///- - - - - - - - - - - - - - - - - - - - - - - - - -
// Decimal floating point values are frequently used in arithmetic computations
// where the precise representation of decimal values is of paramount
// importance (for example, financial calculations, as currency is typically
// denominated in base-10 decimal values).  In the following example we
// demonstrate computing the sum of a sequence of security prices, where each
// price is held in a `DecimalImpUtil::ValueType64` value.
//
// First, we define the signature of a function that computes the sum of an
// array of security prices, and returns that sum as a decimal floating point
// value:
// ```
// /// Return a Decimal Floating Point number representing the arithmetic
// /// total of the values specified by `prices` and `numPrices`.
// bdldfp::DecimalImpUtil::ValueType64
// totalSecurities(bdldfp::DecimalImpUtil::ValueType64 *prices,
//                 int                                  numPrices)
// {
// ```
// Then, we create a local variable to hold the intermediate sum, and set it to
// 0:
// ```
//     bdldfp::DecimalImpUtil::ValueType64 total;
//     total = bdldfp::DecimalImpUtil::int32ToDecimal64(0);
// ```
// Next, we loop over the array of `prices` and add each price to the
// intermediate `total`:
// ```
//     for (int i = 0; i < numPrices; ++i) {
//         total = bdldfp::DecimalImpUtil::add(total, prices[i]);
//     }
// ```
// Now, we return the computed total value of the securities:
// ```
//     return total;
// }
// ```
// Notice that `add` is called as a function, and is not an operator overload
// for `+`; this is because the `bdldfp::DecimalImpUtil` utility is intended to
// be used in the implementation of operator overloads on a more full fledged
// type.
//
// Finally, we call the function with some sample data, and check the result:
// ```
// bdldfp::DecimalImpUtil::ValueType64 data[16];
//
// for (int i = 0; i < 16; ++i) {
//     data[i] = bdldfp::DecimalImpUtil::int32ToDecimal64(i + 1);
// }
//
// bdldfp::DecimalImpUtil::ValueType64 result;
// result = totalSecurities(data, 16);
//
// bdldfp::DecimalImpUtil::ValueType64 expected;
//
// expected = bdldfp::DecimalImpUtil::int32ToDecimal64(16);
//
// // Totals of values from 1 to 'x' are '(x * x + x) / 2':
//
// expected = bdldfp::DecimalImpUtil::add(
//              bdldfp::DecimalImpUtil::multiply(expected, expected),
//              expected);
// expected = bdldfp::DecimalImpUtil::divide(
//                      expected,
//                      bdldfp::DecimalImpUtil::int32ToDecimal64(2));
//
// assert(bdldfp::DecimalImpUtil::equal(expected, result));
// ```
// Notice that arithmetic is unwieldy and hard to visualize.  This is by
// design, as the DecimalImpUtil and subordinate components are not intended
// for public consumption, or direct use in decimal arithmetic.

#include <bdlscm_version.h>

#include <bdldfp_decimalformatconfig.h>
#include <bdldfp_decimalimputil_inteldfp.h>
#include <bdldfp_decimalplatform.h>
#include <bdldfp_decimalstorage.h>
#include <bdldfp_intelimpwrapper.h>
#include <bdldfp_uint128.h>

#include <bslmf_assert.h>

#include <bsls_assert.h>
#include <bsls_keyword.h>
#include <bsls_types.h>

#include <bsl_algorithm.h>
#include <bsl_cmath.h>
#include <bsl_c_errno.h>
#include <bsl_iostream.h>

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bsl_c_signal.h>  // Formerly transitively included via decContext.h
#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES

#ifdef BDLDFP_DECIMALPLATFORM_SOFTWARE

                // DECIMAL FLOATING-POINT LITERAL EMULATION


#define BDLDFP_DECIMALIMPUTIL_DF(lit)                                        \
    BloombergLP::bdldfp::DecimalImpUtil::parse32(                            \
        (BloombergLP::bdldfp::DecimalImpUtil::checkLiteral(lit), #lit))

#define BDLDFP_DECIMALIMPUTIL_DD(lit)                                        \
    BloombergLP::bdldfp::DecimalImpUtil::parse64(                            \
        (BloombergLP::bdldfp::DecimalImpUtil::checkLiteral(lit), #lit))

#define BDLDFP_DECIMALIMPUTIL_DL(lit)                                        \
    BloombergLP::bdldfp::DecimalImpUtil::parse128(                           \
        (BloombergLP::bdldfp::DecimalImpUtil::checkLiteral(lit), #lit))

#elif defined(BDLDFP_DECIMALPLATFORM_C99_TR) || defined( __IBM_DFP__ )

#define BDLDFP_DECIMALIMPUTIL_JOIN_(a,b) a##b

               // Portable decimal floating-point literal support

#define BDLDFP_DECIMALIMPUTIL_DF(lit) BDLDFP_DECIMALIMPUTIL_JOIN_(lit,df)

#define BDLDFP_DECIMALIMPUTIL_DD(lit) BDLDFP_DECIMALIMPUTIL_JOIN_(lit,dd)

#define BDLDFP_DECIMALIMPUTIL_DL(lit) BDLDFP_DECIMALIMPUTIL_JOIN_(lit,dl)

#endif


namespace BloombergLP {
namespace bdldfp {

                        // ====================
                        // class DecimalImpUtil
                        // ====================

/// This `struct` provides a namespace for utility functions that implement
/// core decimal floating-poing operations.
class DecimalImpUtil {

  private:
#if defined(BDLDFP_DECIMALPLATFORM_INTELDFP)
    typedef DecimalImpUtil_IntelDfp  Imp;
#else
    BDLDFP_DECIMALPLATFORM_COMPILER_ERROR;
#endif

  public:
    // TYPES
    typedef Imp::ValueType32  ValueType32;
    typedef Imp::ValueType64  ValueType64;
    typedef Imp::ValueType128 ValueType128;

    enum {
        // Status flag bitmask for numeric operations.

        k_STATUS_INEXACT = Imp::k_STATUS_INEXACT,
        k_STATUS_UNDERFLOW = Imp::k_STATUS_UNDERFLOW,
        k_STATUS_OVERFLOW = Imp::k_STATUS_OVERFLOW
    };

    // CLASS METHODS

    /// Return a `Decimal64` object that has the specified `significand` and
    /// `exponent`, rounded according to the current decimal rounding mode,
    /// if necessary.  If an overflow condition occurs, store the value of
    /// the macro `ERANGE` into `errno` and return infinity with the
    /// appropriate sign.
    static ValueType64 makeDecimal64(                   int significand,
                                                        int exponent);
    static ValueType64 makeDecimal64(unsigned           int significand,
                                                        int exponent);
    static ValueType64 makeDecimal64(         long long int significand,
                                                        int exponent);
    static ValueType64 makeDecimal64(unsigned long long int significand,
                                                        int exponent);

    /// Return a `ValueType64` representing infinity.  Optionally specify
    /// whether the infinity `isNegative`.  If `isNegative` is `false` or is
    /// is not supplied, the returned value will be infinity, and negative
    /// infinity otherwise.
    static ValueType64 makeInfinity64(bool isNegative = false);

#ifdef BDLDFP_DECIMALPLATFORM_SOFTWARE

                        // Literal Checking Functions

    /// This `struct` is a helper type used to generate error messages for
    /// bad literals.
    struct This_is_not_a_floating_point_literal {};

    /// Generate an error if the specified `t` is bad decimal
    /// floating-point.  Note that this function is intended for use with
    /// literals
    template <class TYPE>
    static void checkLiteral(const TYPE& t);

    /// Overload to avoid an error when the decimal floating-point literal
    /// (without the suffix) can be interpreted as a `double` literal.
    static void checkLiteral(double);

#elif defined(BDLDFP_DECIMALPLATFORM_HARDWARE)

#else

#error Improperly configured decimal floating point platform settings

#endif
                            // classify

    /// Return the integer value that respresents the floating point
    /// classification of the specified `x` value as follows:
    ///
    /// * if `x` is NaN, return FP_NAN;
    /// * otherwise if `x` is positive or negative infinity, return
    ///   `FP_INFINITE`;
    /// * otherwise if `x` is a subnormal value, return `FP_SUBNORMAL`
    /// * otherwise if `x` is a zero value, return `FP_ZERO`
    /// * otherwise return `FP_NORMAL`
    ///
    /// Note that the mention `FP_XXX` constants are C99 standard macros and
    /// they are defined in the math.h (cmath) standard header.  On systems
    /// that fail to define those standard macros we define the in this
    /// component as public macros.
    static int classify(ValueType32  x);
    static int classify(ValueType64  x);
    static int classify(ValueType128 x);


                          // normalize

    /// Return a `ValueTypeXX` number having the value as the specified
    /// 'original, but with the significand, that can not be divided by ten,
    /// and appropriate exponent.
    ///
    /// * Any representations of zero value (either positive or negative)
    ///   are normalized to positive zero having null significand and
    ///   exponent.
    /// * Any NaN values (either signaling or quiet) are normalized to
    ///   quiet NaN.
    /// * Normalized non-zero value has the same sign as the original one.
    static ValueType32  normalize(ValueType32  original);
    static ValueType64  normalize(ValueType64  original);
    static ValueType128 normalize(ValueType128 original);

                             // Quantum functions

    /// Return a number equal to the specified `value` (except for possible
    /// rounding) having the exponent equal to the exponent of the specified
    /// `exponent`.  Rounding may occur when the exponent is greater than
    /// the quantum of `value`.  E.g., `quantize(147e-2_d32, 1e-1_d32)`
    /// yields `15e-1_d32`.  In the opposite direction, if `exponent` is
    /// sufficiently less than the quantum of `value`, it may not be
    /// possible to construct the requested result, and if so, `NaN` is
    /// returned.  E.g., `quantize(1234567e0_d32, 1e-1_d32)` returns `NaN`.
    static ValueType32  quantize(ValueType32  value, ValueType32  exponent);
    static ValueType64  quantize(ValueType64  value, ValueType64  exponent);
    static ValueType128 quantize(ValueType128 value, ValueType128 exponent);

    /// Return a number equal to the specified `value` (except for possible
    /// rounding) having the specified `exponent`.  Rounding may occur when
    /// `exponent` is greater than the quantum of `value`.  E.g.,
    /// `quantize(147e-2_d32, -1)` yields `15e-1_d32`.  In the opposite
    /// direction, if `exponent` is sufficiently less than the quantum of
    /// `value`, it may not be possible to construct the requested result,
    /// and if so, `NaN` is returned.  E.g., `quantize(1234567e0_d32, -1)`
    /// returns `NaN`.  Behavior is undefined unless the `exponent`
    /// satisfies the following conditions
    /// * for `Decimal32`  type:  `-101 <= exponent <=   90`
    /// * for `Decimal64`  type:  `-398 <= exponent <=  369`
    /// * for `Decimal128` type: `-6176 <= exponent <= 6111`
    static ValueType32  quantize(ValueType32  value, int exponent);
    static ValueType64  quantize(ValueType64  value, int exponent);
    static ValueType128 quantize(ValueType128 value, int exponent);

    /// If a floating-point number equal to the specified `y` and having the
    /// specified `exponent` can be constructed, set that value into the
    /// specified `x` and return 0.  Otherwise, or if `y` is NaN or
    /// infinity, leave the contents of `x` unchanged and return a non-zero
    /// value.  The behavior is undefined unless `exponent` satisfies the
    /// following conditions
    /// * for `Decimal32`  type:  `-101 <= exponent <=   90`
    /// * for `Decimal64`  type:  `-398 <= exponent <=  369`
    /// * for `Decimal128` type: `-6176 <= exponent <= 6111`
    ///
    /// Example:
    ///     `Decimal32 x;`
    ///     `BSLS_ASSERT(0 == quantizeEqual(&x, 123e+3_d32, 2);`
    ///     `BSLS_ASSERT(1230e+2_d32 == x);`
    ///     `BSLS_ASSERT(0 != quantizeEqual(&x, 123e+3_d32, -2);`
    ///     `BSLS_ASSERT(1230e+2_d32 == x);`
    static int quantizeEqual(ValueType32  *x, ValueType32  y, int exponent);
    static int quantizeEqual(ValueType64  *x, ValueType64  y, int exponent);
    static int quantizeEqual(ValueType128 *x, ValueType128 y, int exponent);

    /// Return `true` if the specified `x` and `y` values have the same
    /// quantum exponents, and `false` otherwise.  If both arguments are NaN
    /// or both arguments are infinity, they have the same quantum
    /// exponents.  Note that if exactly one operand is NaN or exactly one
    /// operand is infinity, they do not have the same quantum exponents.
    static bool sameQuantum(ValueType32  x, ValueType32  y);
    static bool sameQuantum(ValueType64  x, ValueType64  y);
    static bool sameQuantum(ValueType128 x, ValueType128 y);

                        // compose and decompose

    /// Decompose the specified decimal `value` into the components of
    /// the decimal floating-point format and load the result into the
    /// specified `sign`, `significand` and `exponent` such that
    /// `value` is equal to `sign * significand * (10 ** exponent)`.
    /// The special values infinity and NaNs are decomposed to `sign`,
    /// `exponent` and `significand` parts, even though they don't have
    /// their normal meaning (except `sign`).  That is those specific values
    /// cannot be restored using these parts, unlike the finite ones.
    /// Return the integer value that represents the floating point
    /// classification of the specified `value` as follows:
    ///
    /// * if `value` is NaN, return FP_NAN;
    /// * if `value` is infinity, return `FP_INFINITE`;
    /// * if `value` is a subnormal value, return `FP_SUBNORMAL`;
    /// * if `value` is a zero value, return `FP_ZERO`;
    /// * otherwise return `FP_NORMAL`.
    ///
    /// Note that a decomposed representation may not be unique,
    /// for example 10 can be represented as either `10 * (10 ** 0)`
    /// or `1 * (10 ** 1)`.  The returned `significand` and `exponent`
    /// reflect the encoded representation of `value` (i.e., they
    /// reflect the `quantum` of `value`).
    static int decompose(int                 *sign,
                         unsigned  int       *significand,
                         int                 *exponent,
                         ValueType32          value);
    static int decompose(int                 *sign,
                         bsls::Types::Uint64 *significand,
                         int                 *exponent,
                         ValueType64          value);
    static int decompose(int                 *sign,
                         Uint128             *significand,
                         int                 *exponent,
                         ValueType128         value);

                         // Format functions

    static int format(char                      *buffer,
                      int                        length,
                      ValueType32                value,
                      const DecimalFormatConfig& cfg);

    static int format(char                      *buffer,
                      int                        length,
                      ValueType64                value,
                      const DecimalFormatConfig& cfg);

    /// Format the specified `value`, according to the parameters in the
    /// specified `cfg`. Place the output in the buffer designated by the
    /// specified `buffer` and `length`, and return the length of the
    /// formatted value.  If there is insufficient room in the buffer, its
    /// contents will be left in an unspecified state, with the returned
    /// value indicating the necessary size.  This function does not write
    /// a terminating null character.  If `length` is not positive, `buffer`
    /// is permitted to be null.  This can be used to determine the
    /// necessary buffer size.  See the
    /// [](bdldfp_decimalformatconfig#Attributes) section for information on
    /// the configuration attributes.
    ///
    /// Note that for some combinations of `value` and precision provided by
    /// `cfg` object, the number being written must first be rounded to
    /// fewer digits than it initially contains.  The number written must be
    /// as close as possible to the initial value given the constraints on
    /// precision.  The rounding should be done as "round-half-up", i.e.,
    /// round up in magnitude when the first of the discarded digits is
    /// between 5 and 9.
    ///
    /// Also note that if the configuration format attribute `style` is
    /// `e_NATURAL` then all significand digits of the `value` are output in
    /// the buffer regardless of the value specified in configuration's
    /// `precision` attribute.
    static int format(char                      *buffer,
                      int                        length,
                      ValueType128               value,
                      const DecimalFormatConfig& cfg);

                        // Integer construction

    static ValueType32  int32ToDecimal32(                   int value);
    static ValueType32 uint32ToDecimal32(unsigned           int value);
    static ValueType32  int64ToDecimal32(         long long int value);

    /// Return a `Decimal32` object having the value closest to the
    /// specified `value` following the conversion rules as defined by
    /// IEEE-754:
    ///
    /// * If `value` is zero then initialize this object to a zero with an
    ///   unspecified sign and an unspecified exponent.
    /// * Otherwise if `value` has a value that is not exactly
    ///   representable using `std::numeric_limits<Decimal32>::max_digit`
    ///   decimal digits then return a decimal value initialized to the
    ///   value of `value` rounded according to the rounding direction.
    /// * Otherwise initialize this object to the value of the `value`.
    ///
    /// The exponent 0 (quantum 1e-6) is preferred during conversion unless
    /// it would cause unnecessary loss of precision.
    static ValueType32 uint64ToDecimal32(unsigned long long int value);

    static ValueType64  int32ToDecimal64(                   int value);
    static ValueType64 uint32ToDecimal64(unsigned           int value);
    static ValueType64  int64ToDecimal64(         long long int value);

    /// Return a `Decimal64` object having the value closest to the
    /// specified `value` following the conversion rules as defined by
    /// IEEE-754:
    ///
    /// * If `value` is zero then initialize this object to a zero with an
    ///   unspecified sign and an unspecified exponent.
    /// * Otherwise if `value` has a value that is not exactly
    ///   representable using `std::numeric_limits<Decimal64>::max_digit`
    ///   decimal digits then return a decimal value initialized to the
    ///   value of `value` rounded according to the rounding direction.
    /// * Otherwise initialize this object to the value of the `value`.
    ///
    /// The exponent 0 (quantum 1e-15) is preferred during conversion unless
    /// it would cause unnecessary loss of precision.
    static ValueType64 uint64ToDecimal64(unsigned long long int value);

    static ValueType128  int32ToDecimal128(                   int value);
    static ValueType128 uint32ToDecimal128(unsigned           int value);
    static ValueType128  int64ToDecimal128(         long long int value);

    /// Return a `Decimal128` object having the value closest to the
    /// specified `value` subject to the conversion rules as defined by
    /// IEEE-754:
    ///
    /// * If `value` is zero then initialize this object to a zero with an
    ///   unspecified sign and an unspecified exponent.
    /// * Otherwise if `value` has a value that is not exactly
    ///   representable using `std::numeric_limits<Decimal128>::max_digit`
    ///   decimal digits then return a decimal value initialized to the
    ///   value of `value` rounded according to the rounding direction.
    /// * Otherwise initialize this object to `value`.
    ///
    /// The exponent 0 (quantum 1e-33) is preferred during conversion unless
    /// it would cause unnecessary loss of precision.
    static ValueType128 uint64ToDecimal128(unsigned long long int value);

                        // Arithmetic

                        // Addition functions

    /// Add the value of the specified `rhs` to the value of the specified
    /// `lhs` as described by IEEE-754 and return the result.
    ///
    /// * If either of `lhs` or `rhs` is signaling NaN, then store the
    ///   value of the macro `EDOM` into `errno` and return a NaN.
    /// * Otherwise if either of `lhs` or `rhs` is NaN, return a NaN.
    /// * Otherwise if `lhs` and `rhs` are infinities of differing signs,
    ///   store the value of the macro `EDOM` into `errno` and return a
    ///   NaN.
    /// * Otherwise if `lhs` and `rhs` are infinities of the same sign then
    ///   return infinity of that sign.
    /// * Otherwise if `rhs` is zero (positive or negative), return `lhs`.
    /// * Otherwise if the sum of `lhs` and `rhs` has an absolute value
    ///   that is larger than the maximum value supported by the indicated
    ///   result type then store the value of the macro `ERANGE` into
    ///   `errno` and return infinity with the same sign as that result.
    /// * Otherwise return the sum of the number represented by `lhs` and
    ///   the number represented by `rhs`.
    static ValueType32  add(ValueType32  lhs, ValueType32  rhs);
    static ValueType64  add(ValueType64  lhs, ValueType64  rhs);
    static ValueType128 add(ValueType128 lhs, ValueType128 rhs);

                        // Subtraction functions

    /// Subtract the value of the specified `rhs` from the value of the
    /// specified `lhs` as described by IEEE-754 and return the result.
    ///
    /// * If either of `lhs` or `rhs` is signaling NaN, then store the
    ///   value of the macro `EDOM` into `errno` and return a NaN.
    /// * Otherwise if either of `lhs` or `rhs` is NaN, return a NaN.
    /// * Otherwise if `lhs` and the `rhs` have infinity values of the same
    ///   sign, store the value of the macro `EDOM` into `errno` and return
    ///   a NaN.
    /// * Otherwise if `lhs` and the `rhs` have infinity values of
    ///   differing signs, then return `lhs`.
    /// * Otherwise if `rhs` has a zero value (positive or negative), then
    ///   return `lhs`.
    /// * Otherwise if the subtracting of `lhs` and `rhs` has an absolute
    ///   value that is larger than the maximum value supported by the
    ///   indicated result type then store the value of the macro `ERANGE`
    ///   into `errno` and return infinity with the same sign as that
    ///   result.
    /// * Otherwise return the result of subtracting the value of `rhs`
    ///   from the value of `lhs`.
    static ValueType32  subtract(ValueType32  lhs, ValueType32  rhs);
    static ValueType64  subtract(ValueType64  lhs, ValueType64  rhs);
    static ValueType128 subtract(ValueType128 lhs, ValueType128 rhs);

                        // Multiplication functions

    /// Multiply the value of the specified `lhs` object by the value of the
    /// specified `rhs` as described by IEEE-754 and return the result.
    ///
    /// * If either of `lhs` or `rhs` is signaling NaN, then store the
    ///   value of the macro `EDOM` into `errno` and return a NaN.
    /// * Otherwise if either of `lhs` or `rhs` is NaN, return a NaN.
    /// * Otherwise if one of the operands is infinity (positive or
    ///   negative) and the other is zero (positive or negative), then
    ///   store the value of the macro `EDOM` into `errno` and return a
    ///   NaN.
    /// * Otherwise if both `lhs` and `rhs` are infinity (positive or
    ///   negative), return infinity.  The sign of the returned value will
    ///   be positive if `lhs` and `rhs` have the same sign, and negative
    ///   otherwise.
    /// * Otherwise, if either `lhs` or `rhs` is zero, return zero.  The
    ///   sign of the returned value will be positive if `lhs` and `rhs`
    ///   have the same sign, and negative otherwise.
    /// * Otherwise if the product of `lhs` and `rhs` has an absolute value
    ///   that is larger than the maximum value of the indicated result
    ///   type then store the value of the macro `ERANGE` into `errno` and
    ///   return infinity with the same sign as that result.
    /// * Otherwise if the product of `lhs` and `rhs` has an absolute value
    ///   that is smaller than min value of the indicated result type then
    ///   store the value of the macro `ERANGE` into `errno` and return
    ///   zero with the same sign as that result.
    /// * Otherwise return the product of the value of `rhs` and the number
    ///   represented by `rhs`.
    static ValueType32  multiply(ValueType32  lhs, ValueType32  rhs);
    static ValueType64  multiply(ValueType64  lhs, ValueType64  rhs);
    static ValueType128 multiply(ValueType128 lhs, ValueType128 rhs);

                        // Division functions

    /// Divide the value of the specified `lhs` by the value of the
    /// specified `rhs` as described by IEEE-754, and return the result.
    ///
    /// * If either of `lhs` or `rhs` is signaling NaN, then store the
    ///   value of the macro `EDOM` into `errno` and return a NaN.
    /// * Otherwise if either of `lhs` or `rhs` is NaN, return a NaN.
    /// * Otherwise if `lhs` and `rhs` are both infinity (positive or
    ///   negative) or both zero (positive or negative) then store the
    ///   value of the macro `EDOM` into `errno` and return a NaN.
    /// * Otherwise if `lhs` has a normal value and `rhs` has a positive
    ///   zero value, store the value of the macro `ERANGE` into `errno`
    ///   and return infinity with the sign of `lhs`.
    /// * Otherwise if `lhs` has a normal value and `rhs` has a negative
    ///   zero value, store the value of the macro `ERANGE` into `errno`
    ///   and return infinity with the opposite sign as `lhs`.
    /// * Otherwise if dividing the value of `lhs` by the value of `rhs`
    ///   results in an absolute value that is larger than the maximum
    ///   value supported by the result type then store the value of the
    ///   macro `ERANGE` into `errno` and return infinity with the same
    ///   sign as that result.
    /// * Otherwise if dividing the value of `lhs` by the value of `rhs`
    ///   results in an absolute value that is smaller than min value
    ///   supported by the indicated result type then store the value of
    ///   the macro `ERANGE` into `errno`and return zero with the same sign
    ///   as that result.
    /// * Otherwise return the result of dividing the value of `lhs` by the
    ///   value of `rhs`.
    static ValueType32  divide(ValueType32  lhs, ValueType32  rhs);
    static ValueType64  divide(ValueType64  lhs, ValueType64  rhs);
    static ValueType128 divide(ValueType128 lhs, ValueType128 rhs);

                        // Math functions

    /// Return a decimal value with the magnitude of the specifed `x` and
    /// the sign of the specified `y`.  If `x` is NaN, then NaN with the
    /// sign of `y` is returned.
    ///
    /// Examples: `copysign( 5.0, -2.0)` ==> -5.0;
    ///           `copysign(-5.0, -2.0)` ==> -5.0
    static ValueType32  copySign(ValueType32  x, ValueType32  y);
    static ValueType64  copySign(ValueType64  x, ValueType64  y);
    static ValueType128 copySign(ValueType128 x, ValueType128 y);

    /// Return `e` (Euler's number, 2.7182818) raised to the specified power
    /// `x`.
    ///
    /// Special value handling:
    /// * If `x` is +/-0, 1 is returned.
    /// * If `x` is negative infinity, +0 is returned.
    /// * If `x` is +infinity, +infinity is returned.
    /// * If `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    /// * If `x` is finite, but the result value is outside the range of
    ///   the return type, store the value of the macro `ERANGE` into
    ///   `errno` and +infinity value is returned.
    static ValueType32  exp(ValueType32  x);
    static ValueType64  exp(ValueType64  x);
    static ValueType128 exp(ValueType128 x);

    /// Return the natural (base `e`) logarithm of the specified `x`.
    ///
    /// Special value handling:
    /// * If `x` is +/-0, -infinity is returned and the value of the macro
    ///   `ERANGE` is stored into `errno`.
    /// * If `x` is 1, +0 is returned.
    /// * If `x` is negative, quiet NaN is returned and the value of the
    ///   macro `EDOM` is stored into `errno`.
    /// * If `x` is +infinity, +infinity is returned.
    /// * If `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    static ValueType32  log(ValueType32  x);
    static ValueType64  log(ValueType64  x);
    static ValueType128 log(ValueType128 x);

    /// Return the FLT_RADIX-based logarithm (i.e., base 10) of the absolute
    ///  value of the specified `x`.
    ///
    /// Special value handling:
    /// * If `x` is +/-0, -infinity is returned and the value of the macro
    ///   `ERANGE` is stored into `errno`.
    /// * If `x` is 1, +0 is returned.
    /// * If `x` is +/-infinity, +infinity is returned.
    /// * If `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    ///
    /// Examples: `logB(  10.0)` ==> 1.0;
    ///           `logB(-100.0)` ==> 2.0
    static ValueType32  logB(ValueType32  x);
    static ValueType64  logB(ValueType64  x);
    static ValueType128 logB(ValueType128 x);

    /// Return the common (base-10) logarithm of the specified `x`.
    ///
    /// Special value handling:
    /// * If `x` is +/-0, -infinity is returned and the value of the macro
    ///   `ERANGE` is stored into `errno`.
    /// * If `x` is 1, +0 is returned.
    /// * If `x` is negative, quiet NaN is returned and the value of the
    ///   macro `EDOM` is stored into `errno`.
    /// * If `x` is +infinity, +infinity is returned.
    /// * If `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    static ValueType32  log10(ValueType32  x);
    static ValueType64  log10(ValueType64  x);
    static ValueType128 log10(ValueType128 x);

    /// Return the remainder of the division of the specified `x` by the
    /// specified `y`.  The returned value has the same sign as `x` and is
    /// less than `y` in magnitude.
    ///
    /// Special value handling:
    /// * If either argument is quiet NaN, quiet NaN is returned.
    /// * If either argument is signaling NaN, quiet NaN is returned, and
    ///   the value of the macro `EDOM` is stored into `errno`.
    /// * If `x` is +/-infnity and `y` is not NaN, quiet NaN is returned
    ///   and the value of the macro `EDOM` is stored into `errno`.
    /// * If `x` is +/-0 and `y` is not zero, +/-0 is returned.
    /// * If `y` is +/-0, quite NaN is returned and the value of the macro
    ///   `EDOM` is stored into `errno`.
    /// * If `x` is finite and `y` is +/-infnity, `x` is returned.
    static ValueType32  fmod(ValueType32  x, ValueType32  y);
    static ValueType64  fmod(ValueType64  x, ValueType64  y);
    static ValueType128 fmod(ValueType128 x, ValueType128 y);

    /// Return the remainder of the division of the specified `x` by the
    /// specified `y`.  The remainder of the division operation `x/y`
    /// calculated by this function is exactly the value `x - n*y`, where
    /// `n` s the integral value nearest the exact value `x/y`.  When
    /// `|n - x/y| == 0.5`, the value `n` is chosen to be even.  Note that
    /// in contrast to `DecimalImpUtil::fmod()`, the returned value is not
    /// guaranteed to have the same sign as `x`.
    ///
    /// Special value handling:
    /// * The current rounding mode has no effect.
    /// * If either argument is quiet NaN, quiet NaN is returned.
    /// * If either argument is signaling NaN, quiet NaN is returned, and
    ///   the value of the macro `EDOM` is stored into `errno`.
    /// * If `y` is +/-0, quiet NaN is returned and the value of the macro
    ///   `EDOM` is stored into `errno`.
    /// * If `x` is +/-infnity and `y` is not NaN, quiet NaN is returned
    ///   and the value of the macro `EDOM` is stored into `errno`.
    /// * If `x` is finite and `y` is +/-infnity, `x` is returned.
    static ValueType32  remainder(ValueType32  x, ValueType32  y);
    static ValueType64  remainder(ValueType64  x, ValueType64  y);
    static ValueType128 remainder(ValueType128 x, ValueType128 y);

    static long int        lrint(ValueType32  x);
    static long int        lrint(ValueType64  x);
    static long int        lrint(ValueType128 x);

    /// Return an integer value nearest to the specified `x`.  Round `x`
    /// using the current rounding mode.  If `x` is +/-infnity, NaN (either
    /// signaling or quiet) or the rounded value is outside the range of the
    /// return type, store the value of the macro `EDOM` into `errno` and
    /// return implementation-defined value.
    static long long int  llrint(ValueType32  x);
    static long long int  llrint(ValueType64  x);
    static long long int  llrint(ValueType128 x);

    static ValueType32  nextafter( ValueType32  from, ValueType32  to);
    static ValueType64  nextafter( ValueType64  from, ValueType64  to);
    static ValueType128 nextafter( ValueType128 from, ValueType128 to);

    /// Return the next representable value of the specified `from` in the
    /// direction of the specified `to`.
    ///
    /// Special value handling:
    /// * If `from` equals `to`, `to` is returned.
    /// * If either argument is quiet NaN, quiet NaN is returned.
    /// * If either argument is signaling NaN, quiet NaN is returned and
    ///   the value of the macro `EDOM` is stored into `errno`.
    /// * If `from` is finite, but the expected result is infinity,
    ///   infinity is returned and the value of the macro `ERANGE` is
    ///   stored into `errno`.
    /// * If `from` does not equal `to` and the result is subnormal or
    ///   zero, the value of the macro `ERANGE` is stored into `errno`.
    static ValueType32  nexttoward(ValueType32  from, ValueType128 to);
    static ValueType64  nexttoward(ValueType64  from, ValueType128 to);
    static ValueType128 nexttoward(ValueType128 from, ValueType128 to);

    /// Return the value of the specified `base` raised to the power of the
    /// specified `exp`.
    ///
    /// Special value handling:
    /// * If `base` is finite and negative and `exp` is finite and
    ///   non-integer, quiet NaN is returned and the value of the macro
    ///   `EDOM` is stored into `errno`.
    /// * If the mathematical result of this function is infinity or
    ///   undefined or a range error due to overflow occurs, infinity is
    ///   returned and the value of the macro `ERANGE` is stored into
    ///   `errno`.
    /// * If a range error occurs due to underflow, the correct result
    ///   (after rounding) is returned and the value of the macro `ERANGE`
    ///   is stored into `errno`.
    /// * If either argument is signaling NaN, quiet NaN is returned and
    ///   the value of the macro `EDOM` is stored into `errno`.
    static ValueType32  pow(ValueType32  base, ValueType32  exp);
    static ValueType64  pow(ValueType64  base, ValueType64  exp);
    static ValueType128 pow(ValueType128 base, ValueType128 exp);

    /// Return the smallest integral value that is not less than the
    /// specified `x`.
    ///
    /// Special value handling:
    /// * if `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    /// * if `x` is +/-infinity or +/-0, it is returned unmodified.
    ///
    /// Examples: `ceil(0.5)` ==> 1.0; `ceil(-0.5)` ==> 0.0
    static ValueType32  ceil(ValueType32  x);
    static ValueType64  ceil(ValueType64  x);
    static ValueType128 ceil(ValueType128 x);

    /// Return the largest integral value that is not greater than the
    /// specified `x`.
    ///
    /// Special value handling:
    /// * if `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    /// * if `x` is +/-infinity or +/-0, it is returned unmodified.
    ///
    /// Examples: `floor(0.5)` ==> 0.0; `floor(-0.5)` ==> -1.0
    static ValueType32  floor(ValueType32  x);
    static ValueType64  floor(ValueType64  x);
    static ValueType128 floor(ValueType128 x);

    /// Return the integral value nearest to the specified `x`.  Round
    /// halfway cases away from zero, regardless of the current decimal
    /// floating point rounding mode.
    ///
    /// Special value handling:
    /// * if `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    /// * if `x` is +/-infinity or +/-0, it is returned unmodified.
    ///
    /// Examples: `round(0.5)` ==> 1.0; `round(-0.5)` ==> -1.0
    static ValueType32  round(ValueType32  x);
    static ValueType64  round(ValueType64  x);
    static ValueType128 round(ValueType128 x);

    /// Return the integral value nearest to the specified `x`.  Round
    /// halfway cases away from zero, regardless of the current decimal
    /// floating point rounding mode.
    ///
    /// Special value handling:
    /// * if `x` is NaN (either quiet or signaling), quiet NaN is returned
    ///   and the value of the macro `EDOM` is stored into `errno`.
    /// * if `x` is +/-infinity, quite NaN is returned and the value of the
    ///   macro `EDOM` is stored into `errno`.
    /// * If the result of the rounding is outside the range of the return
    ///   type, the macro `EDOM` is stored into `errno`.
    ///
    /// Examples: `lround(0.5)` ==> 1.0; `lround(-0.5)` ==> -1.0
    static long int lround(ValueType32  x);
    static long int lround(ValueType64  x);
    static long int lround(ValueType128 x);

    /// Return the specified `x` value rounded to the specified `precision`.
    /// Round halfway cases away from zero, regardless of the current
    /// decimal floating point rounding mode.  If `x` is integral, positive
    /// zero, negative zero, NaN, or infinity then return `x` itself.
    ///
    ///  Examples: `round(3.14159, 3)` ==> 3.142
    static ValueType32  round(ValueType32  x, unsigned int precision);
    static ValueType64  round(ValueType64  x, unsigned int precision);
    static ValueType128 round(ValueType128 x, unsigned int precision);


    /// Return the nearest integral value that is not greater in absolute
    /// value than the specified `x`.
    ///
    /// Special value handling:
    /// * if `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    /// * if `x` is +/-infinity or +/-0, it is returned unmodified.
    ///
    /// Examples: `trunc(0.5)` ==> 0.0; `trunc(-0.5)` ==> 0.0
    static ValueType32  trunc(ValueType32  x);
    static ValueType64  trunc(ValueType64  x);
    static ValueType128 trunc(ValueType128 x);

    /// Return, using the specified `x`, `y`, and `z`, the value of the
    /// expression `x * y + z`, rounded as one ternary operation according
    /// to the current decimal floating point rounding mode.
    ///
    /// Special value handling:
    /// * If `x` or `y` are quiet NaN, quiet NaN is returned.
    /// * If any argument is signaling NaN, quiet NaN is returned and the
    ///   value of the macro `EDOM` is stored into `errno`.
    /// * If `x*y` is an exact infinity and `z` is infinity with the
    ///   opposite sign, quiet NaN is returned and the value of the macro
    ///   `EDOM` is stored into `errno`.
    /// * If `x` is zero and `y` is infinite or if `x` is infinite and `y`
    ///   is zero, and `z` is not a NaN, then quiet NaN is returned and the
    ///   value of the macro `EDOM` is stored into `errno`.
    /// * If `x` is zero and `y` is infinite or if `x` is infinite and `y`
    ///   is zero, and `z` is NaN, then quiet NaN is returned.
    static ValueType32  fma(ValueType32  x, ValueType32  y, ValueType32  z);
    static ValueType64  fma(ValueType64  x, ValueType64  y, ValueType64  z);
    static ValueType128 fma(ValueType128 x, ValueType128 y, ValueType128 z);

    /// Return the absolute value of the specified `x`.
    ///
    /// Special value handling:
    /// * if `x` is NaN (either signaling or quiet), quiet NaN is returned.
    /// * if `x` is +/-infinity or +/-0, it is returned unmodified.
    static ValueType32  fabs(ValueType32  x);
    static ValueType64  fabs(ValueType64  x);
    static ValueType128 fabs(ValueType128 x);

    /// Return the square root of the specified `x`.
    ///
    /// Special value handling:
    /// * If `x` is quiet NaN, quiet NaN is returned.
    /// * If `x` is signaling NaN, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    /// * If `x` is less than -0, quiet NaN is returned and the value of
    ///   the macro `EDOM` is stored into `errno`.
    /// * If `x` is +/-infinity or +/-0, it is returned unmodified.
    static ValueType32  sqrt(ValueType32  x);
    static ValueType64  sqrt(ValueType64  x);
    static ValueType128 sqrt(ValueType128 x);

                        // Negation functions

    /// Return the result of applying the unary negation (`-`) operator to
    /// the specified `value` as described by IEEE-754.  Note that decimal
    /// floating point representations can encode signed zero values, thus
    /// negating 0 results in -0 and negating -0 results in 0.
    static ValueType32  negate(ValueType32  value);
    static ValueType64  negate(ValueType64  value);
    static ValueType128 negate(ValueType128 value);

                        // Comparison functions

                        // Less Than functions

    /// Return `true` if the specified `lhs` has a value less than the
    /// specified `rhs` and `false` otherwise.  The value of a `Decimal64`
    /// object `lhs` is less than that of an object `rhs` if the
    /// `compareQuietLess` operation (IEEE-754 defined, non-total ordering
    /// comparison) considers the underlying IEEE representation of `lhs` to
    /// be less than of that of `rhs`.  In other words, `lhs` is less than
    /// `rhs` if:
    ///
    /// * neither `lhs` nor `rhs` are NaN, or
    /// * `lhs` is zero (positive or negative) and `rhs` is positive, or
    /// * `rhs` is zero (positive or negative) and `lhs` negative, or
    /// * `lhs` is not positive infinity, or
    /// * `lhs` is negative infinity and `rhs` is not, or
    /// * `lhs` and `rhs` both represent a real number and the real number
    ///   of `lhs` is less than that of `rhs`
    ///
    /// If either or both operands are signaling NaN, store the value of the
    /// macro `EDOM` into `errno` and return `false`.
    static bool less(ValueType32  lhs, ValueType32  rhs);
    static bool less(ValueType64  lhs, ValueType64  rhs);
    static bool less(ValueType128 lhs, ValueType128 rhs);

                        // Greater Than functions

    /// Return `true` if the specified `lhs` has a greater value than the
    /// specified `rhs` and `false` otherwise.  The value of a `Decimal64`
    /// object `lhs` is greater than that of an object `rhs` if the
    /// `compareQuietGreater` operation (IEEE-754 defined, non-total
    /// ordering comparison) considers the underlying IEEE representation of
    /// `lhs` to be greater than of that of `rhs`.  In other words, `lhs` is
    /// greater than `rhs` if:
    ///
    /// * neither `lhs` nor `rhs` are NaN, or
    /// * `rhs` is zero (positive or negative) and `lhs` positive, or
    /// * `lhs` is zero (positive or negative) and `rhs` negative, or
    /// * `lhs` is not negative infinity, or
    /// * `lhs` is positive infinity and `rhs` is not, or
    /// * `lhs` and `rhs` both represent a real number and the real number
    ///   of `lhs` is greater than that of `rhs`
    ///
    /// If either or both operands are signaling NaN, store the value of the
    /// macro `EDOM` into `errno` and return `false`.
    static bool greater(ValueType32  lhs, ValueType32  rhs);
    static bool greater(ValueType64  lhs, ValueType64  rhs);
    static bool greater(ValueType128 lhs, ValueType128 rhs);

                        // Less Or Equal functions

    /// Return `true` if the specified `lhs` has a value less than or equal
    /// the value of the specified `rhs` and `false` otherwise.  The value
    /// of a `Decimal64` object `lhs` is less than or equal to the value of
    /// an object `rhs` if the `compareQuietLessEqual` operation (IEEE-754
    /// defined, non-total ordering comparison) considers the underlying
    /// IEEE representation of `lhs` to be less or equal to that of `rhs`.
    /// In other words, `lhs` is less or equal than `rhs` if:
    ///
    /// * neither `lhs` nor `rhs` are NaN, or
    /// * `lhs` and `rhs` are both zero (positive or negative), or
    /// * both `lhs` and `rhs` are positive infinity, or
    /// * `lhs` is negative infinity, or
    /// * `lhs` and `rhs` both represent a real number and the real number
    ///   of `lhs` is less or equal to that of `rhs`
    ///
    /// If either or both operands are signaling NaN, store the value of the
    /// macro `EDOM` into `errno` and return `false`.
    static bool lessEqual(ValueType32  lhs, ValueType32  rhs);
    static bool lessEqual(ValueType64  lhs, ValueType64  rhs);
    static bool lessEqual(ValueType128 lhs, ValueType128 rhs);

                        // Greater Or Equal functions

    /// Return `true` if the specified `lhs` has a value greater than or
    /// equal to the value of the specified `rhs` and `false` otherwise.
    /// The value of a `Decimal64` object `lhs` is greater or equal to a
    /// `Decimal64` object `rhs` if the `compareQuietGreaterEqual` operation
    /// (IEEE-754 defined, non-total ordering comparison ) considers the
    /// underlying IEEE representation of `lhs` to be greater or equal to
    /// that of `rhs`.  In other words, `lhs` is greater than or equal to
    /// `rhs` if:
    ///
    /// * neither `lhs` nor `rhs` are NaN, or
    /// * `lhs` and `rhs` are both zero (positive or negative), or
    /// * both `lhs` and `rhs` are negative infinity, or
    /// * `lhs` is positive infinity, or
    /// * `lhs` and `rhs` both represent a real number and the real number
    ///   of `lhs` is greater or equal to that of `rhs`
    ///
    /// If either or both operands are signaling NaN, store the value of the
    /// macro `EDOM` into `errno` and return `false`.
    static bool greaterEqual(ValueType32  lhs, ValueType32  rhs);
    static bool greaterEqual(ValueType64  lhs, ValueType64  rhs);
    static bool greaterEqual(ValueType128 lhs, ValueType128 rhs);

                        // Equality functions

    /// Return `true` if the specified `lhs` and `rhs` have the same value,
    /// and `false` otherwise.  Two decimal objects have the same value if
    /// the `compareQuietEqual` operation (IEEE-754 defined, non-total
    /// ordering comparison) considers the underlying IEEE representations
    /// equal.  In other words, two decimal objects have the same value if:
    ///
    /// * both have a zero value (positive or negative), or
    /// * both have the same infinity value (both positive or negative), or
    /// * both have the value of a real number that are equal, even if they
    ///   are represented differently (cohorts have the same value)
    ///
    /// If either or both operands are signaling NaN, store the value of the
    /// macro `EDOM` into `errno` and return `false`.
    static bool equal(ValueType32  lhs, ValueType32  rhs);
    static bool equal(ValueType64  lhs, ValueType64  rhs);
    static bool equal(ValueType128 lhs, ValueType128 rhs);

                        // Inequality functions

    /// Return `false` if the specified `lhs` and `rhs` have the same value,
    /// and `true` otherwise.  Two decimal objects have the same value if
    /// the `compareQuietEqual` operation (IEEE-754 defined, non-total
    /// ordering comparison) considers the underlying IEEE representations
    /// equal.  In other words, two decimal objects have the same value if:
    ///
    /// * both have a zero value (positive or negative), or
    /// * both have the same infinity value (both positive or negative), or
    /// * both have the value of a real number that are equal, even if they
    ///   are represented differently (cohorts have the same value)
    ///
    /// If either or both operands are signaling NaN, store the value of the
    /// macro `EDOM` into `errno` and return `false`.
    static bool notEqual(ValueType32  lhs, ValueType32  rhs);
    static bool notEqual(ValueType64  lhs, ValueType64  rhs);
    static bool notEqual(ValueType128 lhs, ValueType128 rhs);

                        // Inter-type Conversion functions

    static ValueType32  convertToDecimal32 (const ValueType64&  input);
    static ValueType32  convertToDecimal32 (const ValueType128& input);
    static ValueType64  convertToDecimal64 (const ValueType32&  input);
    static ValueType64  convertToDecimal64 (const ValueType128& input);

    /// Convert the specified `input` to the closest value of the indicated
    /// result type following the conversion rules as defined by IEEE-754:
    ///
    /// * If `input` is signaling NaN, store the value of the macro `EDOM`
    ///   into `errno` and return signaling NaN value.
    /// * If `input` is NaN, return NaN value.
    /// * Otherwise if `input` is infinity (positive or negative), then
    ///   return infinity with the same sign.
    /// * Otherwise if `input` is zero (positive or negative), then
    ///   return zero with the same sign.
    /// * Otherwise if `input` has an absolute value that is larger than
    ///   maximum or is smaller than minimum value supported by the result
    ///   type, store the value of the macro `ERANGE` into `errno` and
    ///   return infinity or zero with the same sign respectively.
    /// * Otherwise if `input` has a value that is not exactly
    ///   representable using maximum digit number supported by the
    ///   indicated result type then return the `input` rounded according
    ///   to the rounding direction.
    /// * Otherwise return `input` value of the result type.
    static ValueType128 convertToDecimal128(const ValueType32&  input);
    static ValueType128 convertToDecimal128(const ValueType64&  input);

                        // Binary floating point conversion functions

    /// Create a `Decimal32` object having the value closest to the
    /// specified `value` following the conversion rules as defined by
    /// IEEE-754:
    ///
    /// * If `value` is signaling NaN, store the value of the macro `EDOM`
    ///   into `errno` and return signaling NaN value.
    /// * Otherwise if `value` is NaN, return a NaN.
    /// * Otherwise if `value` is infinity (positive or negative), then
    ///   return an object equal to infinity with the same sign.
    /// * Otherwise if `value` is a zero value, then return an object equal
    ///   to zero with the same sign.
    /// * Otherwise if `value` has an absolute value that is larger than
    ///   `std::numeric_limits<Decimal32>::max()` then store the value of
    ///   the macro `ERANGE` into `errno` and return infinity with the same
    ///   sign as `value`.
    /// * Otherwise if `value` has an absolute value that is smaller than
    ///   `std::numeric_limits<Decimal32>::min()` then store the value of
    ///   the macro `ERANGE` into `errno` and return a zero with the same
    ///   sign as `value`.
    /// * Otherwise if `value` needs more than
    ///   `std::numeric_limits<Decimal32>::max_digit` significant decimal
    ///   digits to represent then return the `value` rounded according to
    ///   the rounding direction.
    /// * Otherwise return a `Decimal32` object representing `value`.
    static ValueType32  binaryToDecimal32(      float value);
    static ValueType32  binaryToDecimal32(     double value);

    /// Create a `Decimal64` object having the value closest to the
    /// specified `value` following the conversion rules as defined by
    /// IEEE-754:
    ///
    /// * If `value` is signaling NaN, store the value of the macro `EDOM`
    ///   into `errno` and return signaling NaN value.
    /// * Otherwise if `value` is NaN, return a NaN.
    /// * Otherwise if `value` is infinity (positive or negative), then
    ///   return an object equal to infinity with the same sign.
    /// * Otherwise if `value` is a zero value, then return an object equal
    ///   to zero with the same sign.
    /// * Otherwise if `value` needs more than
    ///   `std::numeric_limits<Decimal64>::max_digit` significant decimal
    ///   digits to represent then return the `value` rounded according to
    ///   the rounding direction.
    /// * Otherwise return a `Decimal64` object representing `value`.
    static ValueType64  binaryToDecimal64(      float value);
    static ValueType64  binaryToDecimal64(     double value);

    /// Create a `Decimal128` object having the value closest to the
    /// specified `value` following the conversion rules as defined by
    /// IEEE-754:
    ///
    /// * If `value` is signaling NaN, store the value of the macro `EDOM`
    ///   into `errno` and return signaling NaN value.
    /// * Otherwise if `value` is NaN, return a NaN.
    /// * Otherwise if `value` is infinity (positive or negative), then
    ///   return an object equal to infinity with the same sign.
    /// * Otherwise if `value` is a zero value, then return an object equal
    ///   to zero with the same sign.
    /// * Otherwise if `value` has an absolute value that is larger than
    ///   `std::numeric_limits<Decimal128>::max()` then store the value of
    ///   the macro `ERANGE` into `errno` and return infinity with the same
    ///   sign as `value`.
    /// * Otherwise if `value` has an absolute value that is smaller than
    ///   `std::numeric_limits<Decimal128>::min()` then store the value of
    ///   the macro `ERANGE` into `errno` and return a zero with the same
    ///   sign as `value`.
    /// * Otherwise if `value` needs more than
    ///   `std::numeric_limits<Decimal128>::max_digit` significant decimal
    ///   digits to represent then return the `value` rounded according to
    ///   the rounding direction.
    /// * Otherwise return a `Decimal128` object representing `value`.
    static ValueType128 binaryToDecimal128(      float value);
    static ValueType128 binaryToDecimal128(     double value);

                        // makeDecimalRaw functions

    /// Create a `ValueType32` object representing a decimal floating point
    /// number consisting of the specified `significand` and `exponent`,
    /// with the sign given by `significand`.  The behavior is undefined
    /// unless `abs(significand) <= 9,999,999` and `-101 <= exponent <= 90`.
    static ValueType32 makeDecimalRaw32(int significand, int exponent);

    /// Create a `ValueType64` object representing a decimal floating point
    /// number consisting of the specified `significand` and `exponent`,
    /// with the sign given by `significand`.  The behavior is undefined
    /// unless `abs(significand) <= 9,999,999,999,999,999` and
    /// `-398 <= exponent <= 369`.
    static ValueType64 makeDecimalRaw64(unsigned long long int significand,
                                                           int exponent);
    static ValueType64 makeDecimalRaw64(         long long int significand,
                                                           int exponent);
    static ValueType64 makeDecimalRaw64(unsigned           int significand,
                                                           int exponent);
    static ValueType64 makeDecimalRaw64(                   int significand,
                                                           int exponent);

    /// Create a `ValueType128` object representing a decimal floating point
    /// number consisting of the specified `significand` and `exponent`,
    /// with the sign given by `significand`.  The behavior is undefined
    /// unless `-6176 <= exponent <= 6111`.
    static ValueType128 makeDecimalRaw128(unsigned long long int significand,
                                                             int exponent);
    static ValueType128 makeDecimalRaw128(         long long int significand,
                                                             int exponent);
    static ValueType128 makeDecimalRaw128(unsigned           int significand,
                                                             int exponent);
    static ValueType128 makeDecimalRaw128(                   int significand,
                                                             int exponent);

                        // ScaleB functions

    /// Return the result of multiplying the specified `value` by ten raised
    /// to the specified `exponent`.  The quantum of `value` is scaled
    /// according to IEEE 754's `scaleB` operations.
    ///
    /// Special value handling:
    /// * If `value` is quiet NaN, quiet NaN is returned.
    /// * If `value` is signaling NaN, quiet NaN is returned and the value
    ///   of the macro `EDOM` is stored into `errno`.
    /// * If `x` is infinite, then infinity is returned.
    /// * If a range error due to overflow occurs, infinity is returned and
    ///: the value of the macro `ERANGE` is stored into `errno`.
    static ValueType32  scaleB(ValueType32  value, int exponent);
    static ValueType64  scaleB(ValueType64  value, int exponent);
    static ValueType128 scaleB(ValueType128 value, int exponent);

                        // Parsing functions

    static ValueType32  parse32( const char *input);
    static ValueType64  parse64( const char *input);
    static ValueType128 parse128(const char *input);
    static ValueType32  parse32( const char *input, unsigned int *status);
    static ValueType64  parse64( const char *input, unsigned int *status);

    /// Produce an object of the indicated return type by parsing the
    /// specified `input` string that represents a floating-point number
    /// (written in either fixed or scientific notation).  Optionally
    /// specify `status` in which to load a bit mask of additional status
    /// information.  The resulting decimal object is initialized as follows:
    ///
    /// * If `input` does not represent a floating-point value, then return
    ///   a decimal object of the indicated return type initialized to a
    ///   NaN.
    /// * Otherwise if `input` represents infinity (positive or negative),
    ///   as case-insensitive "Inf" or "Infinity" string, then return a
    ///   decimal object of the indicated return type initialized to
    ///   infinity value with the same sign.
    /// * Otherwise if `input` represents zero (positive or negative), then
    ///   return a decimal object of the indicated return type initialized
    ///   to zero with the same sign.
    /// * Otherwise if `str` represents a value that has an absolute value
    ///   that is larger than `std::numeric_limits<Decimal32>::max()` then
    ///   store the value of the macro `ERANGE` into `errno` and return a
    ///   decimal object of the indicated return type initialized to
    ///   infinity with the same sign.
    /// * Otherwise if `input` represents a value that has an absolute
    ///   value that is smaller than
    ///   `std::numeric_limits<Decimal32>::min()`, then store the value of
    ///   the macro `ERANGE` into `errno` and return a decimal object of
    ///   the indicated return type initialized to zero with the same sign.
    /// * Otherwise if `input` has a value that is not exactly
    ///   representable using `std::numeric_limits<Decimal32>::max_digit`
    ///   decimal digits then return a decimal object of the indicated
    ///   return type initialized to the value represented by `input`
    ///   rounded according to the rounding direction.
    /// * Otherwise return a decimal object of the indicated return type
    ///   initialized to the decimal value representation of `input`.
    ///
    /// The `*status`, if supplied, mest be 0, and may be loaded with a bit
    /// mask of `k_STATUS_INEXACT`, `k_STATUS_UNDERFLOW`, and
    /// `k_STATUS_OVERFLOW` indicating wether the conversion from text was
    /// inexact, underflowed, or overflowed (or some combination)
    /// respectively.  The behavior is undefined unless `*status` (if
    /// supplied) is 0.
    ///
    /// Note that the parsing follows the rules as specified for the
    /// `strtod32` function in section 9.6 of the ISO/EIC TR 24732 C Decimal
    /// Floating-Point Technical Report.
    ///
    /// Also note that the quanta of the resultant value is determined by
    /// the number of decimal places starting with the most significand
    /// digit in `input` string and cannot exceed the maximum number of
    /// digits necessary to differentiate all values of the indicated return
    /// type, for example:
    ///
    /// ```
    /// 'parse32("0.015")    => 15e-3'
    /// 'parse32("1.5")      => 15e-1'
    /// 'parse32("1.500")    => 1500e-3'
    /// 'parse32("1.2345678) => 1234568e-6'
    /// ```
    static ValueType128 parse128(const char *input, unsigned int *status);

    // Densely Packed Conversion Functions

    /// Return a `ValueTypeXX` representing the specified `dpd`, which is
    /// currently in Densely Packed Decimal (DPD) format.  This format is
    /// compatible with the IBM compiler's native type.
    static ValueType32  convertDPDtoBID(DecimalStorage::Type32  dpd);
    static ValueType64  convertDPDtoBID(DecimalStorage::Type64  dpd);
    static ValueType128 convertDPDtoBID(DecimalStorage::Type128 dpd);

    /// Return a `DecimalStorage::TypeXX` representing the specified `value`
    /// in Densely Packed Decimal (DPD) format.  This format is compatible
    /// with the IBM compiler's native type.
    static DecimalStorage::Type32  convertBIDtoDPD(ValueType32  value);
    static DecimalStorage::Type64  convertBIDtoDPD(ValueType64  value);
    static DecimalStorage::Type128 convertBIDtoDPD(ValueType128 value);

                        // Binary Integral Conversion Functions

    /// Return a `ValueTypeXX` representing the specified `bid`, which is
    /// currently in Binary Integral Decimal (BID) format.  This format is
    /// compatible with the Intel DFP implementation type.
    static ValueType32  convertFromBID(DecimalStorage::Type32  bid);
    static ValueType64  convertFromBID(DecimalStorage::Type64  bid);
    static ValueType128 convertFromBID(DecimalStorage::Type128 bid);

    /// Return a `DecimalStorage::TypeXX` representing  the specified
    /// `value` in Binary Integral Decimal (BID) format.  This format is
    /// compatible with the Intel DFP implementation type.
    static
    DecimalStorage::Type32  convertToBID(ValueType32  value);
    static
    DecimalStorage::Type64  convertToBID(ValueType64  value);
    static
    DecimalStorage::Type128 convertToBID(ValueType128 value);

                  // Functions returning special values

    /// Return the smallest positive normalized number `ValueType32` can
    /// represent (IEEE-754: +1e-95).
    static
    ValueType32 min32() BSLS_KEYWORD_NOEXCEPT;

    /// Return the largest number `ValueType32` can represent (IEEE-754:
    /// +9.999999e+96).
    static
    ValueType32 max32() BSLS_KEYWORD_NOEXCEPT;

    /// Return the difference between the least representable value of type
    /// `ValueType32` greater than 1 and 1 (IEEE-754: +1e-6).
    static
    ValueType32 epsilon32() BSLS_KEYWORD_NOEXCEPT;

    /// Return the maximum rounding error for the `ValueType32` type.  The
    /// actual value returned depends on the current decimal floating point
    /// rounding setting.
    static
    ValueType32 roundError32() BSLS_KEYWORD_NOEXCEPT;

    /// Return the smallest positive denormalized value for the
    /// `ValueType32` type (IEEE-754: +0.000001e-95).
    static
    ValueType32 denormMin32() BSLS_KEYWORD_NOEXCEPT;

    /// Return the value that represents positive infinity for the
    /// `ValueType32` type.
    static
    ValueType32 infinity32() BSLS_KEYWORD_NOEXCEPT;

    /// Return a value that represents non-signaling NaN for the
    /// `ValueType32` type.
    static
    ValueType32 quietNaN32() BSLS_KEYWORD_NOEXCEPT;

    /// Return a value that represents signaling NaN for the `ValueType32`
    /// type.
    static
    ValueType32 signalingNaN32() BSLS_KEYWORD_NOEXCEPT;

    /// Return the smallest positive normalized number `ValueType64` can
    /// represent (IEEE-754: +1e-383).
    static
    ValueType64 min64() BSLS_KEYWORD_NOEXCEPT;

    /// Return the largest number `ValueType64` can represent (IEEE-754:
    /// +9.999999999999999e+384).
    static
    ValueType64 max64() BSLS_KEYWORD_NOEXCEPT;

    /// Return the difference between the least representable value of type
    /// `ValueType64` greater than 1 and 1 (IEEE-754: +1e-15).
    static
    ValueType64 epsilon64() BSLS_KEYWORD_NOEXCEPT;

    /// Return the maximum rounding error for the `ValueType64` type.  The
    /// actual value returned depends on the current decimal floating point
    /// rounding setting.
    static
    ValueType64 roundError64() BSLS_KEYWORD_NOEXCEPT;

    /// Return the smallest positive denormalized value for the
    /// `ValueType64` type (IEEE-754: +0.000000000000001e-383).
    static
    ValueType64 denormMin64() BSLS_KEYWORD_NOEXCEPT;

    /// Return the value that represents positive infinity for the
    /// `ValueType64` type.
    static
    ValueType64 infinity64() BSLS_KEYWORD_NOEXCEPT;

    /// Return a value that represents non-signaling NaN for the
    /// `ValueType64` type.
    static
    ValueType64 quietNaN64() BSLS_KEYWORD_NOEXCEPT;

    /// Return a value that represents signaling NaN for the `ValueType64`
    /// type.
    static
    ValueType64 signalingNaN64() BSLS_KEYWORD_NOEXCEPT;

    /// Return the smallest positive normalized number `ValueType128` can
    /// represent (IEEE-754: +1e-6143).
    static
    ValueType128 min128() BSLS_KEYWORD_NOEXCEPT;

    /// Return the largest number `ValueType128` can represent (IEEE-754:
    /// +9.999999999999999999999999999999999e+6144).
    static
    ValueType128 max128() BSLS_KEYWORD_NOEXCEPT;

    /// Return the difference between the least representable value of type
    /// `ValueType128` greater than 1 and 1 (IEEE-754: +1e-33).
    static
    ValueType128 epsilon128() BSLS_KEYWORD_NOEXCEPT;

    /// Return the maximum rounding error for the `ValueType128` type.  The
    /// actual value returned depends on the current decimal floating point
    /// rounding setting.
    static
    ValueType128 roundError128() BSLS_KEYWORD_NOEXCEPT;

    /// Return the smallest positive denormalized value for the
    /// `ValueType128` type (IEEE-754:
    /// +0.000000000000000000000000000000001e-6143).
    static
    ValueType128 denormMin128() BSLS_KEYWORD_NOEXCEPT;

    /// Return the value that represents positive infinity for the
    /// `ValueType128` type.
    static
    ValueType128 infinity128() BSLS_KEYWORD_NOEXCEPT;

    /// Return a value that represents non-signaling NaN for the
    /// `ValueType128` type.
    static
    ValueType128 quietNaN128() BSLS_KEYWORD_NOEXCEPT;

    /// Return a value that represents signaling NaN for the `ValueType128`
    /// type.
    static
    ValueType128 signalingNaN128() BSLS_KEYWORD_NOEXCEPT;
};

// ============================================================================
//                              INLINE DEFINITIONS
// ============================================================================

                          // --------------------
                          // class DecimalImpUtil
                          // --------------------

#ifdef BDLDFP_DECIMALPLATFORM_SOFTWARE

template <class TYPE>
inline
void DecimalImpUtil::checkLiteral(const TYPE& t)
{
    (void)static_cast<This_is_not_a_floating_point_literal>(t);
}

inline
void DecimalImpUtil::checkLiteral(double)
{
}
#endif


// CLASS METHODS

                    // Integer construction

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::int32ToDecimal32(int value)
{
    return Imp::int32ToDecimal32(value);
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::int32ToDecimal64(int value)
{
    return Imp::int32ToDecimal64(value);
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::int32ToDecimal128(int value)
{
    return Imp::int32ToDecimal128(value);
}


inline
DecimalImpUtil::ValueType32
DecimalImpUtil::uint32ToDecimal32(unsigned int value)
{
    return Imp::uint32ToDecimal32(value);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::uint32ToDecimal64(unsigned int value)
{
    return Imp::uint32ToDecimal64(value);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::uint32ToDecimal128(unsigned int value)
{
    return Imp::uint32ToDecimal128(value);
}


inline
DecimalImpUtil::ValueType32
DecimalImpUtil::int64ToDecimal32(long long int value)
{
    return Imp::int64ToDecimal32(value);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::int64ToDecimal64(long long int value)
{
    return Imp::int64ToDecimal64(value);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::int64ToDecimal128(long long int value)
{
    return Imp::int64ToDecimal128(value);
}


inline
DecimalImpUtil::ValueType32
DecimalImpUtil::uint64ToDecimal32(unsigned long long int value)
{
    return Imp::uint64ToDecimal32(value);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::uint64ToDecimal64(unsigned long long int value)
{
    return Imp::uint64ToDecimal64(value);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::uint64ToDecimal128(unsigned long long int value)
{
    return Imp::uint64ToDecimal128(value);
}

                        // Arithmetic

                        // Addition Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::add(DecimalImpUtil::ValueType32 lhs,
                    DecimalImpUtil::ValueType32 rhs)
{
    return Imp::add(lhs, rhs);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::add(DecimalImpUtil::ValueType64 lhs,
                    DecimalImpUtil::ValueType64 rhs)
{
    return Imp::add(lhs, rhs);
}

inline DecimalImpUtil::ValueType128
DecimalImpUtil::add(DecimalImpUtil::ValueType128 lhs,
                    DecimalImpUtil::ValueType128 rhs)
{
    return Imp::add(lhs, rhs);
}

                        // Subtraction Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::subtract(DecimalImpUtil::ValueType32 lhs,
                         DecimalImpUtil::ValueType32 rhs)
{
    return Imp::subtract(lhs, rhs);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::subtract(DecimalImpUtil::ValueType64 lhs,
                         DecimalImpUtil::ValueType64 rhs)
{
    return Imp::subtract(lhs, rhs);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::subtract(DecimalImpUtil::ValueType128 lhs,
                         DecimalImpUtil::ValueType128 rhs)
{
    return Imp::subtract(lhs, rhs);
}

                        // Multiplication Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::multiply(DecimalImpUtil::ValueType32 lhs,
                         DecimalImpUtil::ValueType32 rhs)
{
    return Imp::multiply(lhs, rhs);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::multiply(DecimalImpUtil::ValueType64 lhs,
                         DecimalImpUtil::ValueType64 rhs)
{
    return Imp::multiply(lhs, rhs);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::multiply(DecimalImpUtil::ValueType128 lhs,
                         DecimalImpUtil::ValueType128 rhs)
{
    return Imp::multiply(lhs, rhs);
}

                        // Division Functions

                        // Division Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::divide(DecimalImpUtil::ValueType32 lhs,
                       DecimalImpUtil::ValueType32 rhs)
{
    return Imp::divide(lhs, rhs);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::divide(DecimalImpUtil::ValueType64 lhs,
                       DecimalImpUtil::ValueType64 rhs)
{
    return Imp::divide(lhs, rhs);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::divide(DecimalImpUtil::ValueType128 lhs,
                       DecimalImpUtil::ValueType128 rhs)
{
    return Imp::divide(lhs, rhs);
}

inline
DecimalImpUtil::ValueType32  DecimalImpUtil::quantize(ValueType32  value,
                                                      ValueType32  exponent)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_quantize(value.d_raw,
                                    exponent.d_raw,
                                    &flags);
    return retval;
}

inline
DecimalImpUtil::ValueType64  DecimalImpUtil::quantize(ValueType64  value,
                                                      ValueType64  exponent)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_quantize(value.d_raw,
                                    exponent.d_raw,
                                    &flags);
    return retval;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::quantize(ValueType128 value,
                                                      ValueType128 exponent)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_quantize(value.d_raw,
                                     exponent.d_raw,
                                     &flags);
    return retval;
}

inline
DecimalImpUtil::ValueType32  DecimalImpUtil::quantize(ValueType32  value,
                                                      int          exponent)
{
    BSLS_ASSERT(-101 <= exponent);
    BSLS_ASSERT(        exponent <= 90);

    DecimalImpUtil::ValueType32 retval;
    DecimalImpUtil::ValueType32 exp = DecimalImpUtil::makeDecimalRaw32(
                                                                     1,
                                                                     exponent);
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_quantize(value.d_raw, exp.d_raw, &flags);
    return retval;
}

inline
DecimalImpUtil::ValueType64  DecimalImpUtil::quantize(ValueType64  value,
                                                      int          exponent)
{
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);

    DecimalImpUtil::ValueType64 retval;
    DecimalImpUtil::ValueType64 exp = DecimalImpUtil::makeDecimalRaw64(
                                                                     1,
                                                                     exponent);
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_quantize(value.d_raw, exp.d_raw, &flags);
    return retval;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::quantize(ValueType128 value,
                                                      int          exponent)
{
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);

    DecimalImpUtil::ValueType128 retval;
    DecimalImpUtil::ValueType128 exp = DecimalImpUtil::makeDecimalRaw128(
                                                                     1,
                                                                     exponent);
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_quantize(value.d_raw, exp.d_raw, &flags);
    return retval;
}

inline
int DecimalImpUtil::quantizeEqual(ValueType32 *x, ValueType32 y, int exponent)
{
    BSLS_ASSERT(x);
    BSLS_ASSERT(-101 <= exponent);
    BSLS_ASSERT(        exponent <= 90);

    DecimalImpUtil::ValueType32 retval;
    DecimalImpUtil::ValueType32 exp = DecimalImpUtil::makeDecimalRaw32(
                                                                     1,
                                                                     exponent);
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_quantize(y.d_raw, exp.d_raw, &flags);
    if (DecimalImpUtil::equal(retval, y)) {
        *x = retval;
        return 0;
    }
    return -1;
}

inline
int DecimalImpUtil::quantizeEqual(ValueType64 *x, ValueType64 y, int exponent)
{
    BSLS_ASSERT(x);
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);
    DecimalImpUtil::ValueType64 retval;
    DecimalImpUtil::ValueType64 exp = DecimalImpUtil::makeDecimalRaw64(
                                                                     1,
                                                                     exponent);
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_quantize(y.d_raw, exp.d_raw, &flags);
    if (DecimalImpUtil::equal(retval, y)) {
        *x = retval;
        return 0;
    }
    return -1;
}

inline
int DecimalImpUtil::quantizeEqual(ValueType128 *x, ValueType128 y, int exponent)
{
    BSLS_ASSERT(x);
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);

    DecimalImpUtil::ValueType128 retval;
    DecimalImpUtil::ValueType128 exp = DecimalImpUtil::makeDecimalRaw128(
                                                                     1,
                                                                     exponent);
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_quantize(y.d_raw, exp.d_raw, &flags);
    if (DecimalImpUtil::equal(retval, y)) {
        *x = retval;
        return 0;
    }
    return -1;
}

inline
bool DecimalImpUtil::sameQuantum(ValueType32  x, ValueType32  y)
{
    return __bid32_sameQuantum(x.d_raw, y.d_raw);
}

inline
bool DecimalImpUtil::sameQuantum(ValueType64  x, ValueType64  y)
{
    return __bid64_sameQuantum(x.d_raw, y.d_raw);
}

inline
bool DecimalImpUtil::sameQuantum(ValueType128 x, ValueType128 y)
{
    return __bid128_sameQuantum(x.d_raw, y.d_raw);
}


                        // Math functions

inline
long int DecimalImpUtil::lrint(ValueType32  x)
{
    _IDEC_flags flags(0);
    long int ret =  __bid32_lrint(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return ret;
}

inline
long int DecimalImpUtil::lrint(ValueType64  x)
{
    _IDEC_flags flags(0);
    long int ret =  __bid64_lrint(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return ret;
}

inline
long int DecimalImpUtil::lrint(ValueType128 x)
{
    _IDEC_flags flags(0);
    long int ret =  __bid128_lrint(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return ret;
}

inline
long long int DecimalImpUtil::llrint(ValueType32  x)
{
    _IDEC_flags flags(0);
    long long int ret =  __bid32_llrint(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return ret;
}

inline
long long int DecimalImpUtil::llrint(ValueType64  x)
{
    _IDEC_flags flags(0);
    long long int ret =  __bid64_llrint(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return ret;
}

inline
long long int DecimalImpUtil::llrint(ValueType128 x)
{
    _IDEC_flags flags(0);
    long long int ret =  __bid128_llrint(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return ret;
}

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::nextafter(ValueType32  x, ValueType32  y)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_nextafter(x.d_raw, y.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::nextafter(ValueType64  x, ValueType64  y)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_nextafter(x.d_raw, y.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::nextafter(ValueType128 x, ValueType128 y)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_nextafter(x.d_raw, y.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::nexttoward(ValueType32  x, ValueType128 y)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_nexttoward(x.d_raw, y.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::nexttoward(ValueType64  x, ValueType128 y)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_nexttoward(x.d_raw, y.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::nexttoward(ValueType128 x, ValueType128 y)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_nexttoward(x.d_raw, y.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::pow(ValueType32  base, ValueType32  exp)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_pow(base.d_raw, exp.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION    & flags ||
        BID_UNDERFLOW_EXCEPTION   & flags ||
        BID_ZERO_DIVIDE_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::pow(ValueType64  base, ValueType64  exp)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_pow(base.d_raw, exp.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION    & flags ||
        BID_UNDERFLOW_EXCEPTION   & flags ||
        BID_ZERO_DIVIDE_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }

    return retval;
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::pow(ValueType128 base, ValueType128 exp)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_pow(base.d_raw, exp.d_raw, &flags);
    if (BID_OVERFLOW_EXCEPTION    & flags ||
        BID_UNDERFLOW_EXCEPTION   & flags ||
        BID_ZERO_DIVIDE_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::ceil(ValueType32  x)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_round_integral_positive(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::ceil(ValueType64  x)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_round_integral_positive(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::ceil(ValueType128 x)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_round_integral_positive(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;

}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::floor(ValueType32 x)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_round_integral_negative(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::floor(ValueType64 x)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_round_integral_negative(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::floor(ValueType128 x)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_round_integral_negative(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::round(ValueType32 x)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_round_integral_nearest_away(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::round(ValueType64 x)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_round_integral_nearest_away(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::round(ValueType128 x)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_round_integral_nearest_away(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
long int DecimalImpUtil::lround(ValueType32 x)
{
    _IDEC_flags flags(0);
    long int rv = __bid32_lround(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
long int DecimalImpUtil::lround(ValueType64 x)
{
    _IDEC_flags flags(0);
    long int rv = __bid64_lround(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
long int DecimalImpUtil::lround(ValueType128 x)
{
    _IDEC_flags flags(0);
    long int rv = __bid128_lround(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::trunc(ValueType32 x)
{
    DecimalImpUtil::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_round_integral_zero(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::trunc(ValueType64 x)
{
    DecimalImpUtil::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_round_integral_zero(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::trunc(ValueType128 x)
{
    DecimalImpUtil::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_round_integral_zero(x.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return retval;
}


inline
DecimalImpUtil::ValueType32 DecimalImpUtil::fma(ValueType32 x, ValueType32 y, ValueType32 z)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_fma(x.d_raw, y.d_raw, z.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::fma(ValueType64 x, ValueType64 y, ValueType64 z)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_fma(x.d_raw, y.d_raw, z.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::fma(ValueType128 x, ValueType128 y, ValueType128 z)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_fma(x.d_raw, y.d_raw, z.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}
                       // Selecting, converting functions

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::fabs(ValueType32 value)
{
    ValueType32 rv;
    rv.d_raw = __bid32_abs(value.d_raw);
    return rv;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::fabs(ValueType64 value)
{
    ValueType64 rv;
    rv.d_raw = __bid64_abs(value.d_raw);
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::fabs(ValueType128 value)
{
    ValueType128 rv;
    rv.d_raw = __bid128_abs(value.d_raw);
    return rv;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::sqrt(ValueType32 value)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_sqrt(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::sqrt(ValueType64 value)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_sqrt(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::sqrt(ValueType128 value)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_sqrt(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType32  DecimalImpUtil::copySign(ValueType32  x,
                                                      ValueType32  y)
{
    ValueType32 rv;
    rv.d_raw = __bid32_copySign(x.d_raw, y.d_raw);
    return rv;
}

inline
DecimalImpUtil::ValueType64  DecimalImpUtil::copySign(ValueType64  x,
                                                      ValueType64  y)
{
    ValueType64 rv;
    rv.d_raw = __bid64_copySign(x.d_raw, y.d_raw);
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::copySign(ValueType128 x,
                                                      ValueType128 y)
{
    ValueType128 rv;
    rv.d_raw = __bid128_copySign(x.d_raw, y.d_raw);
    return rv;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::exp(ValueType32 value)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_exp(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_OVERFLOW_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::exp(ValueType64 value)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_exp(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_OVERFLOW_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::exp(ValueType128 value)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_exp(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_OVERFLOW_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::log(ValueType32 value)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_log(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::log(ValueType64 value)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_log(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::log(ValueType128 value)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_log(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::logB(ValueType32 value)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_logb(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::logB(ValueType64 value)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_logb(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::logB(ValueType128 value)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_logb(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType32 DecimalImpUtil::log10(ValueType32 value)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_log10(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64 DecimalImpUtil::log10(ValueType64 value)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_log10(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::log10(ValueType128 value)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_log10(value.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_ZERO_DIVIDE_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType32  DecimalImpUtil::fmod(ValueType32  x,
                                                  ValueType32  y)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_fmod(x.d_raw, y.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64  DecimalImpUtil::fmod(ValueType64  x,
                                                  ValueType64  y)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_fmod(x.d_raw, y.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::fmod(ValueType128 x,
                                                  ValueType128 y)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_fmod(x.d_raw, y.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType32  DecimalImpUtil::remainder(ValueType32  x,
                                                       ValueType32  y)
{
    ValueType32 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid32_rem(x.d_raw, y.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType64  DecimalImpUtil::remainder(ValueType64  x,
                                                       ValueType64  y)
{
    ValueType64 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid64_rem(x.d_raw, y.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return rv;
}

inline
DecimalImpUtil::ValueType128 DecimalImpUtil::remainder(ValueType128 x,
                                                       ValueType128 y)
{
    ValueType128 rv;
    _IDEC_flags flags(0);
    rv.d_raw = __bid128_rem(x.d_raw, y.d_raw, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    return rv;
}

                        // Negation Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::negate(DecimalImpUtil::ValueType32 value)
{
    return Imp::negate(value);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::negate(DecimalImpUtil::ValueType64 value)
{
    return Imp::negate(value);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::negate(DecimalImpUtil::ValueType128 value)
{
    return Imp::negate(value);
}

                        // Comparison

                        // Less Than Functions

inline
bool
DecimalImpUtil::less(DecimalImpUtil::ValueType32 lhs,
                     DecimalImpUtil::ValueType32 rhs)
{
    return Imp::less(lhs, rhs);
}

inline
bool
DecimalImpUtil::less(DecimalImpUtil::ValueType64 lhs,
                     DecimalImpUtil::ValueType64 rhs)
{
    return Imp::less(lhs, rhs);
}

inline
bool
DecimalImpUtil::less(DecimalImpUtil::ValueType128 lhs,
                     DecimalImpUtil::ValueType128 rhs)
{
    return Imp::less(lhs, rhs);
}

                        // Greater Than Functions

inline
bool
DecimalImpUtil::greater(DecimalImpUtil::ValueType32 lhs,
                        DecimalImpUtil::ValueType32 rhs)
{
    return Imp::greater(lhs, rhs);
}

inline
bool
DecimalImpUtil::greater(DecimalImpUtil::ValueType64 lhs,
                        DecimalImpUtil::ValueType64 rhs)
{
    return Imp::greater(lhs, rhs);
}

inline
bool
DecimalImpUtil::greater(DecimalImpUtil::ValueType128 lhs,
                        DecimalImpUtil::ValueType128 rhs)
{
    return Imp::greater(lhs, rhs);
}

                        // Less Or Equal Functions

inline
bool
DecimalImpUtil::lessEqual(DecimalImpUtil::ValueType32 lhs,
                          DecimalImpUtil::ValueType32 rhs)
{
    return Imp::lessEqual(lhs, rhs);
}

inline
bool
DecimalImpUtil::lessEqual(DecimalImpUtil::ValueType64 lhs,
                          DecimalImpUtil::ValueType64 rhs)
{
    return Imp::lessEqual(lhs, rhs);
}

inline
bool
DecimalImpUtil::lessEqual(DecimalImpUtil::ValueType128 lhs,
                          DecimalImpUtil::ValueType128 rhs)
{
    return Imp::lessEqual(lhs, rhs);
}

                        // Greater Or Equal Functions

inline
bool
DecimalImpUtil::greaterEqual(DecimalImpUtil::ValueType32 lhs,
                             DecimalImpUtil::ValueType32 rhs)
{
    return Imp::greaterEqual(lhs, rhs);
}

inline
bool
DecimalImpUtil::greaterEqual(DecimalImpUtil::ValueType64 lhs,
                             DecimalImpUtil::ValueType64 rhs)
{
    return Imp::greaterEqual(lhs, rhs);
}

inline
bool
DecimalImpUtil::greaterEqual(DecimalImpUtil::ValueType128 lhs,
                             DecimalImpUtil::ValueType128 rhs)
{
    return Imp::greaterEqual(lhs, rhs);
}

                        // Equality Functions

inline
bool
DecimalImpUtil::equal(DecimalImpUtil::ValueType32 lhs,
                      DecimalImpUtil::ValueType32 rhs)
{
    return Imp::equal(lhs, rhs);
}

inline
bool
DecimalImpUtil::equal(DecimalImpUtil::ValueType64 lhs,
                      DecimalImpUtil::ValueType64 rhs)
{
    return Imp::equal(lhs, rhs);
}

inline
bool
DecimalImpUtil::equal(DecimalImpUtil::ValueType128 lhs,
                      DecimalImpUtil::ValueType128 rhs)
{
    return Imp::equal(lhs, rhs);
}

                        // Inequality Functions

inline
bool
DecimalImpUtil::notEqual(DecimalImpUtil::ValueType32 lhs,
                         DecimalImpUtil::ValueType32 rhs)
{
    return Imp::notEqual(lhs, rhs);
}

inline
bool
DecimalImpUtil::notEqual(DecimalImpUtil::ValueType64 lhs,
                         DecimalImpUtil::ValueType64 rhs)
{
    return Imp::notEqual(lhs, rhs);
}

inline
bool
DecimalImpUtil::notEqual(DecimalImpUtil::ValueType128 lhs,
                         DecimalImpUtil::ValueType128 rhs)
{
    return Imp::notEqual(lhs, rhs);
}

                        // Inter-type Conversion functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::convertToDecimal32(const DecimalImpUtil::ValueType64& input)
{
    return Imp::convertToDecimal32(input);
}

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::convertToDecimal32(const DecimalImpUtil::ValueType128& input)
{
    return Imp::convertToDecimal32(input);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::convertToDecimal64 (const DecimalImpUtil::ValueType32& input)
{
    return Imp::convertToDecimal64(input);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::convertToDecimal64(const DecimalImpUtil::ValueType128& input)
{
    return Imp::convertToDecimal64(input);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::convertToDecimal128(const DecimalImpUtil::ValueType32& input)
{
    return Imp::convertToDecimal128(input);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::convertToDecimal128(const DecimalImpUtil::ValueType64& input)
{
    return Imp::convertToDecimal128(input);
}

                        // Binary floating point conversion functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::binaryToDecimal32(float value)
{
    return Imp::binaryToDecimal32(value);
}

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::binaryToDecimal32(double value)
{
    return Imp::binaryToDecimal32(value);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::binaryToDecimal64(float value)
{
    return Imp::binaryToDecimal64(value);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::binaryToDecimal64(double value)
{
    return Imp::binaryToDecimal64(value);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::binaryToDecimal128(float value)
{
    return Imp::binaryToDecimal128(value);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::binaryToDecimal128(double value)
{
    return Imp::binaryToDecimal128(value);
}

                        // makeDecimalRaw Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::makeDecimalRaw32(int significand, int exponent)
{
    BSLS_ASSERT(-101 <= exponent);
    BSLS_ASSERT(        exponent <= 90);
    BSLS_ASSERT(bsl::max(significand, -significand) <= 9999999);
    return Imp::makeDecimalRaw32(significand, exponent);
}


inline
DecimalImpUtil::ValueType64
DecimalImpUtil::makeDecimalRaw64(unsigned long long significand, int exponent)
{
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);
    BSLS_ASSERT(significand <= 9999999999999999LL);

    return Imp::makeDecimalRaw64(significand, exponent);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::makeDecimalRaw64(long long significand, int exponent)
{
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);
    BSLS_ASSERT(std::max(significand, -significand) <= 9999999999999999LL);

    return Imp::makeDecimalRaw64(significand, exponent);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::makeDecimalRaw64(unsigned int significand, int exponent)
{
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);

    return Imp::makeDecimalRaw64(significand, exponent);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::makeDecimalRaw64(int significand, int exponent)
{
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);
    return Imp::makeDecimalRaw64(significand, exponent);
}


inline
DecimalImpUtil::ValueType128
DecimalImpUtil::makeDecimalRaw128(unsigned long long significand, int exponent)
{
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);

    return Imp::makeDecimalRaw128(significand, exponent);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::makeDecimalRaw128(long long significand, int exponent)
{
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);

    return Imp::makeDecimalRaw128(significand, exponent);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::makeDecimalRaw128(unsigned int significand, int exponent)
{
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);

    return Imp::makeDecimalRaw128(significand, exponent);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::makeDecimalRaw128(int significand, int exponent)
{
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);

    return Imp::makeDecimalRaw128(significand, exponent);
}

                        // IEEE Scale B Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::scaleB(DecimalImpUtil::ValueType32 value, int exponent)
{
    ValueType32 result;
    _IDEC_flags flags(0);
    result.d_raw = __bid32_scalbn(value.d_raw, exponent, &flags);
    if (BID_INVALID_EXCEPTION     & flags) {
        errno = EDOM;
    }
    if (BID_OVERFLOW_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return result;
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::scaleB(DecimalImpUtil::ValueType64 value, int exponent)
{
    ValueType64 result;
    _IDEC_flags flags(0);
    result.d_raw = __bid64_scalbn(value.d_raw, exponent, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_OVERFLOW_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return result;
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::scaleB(DecimalImpUtil::ValueType128 value, int exponent)
{
    ValueType128 result;
    _IDEC_flags flags(0);
    result.d_raw = __bid128_scalbn(value.d_raw, exponent, &flags);
    if (BID_INVALID_EXCEPTION & flags) {
        errno = EDOM;
    }
    if (BID_OVERFLOW_EXCEPTION & flags) {
        errno = ERANGE;
    }
    return result;
}
                        // Parsing functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::parse32(const char *input)
{
    return Imp::parse32(input);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::parse64(const char *input)
{
    return Imp::parse64(input);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::parse128(const char *input)
{
    return Imp::parse128(input);
}

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::parse32(const char *input, unsigned int *status)
{
    BSLS_ASSERT(0 == *status);
    return Imp::parse32(input, status);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::parse64(const char *input, unsigned int *status)
{
    BSLS_ASSERT(0 == *status);
    return Imp::parse64(input, status);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::parse128(const char *input, unsigned int *status)
{
    BSLS_ASSERT(0 == *status);
    return Imp::parse128(input, status);
}

                        // Densely Packed Conversion Functions
inline
DecimalImpUtil::ValueType32
DecimalImpUtil::convertDPDtoBID(DecimalStorage::Type32 dpd)
{
    return Imp::convertDPDtoBID(dpd);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::convertDPDtoBID(DecimalStorage::Type64 dpd)
{
    return Imp::convertDPDtoBID(dpd);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::convertDPDtoBID(DecimalStorage::Type128 dpd)
{
    return Imp::convertDPDtoBID(dpd);
}

inline
DecimalStorage::Type32
DecimalImpUtil::convertBIDtoDPD(ValueType32 value)
{
    return Imp::convertBIDtoDPD(value);
}

inline
DecimalStorage::Type64
DecimalImpUtil::convertBIDtoDPD(ValueType64 value)
{
    return Imp::convertBIDtoDPD(value);
}

inline
DecimalStorage::Type128
DecimalImpUtil::convertBIDtoDPD(ValueType128 value)
{
    return Imp::convertBIDtoDPD(value);
}
                        // Binary Integral Conversion Functions

inline
DecimalImpUtil::ValueType32
DecimalImpUtil::convertFromBID(DecimalStorage::Type32 bid)
{
    return Imp::convertFromBID(bid);
}

inline
DecimalImpUtil::ValueType64
DecimalImpUtil::convertFromBID(DecimalStorage::Type64 bid)
{
    return Imp::convertFromBID(bid);
}

inline
DecimalImpUtil::ValueType128
DecimalImpUtil::convertFromBID(DecimalStorage::Type128 bid)
{
    return Imp::convertFromBID(bid);
}

inline
DecimalStorage::Type32
DecimalImpUtil::convertToBID(ValueType32 value)
{
    return Imp::convertToBID(value);
}

inline
DecimalStorage::Type64
DecimalImpUtil::convertToBID(ValueType64 value)
{
    return Imp::convertToBID(value);
}

inline
DecimalStorage::Type128
DecimalImpUtil::convertToBID(ValueType128 value)
{
    return Imp::convertToBID(value);
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2014 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
