// bdldfp_decimalimputil_inteldfp.h                                   -*-C++-*-
#ifndef INCLUDED_BDLDFP_DECIMALIMPUTIL_INTELDFP
#define INCLUDED_BDLDFP_DECIMALIMPUTIL_INTELDFP

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

//@PURPOSE: Provide utility to implement decimal `float`s on the Intel library.
//
//@CLASSES:
//  bdldfp::DecimalImpUtil_IntelDfp: Namespace for Intel decimal FP functions
//
//@SEE_ALSO: bdldfp_decimal, bdldfp_decimalplatform
//
//@DESCRIPTION: This component, `bdldfp::DecimalImpUtil_IntelDfp` is for
// internal use only by the `bdldfp_decimal*` components.  Direct use of any
// names declared in this component by any other code invokes undefined
// behavior.  In other words: this code may change, disappear, break, move
// without notice, and no support whatsoever will ever be provided for it.
// This component provides implementations of core Decimal Floating Point
// functionality using the Intel DFP library.
//
///Usage
///-----
// This section shows the intended use of this component.

#include <bdlscm_version.h>

#include <bdldfp_decimalplatform.h>
#include <bdldfp_decimalstorage.h>

#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
#include <bdldfp_intelimpwrapper.h>

#include <bslmf_assert.h>
#include <bslmf_issame.h>
#include <bsls_assert.h>

#include <bsl_locale.h>
#include <bsl_cstring.h>
#include <bsl_c_errno.h>

namespace BloombergLP {
namespace bdldfp {

                          // ==============================
                          // class DecimalImplUtil_IntelDfp
                          // ==============================

/// This `struct` provides a namespace for implementation functions that
/// work in terms of the underlying C-style decimal floating point
/// implementation, Intel's DFP library.
struct DecimalImpUtil_IntelDfp {

    // TYPES
    struct ValueType32  { BID_UINT32  d_raw; };
    struct ValueType64  { BID_UINT64  d_raw; };
    struct ValueType128 { BID_UINT128 d_raw; };

    enum {
        // Status flag bitmask for numeric operations.

        k_STATUS_INEXACT = BID_INEXACT_EXCEPTION,
        k_STATUS_UNDERFLOW = BID_UNDERFLOW_EXCEPTION,
        k_STATUS_OVERFLOW = BID_OVERFLOW_EXCEPTION
    };

  private:
    // CLASS METHODS

    /// Convert bit flags from the specified `flags` into error codes as
    /// follows and load the result into a prepocessor macro `errno`:
    ///
    /// * flag BID_INVALID_EXCEPTION     => `errno = EDOM`
    /// * flag BID_OVERFLOW_EXCEPTION    => `errno = ERANGE`
    /// * flag BID_UNDERFLOW_EXCEPTION   => `errno = ERANGE`
    /// * flag BID_ZERO_DIVIDE_EXCEPTION => `errno = ERANGE`
    static void setErrno(_IDEC_flags flags);

  public:
    // CLASS METHODS

                        // Integer construction (32-bit)

    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 the 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);

                        // Integer construction (64-bit)

    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 `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);

                        // Integer construction (128-bit)

    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 `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 functions

                        // 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 max value supported by 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 max value supported by 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 max 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 `lhs` has infinity value and `rhs` has a positive
    ///   zero value, return infinity with the sign of `lhs`.
    /// * Otherwise if `lhs` has infinity value and `rhs` has a negative
    ///   zero value, return infinity with the opposite sign as `lhs`.
    /// * Otherwise if dividing the value of `lhs` with the value of `rhs`
    ///   results in an absolute value that is larger than max value
    ///   supported by the return 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` with the value of `rhs`
    ///   results in an absolute value that is smaller than min value
    ///   supported by 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` with
    ///   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);

                        // Negation functions

    /// Return the result of applying the unary - operator to the specified
    /// `value` as described by IEEE-754.  Note that floating-point numbers
    /// have signed zero, therefore this operation is not the same as
    /// `0-value`.
    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 indicated
    /// result type following the conversion rules:
    ///
    /// * 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 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.
    /// * 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 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 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<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);

                        // IEEE Scale B 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.  The result is
    /// unspecified if `value` is NaN or infinity.
    static ValueType32  scaleB(ValueType32  value, int exponent);
    static ValueType64  scaleB(ValueType64  value, int exponent);
    static ValueType128 scaleB(ValueType128 value, int exponent);

                        // Parsing functions

