// bdldfp_decimalutil.h                                               -*-C++-*-
#ifndef INCLUDED_BDLDFP_DECIMALUTIL
#define INCLUDED_BDLDFP_DECIMALUTIL

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

//@PURPOSE: Provide utilities dealing with floating point decimal objects.
//
//@CLASSES:
//  bdldfp::DecimalUtil: decimal floating point utility functions.
//
//@MACROS:
//  FP_SUBNORMAL: subnormal floating-point classification identifier constant
//  FP_NORMAL:    normal floating-point classification identifier constant
//  FP_ZERO:      zero floating-point classification identifier constant
//  FP_INFINITE:  infinity floating-point classification identifier constant
//  FP_NAN:       NaN floating-point classification identifier constant
//
// Note that these macros may *not* be defined in this header.  They are C99
// standard macros and this component defines them only for those platforms
// that have failed to implement C99 (such as Microsoft).
//
//@SEE_ALSO: bdldfp_decimal, bdldfp_decimalplatform
//
//@DESCRIPTION: The 'bdldfp::DecimalUtil' component provides utility functions
// for the decimal floating-point types defined in 'bdldfp_decimal':
//
//: o 'FP_XXX', C99 standard floating-point classification macros
//:
//: o the 'makeDecimal' functions building a decimal floating-point value out
//:   of a coefficient and exponent.
//:
//: o the 'parseDecimal' functions that convert text to decimal value.
//:
//: o 'fma', 'fabs', 'ceil', 'floor', 'trunc', 'round' - math functions
//:
//: o 'classify' and the 'isXxxx' floating-point value classification functions
//
// The 'FP_XXX' C99 floating-point classification macros may also be provided
// by this header for platforms where C99 support is still not provided.
//
///Usage
///-----
// This section shows the intended use of this component.
//
///Example 1: Building Decimals From Integer Parts
///- - - - - - - - - - - - - - - - - - - - - - - -
// Floating-point numbers are built from a sign, a significand and an exponent.
// All those 3 are integers (of various sizes), therefore it is possible to
// build decimals from integers:
//..
//  long long coefficient = 42; // Yet another name for significand
//  int exponent          = -1;
//
//  Decimal32  d32  = makeDecimal32( coefficient, exponent);
//  Decimal64  d64  = makeDecimal64( coefficient, exponent);
//  Decimal128 d128 = makeDecimal128(coefficient, exponent);
//
//  assert(BDLDFP_DECIMAL_DF(4.2) == d32);
//  assert(BDLDFP_DECIMAL_DD(4.2) == d64);
//  assert(BDLDFP_DECIMAL_DL(4.2) == d128);
//..

// TODO TBD Priority description:
//
// 1 - these are already implemented so you should not see TBD/TODO for them
// E - implement when the thread-local Environment/Context is implemented
// 2 - implement as second priority (most probably after the 'E')
// N - Do not implement unless explicitly requested

#include <bdlscm_version.h>

#include <bdldfp_decimal.h>
#include <bdldfp_decimalformatconfig.h>
#include <bdldfp_decimalimputil_inteldfp.h>
#include <bdldfp_decimalplatform.h>
#include <bdldfp_uint128.h>

#include <bsls_assert.h>
#include <bsls_libraryfeatures.h>
#include <bsls_platform.h>
#include <bsls_types.h>

#include <bsl_optional.h>
#include <bsl_string.h>

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
#include <memory_resource>  // 'std::pmr::polymorphic_allocator'
#endif  // BSLS_LIBRARYFEATURES_HAS_CPP17_PMR

#include <string>           // 'std::string', 'std::pmr::string'

namespace BloombergLP {
namespace bdldfp {
                            // =================
                            // class DecimalUtil
                            // =================

struct DecimalUtil {
    // This utility 'struct' provides a namespace for functions using the
    // decimal floating point types defined in the 'bdldfp_decimal' package.

    // CLASS METHODS

                            // Creators functions

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

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

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

    static Decimal64 makeDecimal64(int                significand,
                                   int                exponent);
    static Decimal64 makeDecimal64(unsigned int       significand,
                                   int                exponent);
    static Decimal64 makeDecimal64(long long          significand,
                                   int                exponent);
    static Decimal64 makeDecimal64(unsigned long long significand,
                                   int                exponent);
        // Return a 'DecimalNN' 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 int parseDecimal32(Decimal32 *out, const char *str);
    static int parseDecimal64(Decimal64 *out, const char *str);
    static int parseDecimal128(Decimal128 *out, const char *str);
    template <class STRING_TYPE>
    static int parseDecimal32(Decimal32 *out, const STRING_TYPE& str);
    template <class STRING_TYPE>
    static int parseDecimal64(Decimal64 *out, const STRING_TYPE& str);
    template <class STRING_TYPE>
    static int parseDecimal128(Decimal128 *out, const STRING_TYPE& str);
        // Load into the specified 'out' the decimal floating point number
        // described by the specified 'str'; return zero if the conversion was
        // successful and non-zero otherwise.  The value of 'out' is
        // unspecified if the function returns a non-zero value.  The
        // parameterized 'STRING_TYPE' must be one of 'bsl::string',
        // 'std::string', 'std::pmr::string' (if supported), or
        // 'bslstl::StringRef'.