    /// Parse the specified `string` as a 32 bit decimal floating-point
    /// value and return the result.  The parsing is as specified for the
    /// `strtod32` function in section 9.6 of the ISO/EIC TR 24732 C Decimal
    /// Floating-Point Technical Report, except that it is unspecified
    /// whether the NaNs returned are quiet or signaling.  If `string`
    /// represents a value that absolute value exceeds the maximum value or
    /// is less than the smallest value supported by `ValueType32` type then
    /// store the value of the macro `ERANGE` into `errno` and return the
    /// value initialized to infinity or zero respectively with the same
    /// sign as specified in `string`.  The behavior is undefined unless
    /// `input` represents a valid 32 bit decimalfloating-point number in
    /// scientific or fixed notation, and no unrelated characters precede
    /// (not even whitespace) that textual representation and a terminating
    /// nul character immediately follows it.  Note that this method does
    /// not guarantee the behavior of ISO/EIC TR 24732 C when parsing NaN
    /// because the AIX compiler intrinsics return a signaling NaN.
    static ValueType32 parse32 (const char *string);

    /// Parse the specified `string` string as a 64 bit decimal floating-
    /// point value and return the result.  The parsing is as specified for
    /// the `strtod64` function in section 9.6 of the ISO/EIC TR 24732 C
    /// Decimal Floating-Point Technical Report, except that it is
    /// unspecified whether the NaNs returned are quiet or signaling.  If
    /// `string` represents a value that absolute value exceeds the maximum
    /// value or is less than the smallest value supported by `ValueType63`
    /// type then store the value of the macro `ERANGE` into `errno` and
    /// return the value initialized to infinity or zero respectively with
    /// the same sign as specified in `string`.  The behavior is undefined
    /// unless `input` represents a valid 64 bit decimal floating-point
    /// number in scientific or fixed notation, and no unrelated characters
    /// precede (not even whitespace) that textual representation and a
    /// terminating nul character immediately follows it.  Note that this
    /// method does not guarantee the behavior of ISO/EIC TR 24732 C when
    /// parsing NaN because the AIX compiler intrinsics return a signaling
    /// NaN.
    static ValueType64 parse64(const char *string);

    /// Parse the specified `string` string as a 128 bit decimal floating-
    /// point value and return the result.  The parsing is as specified for
    /// the `strtod128` function in section 9.6 of the ISO/EIC TR 24732 C
    /// Decimal Floating-Point Technical Report, except that it is
    /// unspecified whether the NaNs returned are quiet or signaling. If
    /// `string` represents a value that absolute value exceeds the maximum
    /// value or is less than the smallest value supported by `ValueType128`
    /// type then store the value of the macro `ERANGE` into `errno` and
    /// return the value initialized to infinity or zero respectively with
    /// the same sign as specified in `string`.  The behavior is undefined
    /// unless `input` represents a valid 128 bit decimal floating-point
    /// number in scientific or fixed notation, and no unrelated characters
    /// precede (not even whitespace) that textual representation and a
    /// terminating null character immediately follows it.  Note that this
    /// method does not guarantee the behavior of ISO/EIC TR 24732 C when
    /// parsing NaN because the AIX compiler intrinsics return a signaling
    /// NaN.
    static ValueType128 parse128(const char *string);

    static ValueType32 parse32(const char *string, unsigned int *status);
    static ValueType64 parse64(const char *string, unsigned int *status);

    /// Parse the specified `string` string as a decimal floating-point
    /// value and return the result, loading the specified `status` with a
    /// bit mask providing additional status information about the result.
    /// The supplied `*status` must be 0, and may be loaded with a bit mask
    /// of `k_STATUS_INEXACT`, `k_STATUS_UNDERFLOW`, and `k_STATUS_OVERFLOW`
    /// constants indicating wether the conversion from text inexact,
    /// underflowed, or overflowed (or some combination) respectively. The
    /// parsing is as specified for the `strtod128` function in section 9.6
    /// of the ISO/EIC TR 24732 C Decimal Floating-Point Technical Report,
    /// except that it is unspecified whether the NaNs returned are quiet or
    /// signaling. The behavior is undefined unless `input` represents a
    /// valid decimal floating-point number in scientific or fixed notation,
    /// and no unrelated characters precede (not even whitespace) that
    /// textual representation and a terminating null character immediately
    /// follows it.  The behavior is undefined unless `*status` is 0.  Note
    /// that this method does not guarantee the behavior of ISO/EIC TR 24732
    /// C when parsing NaN because the AIX compiler intrinsics return a
    /// signaling NaN.  Also note that the intel decimal floating point
    /// library documents that inexact, underflow, and overflow are the
    /// possible floating point exceptions for this operation.
    static ValueType128 parse128(const char *string, 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 `DenselyPackedDecimalImpUtil::StorageTypeXX` 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);
};

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