    static int parseDecimal32Exact(Decimal32 *out, const char *str);
    static int parseDecimal64Exact(Decimal64 *out, const char *str);
    static int parseDecimal128Exact(Decimal128 *out, const char *str);
    template <class STRING_TYPE>
    static int parseDecimal32Exact(Decimal32 *out, const STRING_TYPE& str);
    template <class STRING_TYPE>
    static int parseDecimal64Exact(Decimal64 *out, const STRING_TYPE& str);
    template <class STRING_TYPE>
    static int parseDecimal128Exact(Decimal128 *out, const STRING_TYPE& str);
        // Load into the specified 'out' the decimal floating point number
        // described by the specified 'str'.  Return 0 if 'out' is an exact
        // representation of 'str', a positive value if 'str' is an
        // approximation of 'str' (i.e., 'str' could not be represented
        // exactly), and a negative value if 'str' could not be parsed.  The
        // value of 'out' is unspecified if the function returns a negative
        // value.  The parameterized 'STRING_TYPE' must be one of
        // 'bsl::string', 'std::string', 'std::pmr::string' (if supported), or
        // 'bslstl::StringRef'.

    // math

    static Decimal32  copySign(Decimal32  x, Decimal32  y);
    static Decimal64  copySign(Decimal64  x, Decimal64  y);
    static Decimal128 copySign(Decimal128 x, Decimal128 y);
        // 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 Decimal32  exp(Decimal32  x);
    static Decimal64  exp(Decimal64  x);
    static Decimal128 exp(Decimal128 x);
        // Return 'e' (Euler's number, 2.7182818) raised to the specified power
        // 'x'.
        //
        // Special value handling:
        //: o If 'x' is +/-0, 1 is returned.
        //: o If 'x' is negative infinity, +0 is returned.
        //: o If 'x' is +infinity, +infinity is returned.
        //: o If 'x' is quiet NaN, quiet NaN is returned.
        //: o If 'x' is signaling NaN, quiet NaN is returned and the value of
        //:   the macro 'EDOM' is stored into 'errno'.
        //: o 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 Decimal32  log(Decimal32  x);
    static Decimal64  log(Decimal64  x);
    static Decimal128 log(Decimal128 x);
        // Return the natural (base 'e') logarithm of the specified 'x'.
        //
        // Special value handling:
        //: o If 'x' is +/-0, -infinity is returned and the value of the macro
        //:   'ERANGE' is stored into 'errno'.
        //: o If 'x' is 1, +0 is returned.
        //: o If 'x' is negative, quiet NaN is returned and the value of the
        //:   macro 'EDOM' is stored into 'errno'.
        //: o If 'x' is +infinity, +infinity is returned.
        //: o If 'x' is quiet NaN, quiet NaN is returned.
        //: o If 'x' is signaling NaN, quiet NaN is returned and the value of
        //:   the macro 'EDOM' is stored into 'errno'.

    static Decimal32  logB(Decimal32  x);
    static Decimal64  logB(Decimal64  x);
    static Decimal128 logB(Decimal128 x);
        // Return the FLT_RADIX-based logarithm (i.e., base 10) of the absolute
        //  value of the specified 'x'.
        //
        // Special value handling:
        //: o If 'x' is +/-0, -infinity is returned and the value of the macro
        //:   'ERANGE' is stored into 'errno'.
        //: o If 'x' is 1, +0 is returned.
        //: o If 'x' is +/-infinity, +infinity is returned.
        //: o If 'x' is quiet NaN, quiet NaN is returned.
        //: o 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 Decimal32  log10(Decimal32  x);
    static Decimal64  log10(Decimal64  x);
    static Decimal128 log10(Decimal128 x);
        // Return the common (base-10) logarithm of the specified 'x'.
        //
        // Special value handling:
        //: o If 'x' is +/-0, -infinity is returned and the value of the macro
        //:   'ERANGE' is stored into 'errno'.
        //: o If 'x' is 1, +0 is returned.
        //: o If 'x' is negative, quiet NaN is returned and the value of the
        //:   macro 'EDOM' is stored into 'errno'.
        //: o If 'x' is +infinity, +infinity is returned.
        //: o If 'x' is quiet NaN, quiet NaN is returned.
        //: o If 'x' is signaling NaN, NaN is returned and the value of the
        //:   macro 'EDOM' is stored into 'errno'.

    static Decimal32  fmod(Decimal32  x, Decimal32  y);
    static Decimal64  fmod(Decimal64  x, Decimal64  y);
    static Decimal128 fmod(Decimal128 x, Decimal128 y);
        // 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:
        //: o If either argument is quiet NaN, quiet NaN is returned.
        //: o If either argument is signaling NaN, quiet NaN is returned, and
        //:   the value of the macro 'EDOM' is stored into 'errno'.
        //: o If 'x' is +/-infnity and 'y' is not NaN, quiet NaN is returned
        //:   and the value of the macro 'EDOM' is stored into 'errno'.
        //: o If 'x' is +/-0 and 'y' is not zero, +/-0 is returned.
        //: o If 'y' is +/-0, quite NaN is returned and the value of the macro
        //:   'EDOM' is stored into 'errno'.
        //: o If 'x' is finite and 'y' is +/-infnity, 'x' is returned.

    static Decimal32  remainder(Decimal32  x, Decimal32  y);
    static Decimal64  remainder(Decimal64  x, Decimal64  y);
    static Decimal128 remainder(Decimal128 x, Decimal128 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:
        //: o The current rounding mode has no effect.
        //: o If either argument is quiet NaN, quiet NaN is returned.
        //: o If either argument is signaling NaN, quiet NaN is returned, and
        //:   the value of the macro 'EDOM' is stored into 'errno'.
        //: o If 'y' is +/-0, quiet NaN is returned and the value of the macro
        //:   'EDOM' is stored into 'errno'.
        //: o If 'x' is +/-infnity and 'y' is not NaN, quiet NaN is returned
        //:   and the value of the macro 'EDOM' is stored into 'errno'.
        //: o If 'x' is finite and 'y' is +/-infnity, 'x' is returned.

    static long int        lrint(Decimal32  x);
    static long int        lrint(Decimal64  x);
    static long int        lrint(Decimal128 x);
    static long long int  llrint(Decimal32  x);
    static long long int  llrint(Decimal64  x);
    static long long int  llrint(Decimal128 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 Decimal32  nextafter( Decimal32  from, Decimal32  to);
    static Decimal64  nextafter( Decimal64  from, Decimal64  to);
    static Decimal128 nextafter( Decimal128 from, Decimal128 to);
    static Decimal32  nexttoward(Decimal32  from, Decimal128 to);
    static Decimal64  nexttoward(Decimal64  from, Decimal128 to);
    static Decimal128 nexttoward(Decimal128 from, Decimal128 to);
        // Return the next representable value of the specified 'from' in the
        // direction of the specified 'to'.
        //
        // Special value handling:
        //: o If 'from' equals 'to', 'to' is returned.
        //: o If either argument is quiet NaN, quiet NaN is returned.
        //: o If either argument is signaling NaN, quiet NaN is returned and
        //:   the value of the macro 'EDOM' is stored into 'errno'.
        //: o If 'from' is finite, but the expected result is an infinity,
        //:   infinity is returned and the value of the macro 'ERANGE' is
        //:   stored into 'errno'.
        //: o If 'from' does not equal 'to' and the result is subnormal or
        //:   zero, the value of the macro 'ERANGE' is stored into 'errno'.

    static Decimal32  pow(Decimal32  base, Decimal32  exp);
    static Decimal64  pow(Decimal64  base, Decimal64  exp);
    static Decimal128 pow(Decimal128 base, Decimal128 exp);
        // Return the value of the specified 'base' raised to the power of the
        // specified 'exp'.
        //
        // Special value handling:
        //: o 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'.
        //: o 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'.
        //: o 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'.
        //: o If either argument is signaling NaN, quiet NaN is returned and
        //:   the value of the macro 'EDOM' is stored into 'errno'.

    static Decimal32  fma(Decimal32  x, Decimal32  y, Decimal32  z);
    static Decimal64  fma(Decimal64  x, Decimal64  y, Decimal64  z);
    static Decimal128 fma(Decimal128 x, Decimal128 y, Decimal128 z);
        // 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:
        //: o If 'x' or 'y' are quiet NaN, quiet NaN is returned.
        //: o If any argument is signaling NaN, quiet NaN is returned and the
        //:   value of the macro 'EDOM' is stored into 'errno'.
        //: o If 'x*y' is an exact infinity and 'z' is an infinity with the
        //:   opposite sign, quiet NaN is returned and the value of the macro
        //:   'EDOM' is stored into 'errno'.
        //: o 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'.
        //: o 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.

                       // Selecting, converting functions

    static Decimal32  fabs(Decimal32  value);
    static Decimal64  fabs(Decimal64  value);
    static Decimal128 fabs(Decimal128 value);
        // Return the absolute value of the specified 'x'.
        //
        // Special value handling:
        //: o if 'x' is NaN (either signaling or quiet), quiet NaN is returned.
        //: o if 'x' is +/-infinity or +/-0, it is returned unmodified.

    static Decimal32  sqrt(Decimal32  x);
    static Decimal64  sqrt(Decimal64  x);
    static Decimal128 sqrt(Decimal128 x);
        // Return the square root of the specified 'x'.
        //
        // Special value handling:
        //: o If 'x' is NaN, NaN is returned.
        //: o If 'x' is less than -0, NaN is returned and the value of the
        //:   macro 'EDOM' is stored into 'errno'.
        //: o If 'x' is +/-infinity or +/-0, it is returned unmodified.

                               // classification

    // Names are camelCase so they do not collide with macros of 'math.h'.

    static int classify(Decimal32  x);
    static int classify(Decimal64  x);
    static int classify(Decimal128 x);
        // Return the integer value that respresents the floating point
        // classification of the specified 'x' value as follows:
        //
        //: o if 'x' is NaN, return FP_NAN;
        //: o otherwise if 'x' is positive or negative infinity, return
        //:   'FP_INFINITE';
        //: o otherwise if 'x' is a subnormal value, return 'FP_SUBNORMAL'
        //: o otherwise if 'x' is a zero value, return 'FP_ZERO'
        //: o 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 bool isFinite(Decimal32  x);
    static bool isFinite(Decimal64  x);
    static bool isFinite(Decimal128 x);
        // Return 'true' if the specified 'x' is not an infinity value or NaN
        // and 'false' otherwise.  Note that this is equivalent to
        // 'classify(x) != FP_INFINITE && classify(x) != FP_NAN'.

    static bool isInf(Decimal32  x);
    static bool isInf(Decimal64  x);
    static bool isInf(Decimal128 x);
        // Return 'true' if the specified 'x' is an infinity value and 'false'
        // otherwise.  Note that this is equivalent to
        // 'classify(x) == FP_INFINITE'.

    static bool isNan(Decimal32  x);
    static bool isNan(Decimal64  x);
    static bool isNan(Decimal128 x);
        // Return 'true' if the specified 'x' is NaN and 'false' otherwise.
        // Note that this is equivalent to 'classify(x) == FP_NAN'.

    static bool isNormal(Decimal32  x);
    static bool isNormal(Decimal64  x);
    static bool isNormal(Decimal128 x);
        // Return 'true' if the specified 'x' is a normal value and 'false'
        // otherwise.  Note that this is equivalent to
        // 'classify(x) == FP_NORMAL'.

                           // Comparison functions

    static bool isUnordered(Decimal32  x, Decimal32  y);
    static bool isUnordered(Decimal64  x, Decimal64  y);
    static bool isUnordered(Decimal128 x, Decimal128 y);
        // Return 'true' if either (or both) of the specified 'x' and 'y'
        // arguments is a NaN, or 'false' otherwise.


                             // Rounding functions

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

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

    static Decimal32   round(Decimal32  x);
    static Decimal64   round(Decimal64  x);
    static Decimal128  round(Decimal128 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:
        //: o if 'x' is quiet NaN, quiet NaN is returned.
        //: o If 'x' is signaling NaN, quiet NaN is returned and the value of
        //:   the macro 'EDOM' is stored into 'errno'.
        //: o if 'x' is +/-infinity or +/-0, it is returned unmodified.
        //
        // Examples: 'round(0.5)' ==> 1.0; 'round(-0.5)' ==> -1.0

    static long int   lround(Decimal32  x);
    static long int   lround(Decimal64  x);
    static long int   lround(Decimal128 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:
        //: o if 'x' is NaN (either quiet or signaling), quiet NaN is returned
        //:   and the value of the macro 'EDOM' is stored into 'errno'.
        //: o if 'x' is +/-infinity, quite NaN is returned and the value of the
        //:   macro 'EDOM' is stored into 'errno'.
        //: o 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 Decimal32  round(Decimal32  x, unsigned int precision);
    static Decimal64  round(Decimal64  x, unsigned int precision);
    static Decimal128 round(Decimal128 x, unsigned int precision);
        // Return the specified 'x' value rounded to the specified 'precision'
        // decimal places.  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 Decimal32  trunc(Decimal32  x);
    static Decimal64  trunc(Decimal64  x);
    static Decimal128 trunc(Decimal128 x);
        // Return the nearest integral value that is not greater in absolute
        // value than the specified 'x'.
        //
        // Special value handling:
        //: o if 'x' is quiet NaN, quiet NaN is returned.
        //: o If 'x' is signaling NaN, quiet NaN is returned and the value of
        //:   the macro 'EDOM' is stored into 'errno'.
        //: o if 'x' is +/-infinity or +/-0, it is returned unmodified.
        //
        // Examples: 'trunc(0.5)' ==> 0.0; 'trunc(-0.5)' ==> 0.0

    static Decimal32  trunc(Decimal32  x, unsigned int precision);
    static Decimal64  trunc(Decimal64  x, unsigned int precision);
    static Decimal128 trunc(Decimal128 x, unsigned int precision);
        // Return the specified 'x' value truncated to the specified
        // 'precision' decimal places.  Round towards zero, regardless of the
        // current decimal floating point rounding mode.  If precision of 'x'
        // is less than or equal the 'precision' or 'x' is positive zero,
        // negative zero, NaN, or infinity then return 'x' itself.
        //
        //  Examples: 'trunc(3.14159, 3)' ==> 3.141

                             // Quantum functions

    static Decimal32  multiplyByPowerOf10(Decimal32  value,
                                          int        exponent);
    static Decimal64  multiplyByPowerOf10(Decimal64 value,
                                          int        exponent);
    static Decimal128 multiplyByPowerOf10(Decimal128 value,
                                          int        exponent);
        // 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:
        //: o If 'value' is quiet NaN, quiet NaN is returned.
        //: o If 'value' is signaling NaN, quiet NaN is returned and the value
        //:   of the macro 'EDOM' is stored into 'errno'.
        //: o If 'x' is infinite, then infinity is returned.
        //: o If a range error due to overflow occurs, infinity is returned and
        //: the value of the macro 'ERANGE' is stored into 'errno'.

    static Decimal32  quantize(Decimal32  value, Decimal32  exponent);
    static Decimal64  quantize(Decimal64  value, Decimal64  exponent);
    static Decimal128 quantize(Decimal128 value, Decimal128 exponent);
        // 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 Decimal32  quantize(Decimal32  value, int exponent);
    static Decimal64  quantize(Decimal64  value, int exponent);
    static Decimal128 quantize(Decimal128 value, int 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
        //: o for 'Decimal32'  type:  '-101 <= exponent <=   90'
        //: o for 'Decimal64'  type:  '-398 <= exponent <=  369'
        //: o for 'Decimal128' type: '-6176 <= exponent <= 6111'

    static int quantizeEqual(Decimal32  *x, Decimal32  y, int exponent);
    static int quantizeEqual(Decimal64  *x, Decimal64  y, int exponent);
    static int quantizeEqual(Decimal128 *x, Decimal128 y, 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
        //: o for 'Decimal32'  type:  '-101 <= exponent <=   90'
        //: o for 'Decimal64'  type:  '-398 <= exponent <=  369'
        //: o 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 quantum(Decimal32  value);
    static int quantum(Decimal64  value);
    static int quantum(Decimal128 value);
        // Return an integer equal to the exponent field in the specified
        // 'value'.  Each decimal floating point number is a representation of
        // the ideal form 's * (10 ** e)', where 's' is significand and 'e' is
        // exponent.  This function returns that exponent value.  The behavior
        // is undefined if 'value' is NaN or 'value' is infinity.

    static bool sameQuantum(Decimal32  x, Decimal32  y);
    static bool sameQuantum(Decimal64  x, Decimal64  y);
    static bool sameQuantum(Decimal128 x, Decimal128 y);
        // 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.

                             // Decompose functions

    static int decompose(int                 *sign,
                         unsigned  int       *significand,
                         int                 *exponent,
                         Decimal32            value);
    static int decompose(int                 *sign,
                         bsls::Types::Uint64 *significand,
                         int                 *exponent,
                         Decimal64            value);
    static int decompose(int                 *sign,
                         Uint128             *significand,
                         int                 *exponent,
                         Decimal128           value);
        // 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:
        //
        //: o if 'value' is NaN, return FP_NAN;
        //: o if 'value' is infinity, return 'FP_INFINITE';
        //: o if 'value' is a subnormal value, return 'FP_SUBNORMAL';
        //: o if 'value' is a zero value, return 'FP_ZERO';
        //: o 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').

                         // Format functions

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

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

    static
    int format(char                      *buffer,
               int                        length,
               Decimal128                 value,
               const DecimalFormatConfig& cfg = DecimalFormatConfig());
        // Format the specified 'value', placing 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.  Optionally specify a 'cfg',
        // indicating formatting parameters.  If 'cfg' is not specified, then
        // default configuration instance, indicating scientific notation style
        // with a precision sufficient to produce all available digits is used.
        // See the Attributes section under @DESCRIPTION in the component-level
        // documentation for 'bdldfp::DecimalFormatConfig' component 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.
};

                       // =============================
                       // class DecimalUtil_CStringUtil
                       // =============================

struct DecimalUtil_CStringUtil {
    // This component-private utility 'struct' provides a namespace for the
    // 'flatten' overload set intended to be used in concert with an overload
    // set consisting of a function template with a deduced argument and an
    // non-template overload accepting a 'const char *'.  The actual
    // implementation of the functionality would be in the 'const char *'
    // overload whereas the purpose of the function template is to invoke the
    // 'const char *' overload with a null-terminated string.
    //
    // The function template achieves null-termination by recursively calling
    // the function and supplying it with the result of 'flatten' invoked on
    // the deduced argument.  This 'flatten' invocation will call 'c_str()' on
    // various supported 'string' types, will produce a temporary 'bsl::string'
    // for possibly non-null-terminated 'bslstl::StringRef', and will result in
    // a 'BSLMF_ASSERT' for any unsupported type.  Calling the function with
    // the temporary 'bsl::string' produced from 'bslstl::StringRef' will
    // result in a second invocation of 'flatten', this time producing
    // 'const char *', and finally calling the function with a null-terminated
    // string.
    //
    // Note that the 'bslstl::StringRef' overload for 'flatten' is provided for
    // backwards compatibility.  Without it, the 'bsl::string' and
    // 'std::string' overloads would be ambiguous.  In new code, it is
    // preferable to not provide 'bslstl::StringRef' overload in a similar
    // facility and require the clients to explicitly state the string type in
    // their code, making a potential allocation obvious.  The
    // 'bsl::string_view' overload is not provided for the same reason.

    // CLASS METHODS

    static const char *flatten(const char *cString);
    static const char *flatten(char *cString);
        // Return the specified 'cString'.

    static const char *flatten(const bsl::string& string);
    static const char *flatten(const std::string& string);
#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
    static const char *flatten(const std::pmr::string& string);
#endif
        // Return the result of invoking 'c_str()' on the specified 'string'.

    static bsl::string flatten(const bslstl::StringRef& stringRef);
        // Return a temporary 'bsl::string' constructed from the specified
        // 'stringRef'.

    template <class TYPE>
    static const char *flatten(const TYPE&);
        // Produce a compile-time error informing the caller that the
        // parameterized 'TYPE' is not supported as the parameter for the call.
};

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

                             // -----------------
                             // class DecimalUtil
                             // -----------------

// CLASS METHODS
inline
Decimal32 DecimalUtil::makeDecimalRaw32(int significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw32(significand, exponent);
}
inline
Decimal64 DecimalUtil::makeDecimalRaw64(int significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw64(significand, exponent);
}
inline
Decimal64 DecimalUtil::makeDecimalRaw64(unsigned int significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw64(significand, exponent);
}
inline
Decimal64 DecimalUtil::makeDecimalRaw64(long long significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw64(significand, exponent);
}
inline
Decimal64
DecimalUtil::makeDecimalRaw64(unsigned long long significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw64(significand, exponent);
}
inline
Decimal128 DecimalUtil::makeDecimalRaw128(int significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw128(significand, exponent);
}
inline
Decimal128 DecimalUtil::makeDecimalRaw128(unsigned int significand,
                                          int          exponent)
{
    return DecimalImpUtil::makeDecimalRaw128(significand, exponent);
}
inline
Decimal128 DecimalUtil::makeDecimalRaw128(long long significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw128(significand, exponent);
}
inline
Decimal128
DecimalUtil::makeDecimalRaw128(unsigned long long significand, int exponent)
{
    return DecimalImpUtil::makeDecimalRaw128(significand, exponent);
}

inline
Decimal64 DecimalUtil::makeDecimal64(int significand, int exponent)
{
    return DecimalImpUtil::makeDecimal64(significand, exponent);
}
inline
Decimal64 DecimalUtil::makeDecimal64(unsigned int significand, int exponent)
{
    return DecimalImpUtil::makeDecimal64(significand, exponent);
}
inline
Decimal64 DecimalUtil::makeDecimal64(long long significand, int exponent)
{
    return DecimalImpUtil::makeDecimal64(significand, exponent);
}
inline
Decimal64 DecimalUtil::makeDecimal64(unsigned long long significand,
                                     int                exponent)
{
    return DecimalImpUtil::makeDecimal64(significand, exponent);
}

template <class STRING_TYPE>
inline
int DecimalUtil::parseDecimal32(Decimal32 *out, const STRING_TYPE& str)
{
    return DecimalUtil::parseDecimal32(out,
                                       DecimalUtil_CStringUtil::flatten(str));
}

template <class STRING_TYPE>
inline
int DecimalUtil::parseDecimal64(Decimal64 *out, const STRING_TYPE& str)
{
    return DecimalUtil::parseDecimal64(out,
                                       DecimalUtil_CStringUtil::flatten(str));
}

template <class STRING_TYPE>
inline
int DecimalUtil::parseDecimal128(Decimal128 *out, const STRING_TYPE& str)
{
    return DecimalUtil::parseDecimal128(out,
                                        DecimalUtil_CStringUtil::flatten(str));
}

template <class STRING_TYPE>
inline
int DecimalUtil::parseDecimal32Exact(Decimal32 *out, const STRING_TYPE& str)
{
    return DecimalUtil::parseDecimal32Exact(
                                        out,
                                        DecimalUtil_CStringUtil::flatten(str));
}

template <class STRING_TYPE>
inline
int DecimalUtil::parseDecimal64Exact(Decimal64 *out, const STRING_TYPE& str)
{
    return DecimalUtil::parseDecimal64Exact(
                                        out,
                                        DecimalUtil_CStringUtil::flatten(str));
}

template <class STRING_TYPE>
inline
int DecimalUtil::parseDecimal128Exact(Decimal128 *out, const STRING_TYPE& str)
{
    return DecimalUtil::parseDecimal128Exact(
                                        out,
                                        DecimalUtil_CStringUtil::flatten(str));
}

                             // Quantum functions

inline
Decimal32 DecimalUtil::multiplyByPowerOf10(Decimal32 value, int exponent)
{
    return bdldfp::DecimalImpUtil::scaleB(*value.data(), exponent);
}

inline
Decimal64 DecimalUtil::multiplyByPowerOf10(Decimal64 value, int exponent)
{
    return bdldfp::DecimalImpUtil::scaleB(*value.data(), exponent);
}

inline
Decimal128 DecimalUtil::multiplyByPowerOf10(Decimal128 value, int exponent)
{
    return bdldfp::DecimalImpUtil::scaleB(*value.data(), exponent);
}

inline
Decimal32 DecimalUtil::quantize(Decimal32 value, Decimal32 exponent)
{
    return DecimalImpUtil::quantize(*value.data(), *exponent.data());
}

inline
Decimal64 DecimalUtil::quantize(Decimal64 value, Decimal64 exponent)
{
    return DecimalImpUtil::quantize(*value.data(), *exponent.data());
}

inline
Decimal128 DecimalUtil::quantize(Decimal128 value, Decimal128 exponent)
{
    return DecimalImpUtil::quantize(*value.data(), *exponent.data());
}

inline
Decimal32 DecimalUtil::quantize(Decimal32 value, int exponent)
{
    BSLS_ASSERT(-101 <= exponent);
    BSLS_ASSERT(        exponent <= 90);
    return DecimalImpUtil::quantize(*value.data(), exponent);
}

inline
Decimal64 DecimalUtil::quantize(Decimal64 value, int exponent)
{
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);
    return DecimalImpUtil::quantize(*value.data(), exponent);
}

inline
Decimal128 DecimalUtil::quantize(Decimal128 value, int exponent)
{
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);
    return DecimalImpUtil::quantize(*value.data(), exponent);
}

inline
int DecimalUtil::quantizeEqual(Decimal32 *x, Decimal32 y, int exponent)
{
    BSLS_ASSERT(x);
    BSLS_ASSERT(-101 <= exponent);
    BSLS_ASSERT(        exponent <= 90);
    return DecimalImpUtil::quantizeEqual(x->data(), *y.data(), exponent);
}

inline
int DecimalUtil::quantizeEqual(Decimal64 *x, Decimal64 y, int exponent)
{
    BSLS_ASSERT(x);
    BSLS_ASSERT(-398 <= exponent);
    BSLS_ASSERT(        exponent <= 369);
    return DecimalImpUtil::quantizeEqual(x->data(), *y.data(), exponent);
}

inline
int DecimalUtil::quantizeEqual(Decimal128 *x, Decimal128 y, int exponent)
{
    BSLS_ASSERT(x);
    BSLS_ASSERT(-6176 <= exponent);
    BSLS_ASSERT(         exponent <= 6111);
    return DecimalImpUtil::quantizeEqual(x->data(), *y.data(), exponent);
}

inline
bool DecimalUtil::sameQuantum(Decimal32 x, Decimal32 y)
{
    return DecimalImpUtil::sameQuantum(*x.data(), *y.data());
}

inline
bool DecimalUtil::sameQuantum(Decimal64 x, Decimal64 y)
{
    return DecimalImpUtil::sameQuantum(*x.data(), *y.data());
}

inline
bool DecimalUtil::sameQuantum(Decimal128 x, Decimal128 y)
{
    return DecimalImpUtil::sameQuantum(*x.data(), *y.data());
}

inline
Decimal32 DecimalUtil::copySign(Decimal32 x, Decimal32 y)
{
    return bdldfp::DecimalImpUtil::copySign(*x.data(), *y.data());
}

inline
Decimal64 DecimalUtil::copySign(Decimal64 x, Decimal64 y)
{
    return bdldfp::DecimalImpUtil::copySign(*x.data(), *y.data());
}

inline
Decimal128 DecimalUtil::copySign(Decimal128 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::copySign(*x.data(), *y.data());
}

inline
Decimal32 DecimalUtil::exp(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::exp(*x.data());
}

inline
Decimal64 DecimalUtil::exp(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::exp(*x.data());
}

inline
Decimal128 DecimalUtil::exp(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::exp(*x.data());
}

inline
Decimal32 DecimalUtil::log(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::log(*x.data());
}

inline
Decimal64 DecimalUtil::log(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::log(*x.data());
}

inline
Decimal128 DecimalUtil::log(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::log(*x.data());
}

inline
Decimal32 DecimalUtil::logB(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::logB(*x.data());
}

inline
Decimal64 DecimalUtil::logB(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::logB(*x.data());
}

inline
Decimal128 DecimalUtil::logB(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::logB(*x.data());
}

inline
Decimal32 DecimalUtil::log10(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::log10(*x.data());
}

inline
Decimal64 DecimalUtil::log10(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::log10(*x.data());
}

inline
Decimal128 DecimalUtil::log10(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::log10(*x.data());
}

inline
Decimal32 DecimalUtil::fmod(Decimal32 x, Decimal32 y)
{
    return bdldfp::DecimalImpUtil::fmod(*x.data(), *y.data());
}

inline
Decimal64 DecimalUtil::fmod(Decimal64 x, Decimal64 y)
{
    return bdldfp::DecimalImpUtil::fmod(*x.data(), *y.data());
}

inline
Decimal128 DecimalUtil::fmod(Decimal128 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::fmod(*x.data(), *y.data());
}

inline
Decimal32 DecimalUtil::remainder(Decimal32 x, Decimal32 y)
{
    return bdldfp::DecimalImpUtil::remainder(*x.data(), *y.data());
}

inline
Decimal64 DecimalUtil::remainder(Decimal64 x, Decimal64 y)
{
    return bdldfp::DecimalImpUtil::remainder(*x.data(), *y.data());
}

inline
Decimal128 DecimalUtil::remainder(Decimal128 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::remainder(*x.data(), *y.data());
}

inline
long int DecimalUtil::lrint(Decimal32  x)
{
    return bdldfp::DecimalImpUtil::lrint(*x.data());
}

inline
long int DecimalUtil::lrint(Decimal64  x)
{
    return bdldfp::DecimalImpUtil::lrint(*x.data());
}

inline
long int DecimalUtil::lrint(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::lrint(*x.data());
}

inline
long long int DecimalUtil::llrint(Decimal32  x)
{
    return bdldfp::DecimalImpUtil::llrint(*x.data());
}

inline
long long int DecimalUtil::llrint(Decimal64  x)
{
    return bdldfp::DecimalImpUtil::llrint(*x.data());
}

inline
long long int DecimalUtil::llrint(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::llrint(*x.data());
}

inline
Decimal32 DecimalUtil::nextafter(Decimal32 x, Decimal32 y)
{
    return bdldfp::DecimalImpUtil::nextafter(*x.data(), *y.data());
}

inline
Decimal64 DecimalUtil::nextafter(Decimal64 x, Decimal64 y)
{
    return bdldfp::DecimalImpUtil::nextafter(*x.data(), *y.data());
}

inline
Decimal128 DecimalUtil::nextafter(Decimal128 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::nextafter(*x.data(), *y.data());
}

inline
Decimal32 DecimalUtil::nexttoward(Decimal32 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::nexttoward(*x.data(), *y.data());
}

inline
Decimal64 DecimalUtil::nexttoward(Decimal64 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::nexttoward(*x.data(), *y.data());
}

inline
Decimal128 DecimalUtil::nexttoward(Decimal128 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::nexttoward(*x.data(), *y.data());
}

inline
Decimal32 DecimalUtil::pow(Decimal32 x, Decimal32 y)
{
    return bdldfp::DecimalImpUtil::pow(*x.data(), *y.data());
}

inline
Decimal64 DecimalUtil::pow(Decimal64 x, Decimal64 y)
{
    return bdldfp::DecimalImpUtil::pow(*x.data(), *y.data());
}

inline
Decimal128 DecimalUtil::pow(Decimal128 x, Decimal128 y)
{
    return bdldfp::DecimalImpUtil::pow(*x.data(), *y.data());
}

inline
Decimal32 DecimalUtil::ceil(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::ceil(*x.data());
}

inline
Decimal64 DecimalUtil::ceil(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::ceil(*x.data());
}

inline
Decimal128 DecimalUtil::ceil(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::ceil(*x.data());
}

inline
Decimal32 DecimalUtil::floor(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::floor(*x.data());
}

inline
Decimal64 DecimalUtil::floor(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::floor(*x.data());
}

inline
Decimal128 DecimalUtil::floor(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::floor(*x.data());
}

inline
Decimal32 DecimalUtil::round(Decimal32  x)
{
    return bdldfp::DecimalImpUtil::round(*x.data());
}

inline
Decimal64 DecimalUtil::round(Decimal64  x)
{
    return bdldfp::DecimalImpUtil::round(*x.data());
}

inline
Decimal128 DecimalUtil::round(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::round(*x.data());
}

inline
long int DecimalUtil::lround(Decimal32  x)
{
    return bdldfp::DecimalImpUtil::lround(*x.data());
}

inline
long int DecimalUtil::lround(Decimal64  x)
{
    return bdldfp::DecimalImpUtil::lround(*x.data());
}

inline
long int DecimalUtil::lround(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::lround(*x.data());
}

inline
Decimal32  DecimalUtil::round(Decimal32  x, unsigned int decimalPlaces)
{
    return bdldfp::DecimalImpUtil::round(*x.data(), decimalPlaces);
}

inline
Decimal64 DecimalUtil::round(Decimal64  x, unsigned int decimalPlaces)
{
    return bdldfp::DecimalImpUtil::round(*x.data(), decimalPlaces);
}

inline
Decimal128 DecimalUtil::round(Decimal128 x, unsigned int decimalPlaces)
{
    return bdldfp::DecimalImpUtil::round(*x.data(), decimalPlaces);
}

inline
Decimal32 DecimalUtil::trunc(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::trunc(*x.data());
}

inline
Decimal64 DecimalUtil::trunc(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::trunc(*x.data());
}

inline
Decimal128 DecimalUtil::trunc(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::trunc(*x.data());
}

inline
Decimal32 DecimalUtil::fma(Decimal32  x, Decimal32  y, Decimal32  z)
{
    return bdldfp::DecimalImpUtil::fma(*x.data(), *y.data(), *z.data());
}

inline
Decimal64 DecimalUtil::fma(Decimal64  x, Decimal64  y, Decimal64  z)
{
    return bdldfp::DecimalImpUtil::fma(*x.data(), *y.data(), *z.data());
}

inline
Decimal128 DecimalUtil::fma(Decimal128 x, Decimal128 y, Decimal128 z)
{
    return bdldfp::DecimalImpUtil::fma(*x.data(), *y.data(), *z.data());
}

inline
Decimal32 DecimalUtil::fabs(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::fabs(*x.data());
}

inline
Decimal64 DecimalUtil::fabs(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::fabs(*x.data());
}

inline
Decimal128 DecimalUtil::fabs(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::fabs(*x.data());
}

inline
Decimal32 DecimalUtil::sqrt(Decimal32 x)
{
    return bdldfp::DecimalImpUtil::sqrt(*x.data());
}

inline
Decimal64 DecimalUtil::sqrt(Decimal64 x)
{
    return bdldfp::DecimalImpUtil::sqrt(*x.data());
}

inline
Decimal128 DecimalUtil::sqrt(Decimal128 x)
{
    return bdldfp::DecimalImpUtil::sqrt(*x.data());
}

                       // -----------------------------
                       // class DecimalUtil_CStringUtil
                       // -----------------------------

// CLASS METHODS
inline
const char *DecimalUtil_CStringUtil::flatten(const char *cString)
{
    return cString;
}

inline
const char *DecimalUtil_CStringUtil::flatten(char *cString)
{
    return cString;
}

inline
const char *DecimalUtil_CStringUtil::flatten(const bsl::string& string)
{
    return string.c_str();
}

inline
const char *DecimalUtil_CStringUtil::flatten(const std::string& string)
{
    return string.c_str();
}

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR
inline
const char *DecimalUtil_CStringUtil::flatten(const std::pmr::string& string)
{
    return string.c_str();
}
#endif

inline
bsl::string DecimalUtil_CStringUtil::flatten(
                                            const bslstl::StringRef& stringRef)
{
    return stringRef;
}

template <class TYPE>
inline
const char *DecimalUtil_CStringUtil::flatten(const TYPE&)
{
    BSLMF_ASSERT(("Unsupported parameter type." && !sizeof(TYPE)));
    return 0;
}

}  // 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 ----------------------------------