                          // -----------------------------
                          // class DecimalImpUtil_IntelDfp
                          // -----------------------------

// CLASS METHODS
inline
void DecimalImpUtil_IntelDfp::setErrno(_IDEC_flags flags)
{
    if (BID_INVALID_EXCEPTION  & flags) {
        errno = EDOM;
    }
    else if (BID_OVERFLOW_EXCEPTION    & flags ||
             BID_UNDERFLOW_EXCEPTION   & flags ||
             BID_ZERO_DIVIDE_EXCEPTION & flags)
    {
        errno = ERANGE;
    }
}

// CLASS METHODS

                        // Integer construction

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::int32ToDecimal32(int value)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_from_int32(value, &flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::int32ToDecimal64(int value)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    retval.d_raw = __bid64_from_int32(value);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::int32ToDecimal128(int value)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    retval.d_raw = __bid128_from_int32(value);
    return retval;
}


inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::uint32ToDecimal32(unsigned int value)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_from_uint32(value, &flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::uint32ToDecimal64(unsigned int value)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    retval.d_raw = __bid64_from_uint32(value);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::uint32ToDecimal128(unsigned int value)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    retval.d_raw = __bid128_from_uint32(value);
    return retval;
}


inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::int64ToDecimal32(long long int value)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_from_int64(value, &flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::int64ToDecimal64(long long int value)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_from_int64(value, &flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::int64ToDecimal128(long long int value)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    retval.d_raw = __bid128_from_int64(value);
    return retval;
}


inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::uint64ToDecimal32(unsigned long long int value)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_from_uint64(value, &flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::uint64ToDecimal64(unsigned long long int value)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_from_uint64(value, &flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::uint64ToDecimal128(unsigned long long int value)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    retval.d_raw = __bid128_from_uint64(value);
    return retval;
}

                        // Arithmetic

                        // Addition Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::add(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                             DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_add(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::add(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                             DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_add(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::add(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                             DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_add(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

                        // Subtraction Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::subtract(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_sub(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::subtract(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_sub(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::subtract(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_sub(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

                        // Multiplication Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::multiply(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_mul(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::multiply(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_mul(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::multiply(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_mul(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

                        // Division Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::divide(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                                DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_div(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::divide(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                                DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_div(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::divide(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                                DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_div(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return retval;
}

                        // Negation Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::negate(DecimalImpUtil_IntelDfp::ValueType32 value)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    retval.d_raw = __bid32_negate(value.d_raw);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::negate(DecimalImpUtil_IntelDfp::ValueType64 value)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    retval.d_raw = __bid64_negate(value.d_raw);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::negate(DecimalImpUtil_IntelDfp::ValueType128 value)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    retval.d_raw = __bid128_negate(value.d_raw);
    return retval;
}

                        // Comparison Functions

                        // Less Than Functions

inline
bool
DecimalImpUtil_IntelDfp::less(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                              DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid32_quiet_less(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::less(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                              DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid64_quiet_less(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::less(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                              DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid128_quiet_less(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

                        // Greater Than Functions

inline
bool
DecimalImpUtil_IntelDfp::greater(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                                 DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    _IDEC_flags flags(0);
    bool res =  __bid32_quiet_greater(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool DecimalImpUtil_IntelDfp::greater(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                                      DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid64_quiet_greater(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::greater(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                                 DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid128_quiet_greater(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

                        // Less Or Equal Functions

inline
bool
DecimalImpUtil_IntelDfp::lessEqual(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                                   DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid32_quiet_less_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::lessEqual(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                                   DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid64_quiet_less_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::lessEqual(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                                   DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid128_quiet_less_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

                        // Greater Or Equal Functions

inline
bool
DecimalImpUtil_IntelDfp::greaterEqual(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                                      DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid32_quiet_greater_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::greaterEqual(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                                      DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid64_quiet_greater_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::greaterEqual(
                                     DecimalImpUtil_IntelDfp::ValueType128 lhs,
                                     DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid128_quiet_greater_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

                        // Equality Functions

inline
bool
DecimalImpUtil_IntelDfp::equal(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                               DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid32_quiet_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::equal(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                               DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid64_quiet_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::equal(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                               DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid128_quiet_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

                        // Inequality Functions

inline
bool
DecimalImpUtil_IntelDfp::notEqual(DecimalImpUtil_IntelDfp::ValueType32 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType32 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid32_quiet_not_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::notEqual(DecimalImpUtil_IntelDfp::ValueType64 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType64 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid64_quiet_not_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

inline
bool
DecimalImpUtil_IntelDfp::notEqual(DecimalImpUtil_IntelDfp::ValueType128 lhs,
                                  DecimalImpUtil_IntelDfp::ValueType128 rhs)
{
    _IDEC_flags flags(0);
    bool res = __bid128_quiet_not_equal(lhs.d_raw, rhs.d_raw, &flags);
    setErrno(flags);
    return res;
}

                        // Inter-type Conversion functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::convertToDecimal32(
                             const DecimalImpUtil_IntelDfp::ValueType64& input)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_to_bid32(input.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::convertToDecimal32(
                            const DecimalImpUtil_IntelDfp::ValueType128& input)
{
    DecimalImpUtil_IntelDfp::ValueType32 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_to_bid32(input.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::convertToDecimal64(
                             const DecimalImpUtil_IntelDfp::ValueType32& input)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_to_bid64(input.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::convertToDecimal64(
                            const DecimalImpUtil_IntelDfp::ValueType128& input)
{
    DecimalImpUtil_IntelDfp::ValueType64 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid128_to_bid64(input.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::convertToDecimal128(
                             const DecimalImpUtil_IntelDfp::ValueType32& input)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid32_to_bid128(input.d_raw, &flags);
    setErrno(flags);
    return retval;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::convertToDecimal128(
                             const DecimalImpUtil_IntelDfp::ValueType64& input)
{
    DecimalImpUtil_IntelDfp::ValueType128 retval;
    _IDEC_flags flags(0);
    retval.d_raw = __bid64_to_bid128(input.d_raw, &flags);
    setErrno(flags);
    return retval;
}

                        // Binary floating point conversion functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::binaryToDecimal32(float value)
{
    ValueType32 result;
    _IDEC_flags flags(0);
    result.d_raw = __binary32_to_bid32(value, &flags);
    setErrno(flags);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::binaryToDecimal32(double value)
{
    ValueType32 result;
    _IDEC_flags flags(0);
    result.d_raw = __binary64_to_bid32(value, &flags);
    setErrno(flags);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::binaryToDecimal64(float value)
{
    ValueType64 result;
    _IDEC_flags flags(0);
    result.d_raw = __binary32_to_bid64(value, &flags);
    setErrno(flags);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::binaryToDecimal64(double value)
{
    ValueType64 result;
    _IDEC_flags flags(0);
    result.d_raw = __binary64_to_bid64(value, &flags);
    setErrno(flags);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::binaryToDecimal128(float value)
{
    ValueType128 result;
    _IDEC_flags flags(0);
    result.d_raw = __binary32_to_bid128(value, &flags);
    setErrno(flags);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::binaryToDecimal128(double value)
{
    ValueType128 result;
    _IDEC_flags flags(0);
    result.d_raw = __binary64_to_bid128(value, &flags);
    setErrno(flags);
    return result;
}

                        // makeDecimalRaw Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::makeDecimalRaw32(int significand,
                                          int exponent)
{
    DecimalImpUtil_IntelDfp::ValueType32 result;
    result = DecimalImpUtil_IntelDfp::int32ToDecimal32(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::makeDecimalRaw64(unsigned long long significand,
                                          int                exponent)
{
    DecimalImpUtil_IntelDfp::ValueType64 result;
    result = DecimalImpUtil_IntelDfp::uint64ToDecimal64(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::makeDecimalRaw64(long long significand,
                                          int       exponent)
{
    DecimalImpUtil_IntelDfp::ValueType64 result;
    result = DecimalImpUtil_IntelDfp::int64ToDecimal64(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::makeDecimalRaw64(unsigned int significand,
                                          int          exponent)
{
    DecimalImpUtil_IntelDfp::ValueType64 result;
    result = DecimalImpUtil_IntelDfp::uint32ToDecimal64(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::makeDecimalRaw64(int significand,
                                          int exponent)
{
    DecimalImpUtil_IntelDfp::ValueType64 result;
    result = DecimalImpUtil_IntelDfp::int32ToDecimal64(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::makeDecimalRaw128(unsigned long long significand,
                                           int                exponent)
{
    DecimalImpUtil_IntelDfp::ValueType128 result;
    result = DecimalImpUtil_IntelDfp::uint64ToDecimal128(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::makeDecimalRaw128(long long significand,
                                           int       exponent)
{
    DecimalImpUtil_IntelDfp::ValueType128 result;
    result = DecimalImpUtil_IntelDfp::int64ToDecimal128(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::makeDecimalRaw128(unsigned int significand,
                                           int          exponent)
{
    DecimalImpUtil_IntelDfp::ValueType128 result;
    result = DecimalImpUtil_IntelDfp::uint32ToDecimal128(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::makeDecimalRaw128(int significand,
                                           int exponent)
{
    DecimalImpUtil_IntelDfp::ValueType128 result;
    result = DecimalImpUtil_IntelDfp::int32ToDecimal128(significand);
    result = DecimalImpUtil_IntelDfp::scaleB(result, exponent);
    return result;
}

                        // IEEE Scale B Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::scaleB(DecimalImpUtil_IntelDfp::ValueType32 value,
                                int                                  exponent)
{
    DecimalImpUtil_IntelDfp::ValueType32 result;
    _IDEC_flags flags(0);
    result.d_raw = __bid32_scalbn(value.d_raw, exponent, &flags);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::scaleB(DecimalImpUtil_IntelDfp::ValueType64 value,
                                int                                  exponent)
{
    DecimalImpUtil_IntelDfp::ValueType64 result;
    _IDEC_flags flags(0);
    result.d_raw = __bid64_scalbn(value.d_raw, exponent, &flags);
    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::scaleB(DecimalImpUtil_IntelDfp::ValueType128 value,
                                int                                   exponent)
{
    DecimalImpUtil_IntelDfp::ValueType128 result;
    _IDEC_flags flags(0);
    result.d_raw = __bid128_scalbn(value.d_raw, exponent, &flags);
    return result;
}

                        // Parsing functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::parse32(const char *string)
{
    DecimalImpUtil_IntelDfp::ValueType32 result;
    _IDEC_flags flags(0);
    // NOTE: It is probably safe to convert from a 'const char *' to a 'char *'
    // because the __bid* interfaces are C interfaces.
    result.d_raw = __bid32_from_string(const_cast<char *>(string), &flags);

    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }

    return result;
}


inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::parse64(const char *string)
{
    DecimalImpUtil_IntelDfp::ValueType64 result;
    _IDEC_flags flags(0);
    // NOTE: It is probably safe to convert from a 'const char *' to a 'char *'
    // because the __bid* interfaces are C interfaces.
    result.d_raw = __bid64_from_string(const_cast<char *>(string), &flags);

    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }

    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::parse128(const char *string)
{
    DecimalImpUtil_IntelDfp::ValueType128 result;
    _IDEC_flags flags(0);
    // NOTE: It is probably safe to convert from a 'const char *' to a 'char *'
    // because the __bid* interfaces are C interfaces.
    result.d_raw = __bid128_from_string(const_cast<char *>(string), &flags);

    if (BID_OVERFLOW_EXCEPTION  & flags ||
        BID_UNDERFLOW_EXCEPTION & flags)
    {
        errno = ERANGE;
    }

    return result;
}


inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::parse32(const char *string, unsigned int *status)
{
    BSLS_ASSERT(0 == *status);

    DecimalImpUtil_IntelDfp::ValueType32 result;
    BSLMF_ASSERT((bsl::is_same<_IDEC_flags, unsigned int>::value));

    // NOTE: It is probably safe to convert from a 'const char *' to a 'char *'
    // because the __bid* interfaces are C interfaces.  Also note that inexact,
    // underflow, and overflow are the only dcoumented floating point
    // exceptions for this function.

    result.d_raw = __bid32_from_string(const_cast<char *>(string), status);

    return result;
}


inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::parse64(const char *string, unsigned int *status)
{
    BSLS_ASSERT(0 == *status);

    DecimalImpUtil_IntelDfp::ValueType64 result;

    BSLMF_ASSERT((bsl::is_same<_IDEC_flags, unsigned int>::value));

    // NOTE: It is probably safe to convert from a 'const char *' to a 'char *'
    // because the __bid* interfaces are C interfaces.  Also note that inexact,
    // underflow, and overflow are the only dcoumented floating point
    // exceptions for this function.

    result.d_raw = __bid64_from_string(const_cast<char *>(string), status);

    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::parse128(const char *string, unsigned int *status)
{
    BSLS_ASSERT(0 == *status);

    DecimalImpUtil_IntelDfp::ValueType128 result;
    BSLMF_ASSERT((bsl::is_same<_IDEC_flags, unsigned int>::value));

    // NOTE: It is probably safe to convert from a 'const char *' to a 'char *'
    // because the __bid* interfaces are C interfaces.  Also note that inexact,
    // underflow, and overflow are the only dcoumented floating point
    // exceptions for this function.

    result.d_raw = __bid128_from_string(const_cast<char *>(string), status);

    return result;
}

                        // Densely Packed Conversion Functions
inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::convertDPDtoBID(DecimalStorage::Type32 dpd)
{
    ValueType32 value;
    bsl::memcpy(&value, &dpd, sizeof(value));

    ValueType32 result;
    result.d_raw = __bid_dpd_to_bid32(value.d_raw);

    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::convertDPDtoBID(DecimalStorage::Type64 dpd)
{
    ValueType64 value;
    bsl::memcpy(&value, &dpd, sizeof(value));

    ValueType64 result;
    result.d_raw = __bid_dpd_to_bid64(value.d_raw);

    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::convertDPDtoBID(DecimalStorage::Type128 dpd)
{
    ValueType128 value;
    bsl::memcpy(&value, &dpd, sizeof(value));

    ValueType128 result;
    result.d_raw = __bid_dpd_to_bid128(value.d_raw);

    return result;
}

inline
DecimalStorage::Type32
DecimalImpUtil_IntelDfp::convertBIDtoDPD(
                                    DecimalImpUtil_IntelDfp::ValueType32 value)
{
    ValueType32 result;
    result.d_raw = __bid_to_dpd32(value.d_raw);

    DecimalStorage::Type32 dpd;
    bsl::memcpy(&dpd, &result, sizeof(dpd));

    return dpd;
}

inline
DecimalStorage::Type64
DecimalImpUtil_IntelDfp::convertBIDtoDPD(
                                    DecimalImpUtil_IntelDfp::ValueType64 value)
{
    ValueType64 result;
    result.d_raw = __bid_to_dpd64(value.d_raw);

    DecimalStorage::Type64 dpd;
    bsl::memcpy(&dpd, &result, sizeof(dpd));

    return dpd;
}

inline
DecimalStorage::Type128
DecimalImpUtil_IntelDfp::convertBIDtoDPD(
                                   DecimalImpUtil_IntelDfp::ValueType128 value)
{
    ValueType128 result;
    result.d_raw = __bid_to_dpd128(value.d_raw);

    DecimalStorage::Type128 dpd;
    bsl::memcpy(&dpd, &result, sizeof(dpd));

    return dpd;
}
                        // Binary Integral Conversion Functions

inline
DecimalImpUtil_IntelDfp::ValueType32
DecimalImpUtil_IntelDfp::convertFromBID(DecimalStorage::Type32 bid)
{
    ValueType32 result;
    bsl::memcpy(&result, &bid, sizeof(result));

    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType64
DecimalImpUtil_IntelDfp::convertFromBID(DecimalStorage::Type64 bid)
{
    ValueType64 result;
    bsl::memcpy(&result, &bid, sizeof(result));

    return result;
}

inline
DecimalImpUtil_IntelDfp::ValueType128
DecimalImpUtil_IntelDfp::convertFromBID(DecimalStorage::Type128 bid)
{
    ValueType128 result;
    bsl::memcpy(&result, &bid, sizeof(result));

    return result;
}

inline
DecimalStorage::Type32
DecimalImpUtil_IntelDfp::convertToBID(
                                    DecimalImpUtil_IntelDfp::ValueType32 value)
{
    DecimalStorage::Type32 bid;
    bsl::memcpy(&bid, &value, sizeof(bid));

    return bid;
}

inline
DecimalStorage::Type64
DecimalImpUtil_IntelDfp::convertToBID(
                                    DecimalImpUtil_IntelDfp::ValueType64 value)
{
    DecimalStorage::Type64 bid;
    bsl::memcpy(&bid, &value, sizeof(bid));

    return bid;
}

inline
DecimalStorage::Type128
DecimalImpUtil_IntelDfp::convertToBID(
                                   DecimalImpUtil_IntelDfp::ValueType128 value)
{
    DecimalStorage::Type128 bid;
    bsl::memcpy(&bid, &value, sizeof(bid));

    return bid;
}

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

#endif  // #ifdef BDLDFP_DECIMALPLATFORM_INTELDFP

#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 ----------------------------------
