// bdldfp_decimal.h                                                   -*-C++-*-
#ifndef INCLUDED_BDLDFP_DECIMAL
#define INCLUDED_BDLDFP_DECIMAL

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

//@PURPOSE: Provide IEEE-754 decimal floating-point types.
//
//@CLASSES:
//  bdldfp::Decimal32:   32bit IEEE-754 decimal floating-point type
//  bdldfp::Decimal64:   64bit IEEE-754 decimal floating-point type
//  bdldfp::Decimal128: 128bit IEEE-754 decimal floating-point type
//  bdldfp::DecimalNumGet: Stream Input Facet
//  bdldfp::DecimalNumPut: Stream Output Facet
//
//@MACROS:
//  BDLDFP_DECIMAL_DF: Portable Decimal32 literal macro
//  BDLDFP_DECIMAL_DD: Portable Decimal64 literal macro
//  BDLDFP_DECIMAL_DL: Portable Decimal128 literal macro
//
//@SEE_ALSO: bdldfp_decimalutil, bdldfp_decimalconvertutil,
//           bdldfp_decimalplatform
//
//@DESCRIPTION: This component provides classes that implement decimal
// floating-point types that conform in layout, encoding and operations to the
// IEEE-754 2008 standard.  This component also provides two facets to support
// standard C++ streaming operators as specified by ISO/IEC TR-24733:2009.
// These classes are 'bdldfp::Decimal32' for 32-bit Decimal floating point
// numbers, 'bdldfp::Decimal64' for 64-bit Decimal floating point numbers, and
// 'bdldfp::Decimal128' for 128-bit decimal floating point numbers.
//
// Decimal encoded floating-point numbers are important where exact
// representation of decimal fractions is required, such as in financial
// transactions.  Binary encoded floating-point numbers are generally optimal
// for complex computation but cannot exactly represent commonly encountered
// numbers such as 0.1, 0.2, and 0.99.
//
// NOTE: Interconversion between binary and decimal floating-point values is
// fraught with misunderstanding and must be done carefully and with intent,
// taking into account the provenance of the data.  See the discussion on
// conversion below and in the 'bdldfp_decimalconvertutil' component.
//
// The BDE decimal floating-point system has been designed from the ground up
// to be portable and support writing portable decimal floating-point user
// code, even for systems that do not have compiler or native library support
// for it; while taking advantage of native support (such as ISO/IEC TR
// 24732 - C99 decimal TR) when available.
//
// 'bdldfp::DecimalNumGet' and 'bdldfp::DecimalNumPut' are IO stream facets.
//
///Floating-Point Primer
///---------------------
// There are several ways of represent numbers when using digital computers.
// The simplest would be an integer format, however such a format severely
// limits the range of numbers that can be represented; and it cannot represent
// real (non-integer) numbers directly at all.  Integers might be used to
// represent real numbers of limited precision by treating them as a multiple
// of the real value being represented; these are often known as fixed-point
// numbers.  However general computations require higher precision and a larger
// range than integer and fixed point types are able to efficiently provide.
// Floating-point numbers provide what integers cannot.  They are able to
// represent a large range of real values (although not precisely) while using
// a fixed (and reasonable) amount of storage.
//
// Floating-point numbers are constructed from a set of significant digits of a
// radix on a sliding scale, where their position is determined by an exponent
// over the same radix.  For example let's see some 32bit decimal (radix 10)
// floating-point numbers that have maximum 7 significant digits (significand):
//..
//   Significand | Exponent | Value        |
//  -------------+----------+--------------+  In the Value column you may
//       1234567 |        0 |   1234567.0  |  observer how the decimal point
//       1234567 |        1 |  12345670.0  |  is "floating" about the digits
//       1234567 |        2 | 123456700.0  |  of the significand.
//       1234567 |       -1 |    123456.7  |
//       1234567 |       -2 |     12345.67 |
//..
// Floating-point numbers are standardized by IEEE-754 2008, in two major
// flavors: binary and decimal.  Binary floating-point numbers are supported by
// most computer systems in the forms of the 'float', 'double' and
// 'long double' fundamental data types.  While they are not required to be
// binary that is almost always the choice on modern binary computer
// architectures.
//
///Floating-Point Peculiarities
/// - - - - - - - - - - - - - -
// Floating-point approximation of real numbers creates a deliberate illusion.
// While it looks like we are working with real numbers, floating-point
// encodings are not able to represent real numbers precisely since they have a
// restricted number of digits in the significand.  In fact, a 64 bit
// floating-point type can represent fewer distinct values than a 64 bit binary
// integer.  Yet, because floating-point encodings can represent numbers over a
// much larger range, including extremely small (fractional) numbers, they are
// useful in practice.
//
// Floating-point peculiarities may be split into three categories: those that
// are due to the (binary) radix/base, those that are inherent properties of
// any floating-point representation and finally those that are introduced by
// the IEEE-754 2008 standard.  Decimal floating-point addresses the first set
// of surprises only; so users still need to be aware of the rest.
//
//: 1 Floating-point types cannot exactly represent every number in their
//:   range.  The consequences are surprising and unexpected for the newcomer.
//:   For example: when using binary floating-point numbers, the following
//:   expression is typically *false*: '0.1 + 0.2 == 0.3'.  The problem is not
//:   limited to binary floating-point.  Decimal floating-point cannot
//:   represent the value of one third exactly.
//:
//: 2 Unlike with real numbers, the order of operations on floating-point
//:   numbers is significant, due to accumulation of round off errors.
//:   Therefore floating-point arithmetic is neither commutative nor
//:   transitive.  E.g., 2e-30 + 1e30 - 1e-30 - 1e30 will typically produce 0
//:   (unless your significand can hold 60 decimal digits).  Alternatively,
//:   1e30 - 1e30 + 2e-30 - 1e-30 will typically produce 1e-30.
//:
//: 3 IEEE floating-point types can have special values: negative zero,
//:   negative and positive infinity; and they can be NaN (Not a Number, in two
//:   variants: quiet or signaling).  A NaN (any variant) is never equal to
//:   anything else - including NaN or itself!
//:
//: 4 In IEEE floating-point there are at least two representations of 0, the
//:   positive zero and negative zero.  Consequently unary - operators change
//:   the sign of the value 0; therefore leading to surprising results: if
//:   'f == 0.0' then '0 - f' and '-f' will not result in the same value,
//:   because '0 - f' will be +0.0' while '-f' will be -0.0.
//:
//: 5 Most IEEE floating-point operations (like arithmetic) have implicit input
//:   parameters and output parameters (that do not show up in function
//:   signatures.  The implicit input parameters are called *attributes* by
//:   IEEE while the outputs are called status flags.  The C/C++ programming
//:   language defines a so-called floating-point environment that contains
//:   those attributes and flags ('<fenv.h>' C and '<cfenv>' C++ headers).  To
//:   learn more about the floating point environment read the subsection of
//:   the same title, but first make sure you read the next point as well.
//:
//: 6 IEEE floating-points overloads some very common programming language
//:   terms: *exception*, *signal* and *handler* with IEEE floating-point
//:   specific meanings that are not to be confused with C or C++ or Posix
//:   terms of the same spelling.  Floating-point exceptions are events that
//:   occur when a floating-point operations on the specified operands is
//:   unable to produce a perfect outcome; such as when the result of an
//:   operation is inexact.  When a floating point exception occurs the
//:   (floating-point) - and reporting it is requested by a so-called trap
//:   attribute - the implementation signals the user(*) by invoking a default
//:   or a user-defined handler.  None of the words *exception*, *signal*, and
//:   *handler* used above have nothing to do with C++ exceptions, Posix
//:   signals and the handlers of those.  (To complicate matters more, C and
//:   Posix has decided to implement IEEE floating-point exception reporting as
//:   C/Posix signals - and therefore rendered them mostly useless.)
//:
//: 7 While a 32bit integer is a quite useful type for (integer) calculations,
//:   a 32bit floating-point type has such low accuracy (its significand is so
//:   short) that it is all but useless for calculation.  Such types are called
//:   "interchange formats" by the IEEE standard and should not be used for
//:   calculations.  (Except in special circumstances and by floating-point
//:   experts.  Even a 16 bit binary floating-point type can be useful for an
//:   expert in special circumstances, for example in graphics acceleration
//:   hardware.)
//
// Notes:
//   (*) IEEE Floating-point user is any person, hardware or software that uses
//       the IEEE floating-point implementation.
//
///Floating-Point Environment
/// - - - - - - - - - - - - -
// NOTE: We currently do not give access to the user to the floating-point
// environment used by our decimal system, so description of it here is
// preliminary and generic.  Note that since compilers and the C library
// already provides a (possibly binary floating-point only) environment and we
// cannot change that, our decimal floating-point environment implementation
// cannot conform to the C and C++ TRs (because those require extending the
// existing standard C library functions).
//
// The floating-point environment provides implicit input and output parameters
// to floating-point operations (that are defined to use them).  IEEE defined
// those parameters in principle, but how they are provided is left up to be
// designed/defined by the implementors of the programming languages.
//
// C (and consequently C++) decided to provide a so-called floating-point
// environment that has "thread storage duration", meaning that each thread of
// a multi-threaded program will have its own distinct floating-point
// environment.
//
// The C/C++ floating-point environment consists of 3 major parts: the rounding
// mode, the traps and the status flags.
//
///Rounding Direction in The Environment
///-  -  -  -  -  -  -  -  -  -  -  -  -
// A floating-point *rounding direction* determines how is the significand of a
// higher (or infinite) precision number get rounded to fit into the limited
// number of significant digits (significand) of the floating-point
// representation that needs to store it as a result of an operation.  Note
// that the rounding is done in the radix of the representation, so binary
// floating-point will do binary rounding while decimal floating-point will do
// decimal rounding - and not all rounding modes are useful with all radixes.
// An example of a generally applicable rounding mode would be 'FE_TOWARDZERO'
// (round towards zero).
//
// Most floating point operations in C and C++ do not take a rounding direction
// parameter (and the ones that are implemented as operators simply could not).
// When such operations (that do not have an explicit rounding direction
// parameter) need to do rounding, they use the rounding direction set in the
// floating-point environment (of their thread of execution).
//
///Status Flags
///  -  -  -  -
// Floating point operations in C and C++ do not take a status flag output
// parameter.  They report an important events (such as underflow, overflow or
// in inexact (rounded) result) by setting the appropriate status flag in the
// floating-point environment (of their thread of execution).  (Note that this
// is very similar to how flags work in CPUs, and that is not a coincidence.)
// The flags work much like individual, boolean 'errno' values.  Operations may
// set them to true.  Users may examine them (when interested) and also reset
// them (set them to 0) before an operation.
//
///Floating-Point Traps
/// -  -  -  -  -  -  -
// IEEE says that certain floating-point events are floating-point exceptions
// and they result in invoking a handler.  It may be a default handler (set a
// status flag and continue) or a user defined handler.  Floating point traps
// are a C invention to enable "sort-of handlers" for floating point
// exceptions, but unfortunately they all go to the same handler: the 'SIGFPE'
// handler.  To add insult to injury, setting what traps are active (what will)
// cause a 'SIGFPE') is not standardized.  So floating-point exceptions and
// handlers are considered pretty much useless in C.  (All is not lost, since
// we do have the status flags.  An application that wants to know about
// floating-point events can clear the flags prior to an operation and check
// their values afterwards.)
//
/// Error Reporting
///-  -  -  -  -  -
// The 'bdldfp_decimalutil' utility component provides a set of decimal math
// functions that parallel those provided for binary floating point in the C++
// standard math library.  Errors during computation of these functions (e.g.,
// domain errors) will be reported through the setting of 'errno' as described
// in the "Status Flags" section above.  (Note that this method of reporting
// errors is atypical for BDE-provided interfaces, but matches the style used
// by the standard functions.)
//
///Floating-Point Terminology
/// - - - - - - - - - - - - -
// A floating-point representation of a number is defined as follows:
// 'sign * significand * BASE^exponent', where sign is -1 or +1, significand is
// an integer, BASE is a positive integer (but usually 2 or 10) and exponent is
// a negative or positive integer.  Concrete examples of (decimal) numbers in
// the so-called scientific notation are: 123.4567 is 1.234567e2, while
// -0.000000000000000000000000000000000000001234567 would be -1.234567e-41.
//
//: "base":
//:    the number base of the scaling used by the exponent; and by the
//:    significand
//:
//: "bias":
//:    the number added to the exponent before it is stored in memory; 101, 398
//:    and 6176 for the 32, 64 and 128 bit types respectively.
//:
//: "exponent":
//:    the scaling applied to the significand is calculated by raising the base
//:    to the exponent (which may be also negative)
//:
//: "quantum":
//:     (IEEE-754) the value of one unit at the last significant digit
//:     position; in other words the smallest difference that can be
//:     represented by a floating-point number without changing its exponent.
//:
//: "mantissa":
//:    the old name for the significand
//:
//: "radix":
//:    another name for base
//:
//: "sign":
//:    +1 or -1, determines if the number is positive or negative.  It is
//:    normally represented by a single sign bit.
//:
//: "significand":
//:    the significant digits of the floating-point number; the value of the
//:    number is: 'sign * significand * base^exponent'
//:
//: "precision":
//:    the significant digits of the floating-point type in its base
//:
//: "decimal precision":
//:    the maximum significant decimal digits of the floating-point type
//:
//: "range":
//:    the smallest and largest number the type can represent.  Note that for
//:    floating-point types there are at least *two* interpretations of
//:    minimum.  It may be the largest negative number *or* the smallest number
//:    in absolute value) that can be represented.
//:
//: "normalized number":
//:    '1 <= significand <= base'
//:
//: "normalization":
//:    finding the exponent such as '1 <= significand <= base'
//:
//: "denormal number":
//:    'significand < 1'
//:
//: "densely packed decimal":
//:    one of the two IEEE significand encoding schemes
//:
//: "binary integer significand":
//:    one of the two IEEE significand encoding schemes
//:
//: "cohorts":
//:    equal numbers encoded using different exponents (to signify accuracy)
//
///Decimal Floating-Point
///----------------------
// Binary floating-point formats give best accuracy, they are the fastest (on
// binary computers), and were carefully designed by IEEE to minimize rounding
// errors (errors due to the inherent imprecision of floating-point types)
// during a lengthy calculation.  This makes them the best solution for and
// serious scientific computation.  However, they have a fatal flow when it
// comes to numbers and calculations that involve humans.  Humans think in base
// 10 - decimal.  And as the example has shown earlier, binary floating-point
// formats are unable to precisely represent very common decimal real numbers;
// with binary floating-point '0.1 + 0.2 != 0.3'.  (Why?  Because none of the
// three numbers in that expression have an exact binary floating-point
// representation.)
//
// Financial calculations are governed by laws and expectations that are based
// on decimal (10 based) thinking.  Due to the inherent limitations of the
// binary floating-point format, doing such decimal based calculations and
// algorithms using binary floating-point numbers is so involved and hard that
// that it is considered not feasible.  The IEEE-754 committee have recognized
// the issue and added specifications for 3 decimal floating-point types into
// their 2008 standard: the 32, 64 and 128 bits decimal floating-point formats.
//
// Floating-point types are carefully designed trade-offs between saving space
// (in memory), CPU cycles (for calculations) and still provide useful accuracy
// for computations.  Decimal floating-point types represent further
// compromises (compared to binary floating-points) in being able to represent
// less numbers (than their binary counterparts) and being slower, but
// providing exact representations for the numbers humans care about.
//
// In decimal floating-point world '0.1 + 0.2 == 0.3', as humans expect;
// because each of those 3 numbers can be represented *exactly* in a decimal
// floating-point format.
//
///*WARNING*: Conversions from 'float' and 'double'
/// - - - - - - - - - - - - - - - - - - - - - - - -
// Clients should *be* *careful* when using the conversions from 'float' and
// 'double' provided by this component.  In situations where a 'float' or
// 'double' was originally obtained from a decimal floating point
// representation (e.g., a 'bdldfp::Decimal', or a string, like "4.1"), the
// conversions in 'bdldfp_decimalconvertutil' will provide the correct
// conversion back to a decimal floating point value.  The conversions in this
// component provide the closest decimal floating point value to the supplied
// binary floating point representation, which may replicate imprecisions
// required to initially approximate the value in a binary representation.
// The conversions in this component are typically useful when converting
// binary floating point values that have undergone mathematical operations
// that require rounding (so they are already in-exact approximations).
//
///Cohorts
///- - - -
// In the binary floating-point world the formats are optimized for the highest
// precision, range and speed.  They are stored normalized and therefore store
// no information about their accuracy.  In finances, the area that decimal
// floating-point types target, accuracy of a number is usually very important.
// We may have a number that is 1, but we know it may be 1.001 or 1.002 etc.
// And we may have another number 1, which we know to be accurate to 6
// significant digits.  We would display the former number as '1.00' and the
// latter number as '1.00000'.  The decimal floating-point types are able to
// store both numbers *and* their precision using so called cohorts.  The
// '1.00' will be stored as '100e-2' while '1.00000' will be stored as
// '100000e-5'.
//
// Cohorts compare equal, and mostly behave the same way in calculation except
// when it comes to the accuracy of the result.  If I have a number that is
// accurate to 5 digits only, it would be a mistake to try to expect more than
// 5 digits accuracy from a calculation involving it.  The IEEE-754 rules of
// cohorts (in calculations) ensures that results will be a cohort that
// indicates the proper expected accuracy.
//
///Standards Conformance
///---------------------
// The component has also been designed to resemble the C++ Decimal
// Floating-Point Technical Report ISO/IEC TR-24733 of 2009 and its C++11
// updates of ISO/IEC JTC1 SC22 WG21 N3407=12-0097 of 2012 as much as it is
// possible with C++03 compilers and environments that do not provide decimal
// floating-point support in any form.
//
// At the time of writing there is just one standard about decimal-floating
// point, the IEEE-754 2008 standard and the content of this component conforms
// to it.  The component does not fully implement all required IEEE-754
// functionality because due to our architectural design guidelines some of
// these must go into a separate so-called utility component.)
//
// The component uses the ISO/IEC TR 24732 - the C Decimal Floating-Point
// TR - in its implementation where it is available.
//
// The component closely resembles ISO/IEC TR 24733 - the C++ Decimal
// Floating-Point TR - but does not fully conform to it for several reasons.
// The major reasons are: it is well known that TR 24733 has to change before
// it is included into the C++ standard; the TR would require us to change
// system header files we do not have access to.
//
// In the following subsections the differences to the C++ technical report are
// explained in detail, including a short rationale.
//
///No Namespace Level Named Functions
/// - - - - - - - - - - - - - - - - -
// BDE design guidelines do not allow namespace level functions other than
// operators and aspects.  According to BDE design principles all such
// functions are placed into a utility component.
//
///All Converting Constructors from Integer Types are Explicit
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// This change is necessary to disable the use of comparison operators without
// explicit casting.  See No Heterogeneous Comparisons Without Casting.
//
///No Heterogeneous Comparisons Without Casting
/// - - - - - - - - - - - - - - - - - - - - - -
// The C and C++ Decimal TRs refer to IEEE-754 for specifications of the
// heterogeneous comparison operators (comparing decimal floating-point types
// to binary floating-point types and integer types); however IEEE-754 does
// *not* specify such operations - leaving them unspecified.  To make matters
// worse, there are two possible ways to implement those operators (convert the
// decimal to the other type, or convert the other type to decimal first) and
// depending on which one is chosen, the result of the operator will be
// different.  Also, the C committee is considering the removal of those
// operators.  We have removed them until we know how to implement them.
// Comparing decimal types to those other types is still possible, it just
// requires explicit casting/conversion from the user code.
//
///Arithmetic And Computing Support For 'Decimal32'
/// - - - - - - - - - - - - - - - - - - - - - - - - -
// IEEE-754 designates the 32 bit floating-point types "interchange formats"
// and does not require or recommend arithmetic or computing support of any
// kind for them.  The C (and consequently the C++) TR goes against the IEEE
// design and requires '_Decimal32' (and 'std::decimal32') to provide computing
// support, however, in a twist, allows it to be performed using one of the
// larger types (64 or 128 bits).  The rationale from the C committee is that
// small embedded systems may need to do their calculations using the small
// type (so they have made it mandatory for everyone).  To conform the
// requirement we provide arithmetic and computing support for Decimal32 type
// but users need to be aware of the drawbacks of calculations using the small
// type. Industry experience with the 'float' C type (32bit floating-point
// type, usually binary) has shown that enabling computing using small
// floating-point types are a mistake that causes novice programmers to write
// calculations that are very slow and inaccurate.
//
// We recommend what IEEE recommends: convert your 32 bit types on receipt to a
// type with higher precision (usually 64 bit will suffice), so you
// calculations using that larger type, and convert it back to 32 bit type only
// if your output interchange format requires it.
//
///Non-Standard Member Functions
///- - - - - - - - - - - - - - -
// Due to BDE rules of design and some implementation needs we have extended
// the C++ TR mandated interface of the decimal floating-point types to include
// support for accessing the underlying data (type), to parse literals for the
// portable literal support.
//
// Note that using any of these public member functions will render your code
// non-portable to non-BDE (but standards conforming) implementations.
//
///'Decimal32' Type
///----------------
// A basic format type that supports input, output, relational operators
// construction from the TR mandates data types and arithmetic or operations.
// The type has the size of exactly 32 bits.  It supports 7 significant decimal
// digits and an exponent range of -95 to 96.  The smallest non-zero value that
// can be represented is 1e-101.
//
// Portable 'Decimal32' literals are created using the 'BDLDFP_DECIMAL_DF'
// macro.
//
///'Decimal64' Type
///----------------
// A basic format type that supports input, output, relational operators
// construction from the TR mandates data types and arithmetic or operations.
// The type has the size of exactly 64 bits.  It supports 16 significant
// decimal digits and an exponent range of -383 to 384.  The smallest non-zero
// value that can be represented is 1e-398.
//
// Portable 'Decimal64' literals are created using the 'BDLDFP_DECIMAL_DD'
// macro.
//
///'Decimal128' Type
///-----------------
// A basic format type that supports input, output, relational operators
// construction from the TR mandates data types and arithmetic or operations.
// The type has the size of exactly 128 bits.  It supports 34 significant
// decimal digits and an exponent range of -6143 to 6144.  The smallest
// non-zero value that can be represented is 1e-6176.
//
// Portable 'Decimal128' literals are created using the 'BDLDFP_DECIMAL_DL'
// macro.
//
///Decimal Number Formatting
///-------------------------
// Streaming decimal floating point numbers to an output stream supports
// formatting flags for width, capitalization and justification and flags used
// to output numbers in natural, scientific and fixed notations.  When
// scientific or fixed flags are set then the precision manipulator specifies
// how many digits of the decimal number are to be printed, otherwise all
// significant digits of the decimal number are output using native notation.
//
///User-defined literals
///---------------------
// The user-defined literal 'operator "" _d32', 'operator "" _d64', and
// 'operator "" _d128' are declared for the 'bdldfp::Decimal32',
// 'bdldfp::Decimal64', and 'bdldfp::Decimal128' types respectively .  These
// user-defined literal suffixes can be applied to both numeric and string
// literals, (i.e., 1.2_d128, "1.2"_d128 or "inf"_d128) to produce a decimal
// floating-point value of the indicated type by parsing the argument string
// or numeric value:
//..
//  using namespace bdldfp::DecimalLiterals;
//
//  bdldfp::Decimal32   d0  = "1.2"_d32;
//  bdldfp::Decimal32   d1  =  1.2_d32;
//  assert(d0 == d1);
//
//  bdldfp::Decimal64   d2  = "3.45678901234"_d64;
//  bdldfp::Decimal64   d3  =  3.45678901234_d64;
//  assert(d2 == d3);
//
//  bdldfp::Decimal128  inf = "inf"_d128;
//  bdldfp::Decimal128  nan = "nan"_d128;
//..
// The operators providing literals are available in the
// 'BloombergLP::bdldfp::literals::DecimalLiterals' namespace (where 'literals'
// and 'DecimalLiterals' are both inline namespaces). Because of inline
// namespaces, there are several viable options for a using declaration, but
// *we* *recommend* 'using namespace bdldfp::DecimalLiterals', which minimizes
// the scope of the using declaration.
//
// Note that the parsing follows the rules as specified for the 'strtod32',
// 'strtod64' and 'strtod128' functions in section 9.6 of the ISO/EIC TR 247128
// C Decimal Floating-Point Technical Report.
//
// Also note that these operators can be used only if the compiler supports
// C++11 standard.
//
///Usage
///-----
// In this section, we show the intended usage of this component.
//
///Example 1: Portable Initialization of Non-Integer, Constant Values
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// If your compiler does not support the C Decimal TR, it does not support
// decimal floating-point literals, only binary floating-point literals.  The
// problem with binary floating-point literals is the same as with binary
// floating-point numbers in general: they cannot represent the decimal numbers
// we care about.  To solve this problem there are 3 macros provided by this
// component that can be used to initialize decimal floating-point types with
// non-integer values, precisely.  These macros will evaluate to real, C
// language literals where those are supported and to a runtime-parsed solution
// otherwise.  The following code demonstrates the use of these macros as well
// as mixed-type arithmetics and comparisons:
//..
//  bdldfp::Decimal32  d32( BDLDFP_DECIMAL_DF(0.1));
//  bdldfp::Decimal64  d64( BDLDFP_DECIMAL_DD(0.2));
//  bdldfp::Decimal128 d128(BDLDFP_DECIMAL_DL(0.3));
//
//  assert(d32 + d64 == d128);
//  assert(bdldfp::Decimal64(d32)  * 10 == bdldfp::Decimal64(1));
//  assert(d64  * 10 == bdldfp::Decimal64(2));
//  assert(d128 * 10 == bdldfp::Decimal128(3));
//..
//
///Example 2: Precise Calculations with Decimal Values
///- - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we need to add two (decimal) numbers and then tell if the result is
// a particular decimal number or not.  That can get difficult with binary
// floating-point, but easy with decimal:
//..
//  if (std::numeric_limits<double>::radix == 2) {
//    assert(.1 + .2 != .3);
//  }
//  assert(BDLDFP_DECIMAL_DD(0.1) + BDLDFP_DECIMAL_DD(0.2)
//      == BDLDFP_DECIMAL_DD(0.3));
//..

#include <bdlscm_version.h>

#include <bdldfp_decimalimputil.h>
#include <bdldfp_decimalstorage.h>

#include <bslh_hash.h>

#include <bslma_default.h>

#include <bslmf_istriviallycopyable.h>
#include <bslmf_nestedtraitdeclaration.h>

#include <bsls_assert.h>
#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>
#include <bsls_libraryfeatures.h>
#include <bsls_platform.h>

#include <bsl_cstddef.h>
#include <bsl_cstring.h>
#include <bsl_ios.h>
#include <bsl_iosfwd.h>
#include <bsl_iterator.h>
#include <bsl_limits.h>
#include <bsl_locale.h>


#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bslalg_typetraits.h>

#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES


               // Portable decimal floating-point literal support

#define BDLDFP_DECIMAL_DF(lit)                                                \
    BloombergLP::bdldfp::Decimal32(BDLDFP_DECIMALIMPUTIL_DF(lit))

#define BDLDFP_DECIMAL_DD(lit)                                                \
    BloombergLP::bdldfp::Decimal64(BDLDFP_DECIMALIMPUTIL_DD(lit))

#define BDLDFP_DECIMAL_DL(lit)                                                \
    BloombergLP::bdldfp::Decimal128(BDLDFP_DECIMALIMPUTIL_DL(lit))

namespace BloombergLP {
namespace bdldfp {

                            // FORWARD DECLARATIONS

class Decimal_Type32;
class Decimal_Type64;
class Decimal_Type128;
    // These are the actual (decimal floating-point) types being implemented.
    // They use a different name to cause an error if the official types are
    // forward declared: The exact definition of the decimal types is left
    // unspecified so that that can potentially be aliases for built-in types.

typedef Decimal_Type32  Decimal32;
typedef Decimal_Type64  Decimal64;
typedef Decimal_Type128 Decimal128;
    // The decimal floating-point types are typedefs to the unspecified
    // implementation types.

                      // THE DECIMAL FLOATING-POINT TYPES

                            // ====================
                            // class Decimal_Type32
                            // ====================

class Decimal_Type32 {
    // This value-semantic class implements the IEEE-754 32 bit decimal
    // floating-point interchange format type.  This class is a standard layout
    // type that is 'const' thread-safe and exception-neutral.

  private:
    // DATA
    DecimalImpUtil::ValueType32 d_value; // The underlying IEEE representation

  public:
    // CLASS METHODS

                                  // Aspects

    static int maxSupportedBdexVersion();
    static int maxSupportedBdexVersion(int versionSelector);
        // Return the maximum valid BDEX format version, as indicated by the
        // specified 'versionSelector', to be passed to the 'bdexStreamOut'
        // method.  Note that it is highly recommended that 'versionSelector'
        // be formatted as "YYYYMMDD", a date representation.  Also note that
        // 'versionSelector' should be a *compile*-time-chosen value that
        // selects a format version supported by both externalizer and
        // unexternalizer.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(Decimal_Type32, bsl::is_trivially_copyable);


    // CREATORS
    Decimal_Type32();
        // Create a 'Decimal32_Type' object having the value positive zero and
        // the smallest exponent value.

    Decimal_Type32(DecimalImpUtil::ValueType32 value);              // IMPLICIT
        // Create a 'Decimal32_Type' object having the specified 'value'.

    explicit Decimal_Type32(Decimal_Type64  other);
    explicit Decimal_Type32(Decimal_Type128 other);
        // Create a 'Decimal32_Type' object having the value closest to the
        // value of the specified 'other' following the conversion rules as
        // defined by IEEE-754:
        //
        //: o If 'other' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise if 'other' is infinity (positive or negative), then
        //:   initialize this object to infinity with the same sign.
        //:
        //: o Otherwise if 'other' has a zero value, then initialize this
        //:   object to zero with the same sign.
        //:
        //: o Otherwise if 'other' has an absolute value that is larger than
        //:   'std::numeric_limits<Decimal32>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and initialize this object to
        //:   infinity with the same sign as 'other'.
        //:
        //: o Otherwise if 'other' has an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal32>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and initialize this object to
        //:   zero with the same sign as 'other'.
        //:
        //: o Otherwise if 'other' has a value that has more significant digits
        //:   than 'std::numeric_limits<Decimal32>::max_digit' then initialize
        //:   this object to the value of 'other' rounded according to the
        //:   rounding direction.
        //:
        //: o Otherwise initialize this object to the value of the 'other'.

    explicit Decimal_Type32(float       other);
    explicit Decimal_Type32(double      other);
        // Create a 'Decimal32_Type' object having the value closest to the
        // value of the specified 'other' value.  *Warning:* clients requiring
        // a conversion for an exact decimal value should use
        // 'bdldfp_decimalconvertutil' (see *WARNING*: Conversions from
        // 'float' and 'double'}.  This conversion follows the conversion
        // rules as defined by IEEE-754:
        //
        //: o If 'other' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise if 'other' is infinity (positive or negative), then
        //:   initialize this object to infinity value with the same sign.
        //:
        //: o Otherwise if 'other' has a zero value, then initialize this
        //:   object to zero with the same sign.
        //:
        //: o Otherwise if 'other' has an absolute value that is larger than
        //:   'std::numeric_limits<Decimal32>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and initialize this object to
        //:   infinity with the same sign as 'other'.
        //:
        //: o Otherwise if 'other' has an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal32>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and initialize this object to
        //:   zero with the same sign as 'other'.
        //:
        //: o Otherwise if 'other' has a value that has more significant digits
        //:   than 'std::numeric_limits<Decimal32>::max_digit' then initialize
        //:   this object to the value of 'other' rounded according to the
        //:   rounding direction.
        //:
        //: o Otherwise initialize this object to the value of the 'other'.

    explicit Decimal_Type32(int                other);
    explicit Decimal_Type32(unsigned int       other);
    explicit Decimal_Type32(long int           other);
    explicit Decimal_Type32(unsigned long int  other);
    explicit Decimal_Type32(long long          other);
    explicit Decimal_Type32(unsigned long long other);
        // Create a 'Decimal32_Type' object having the value closest to the
        // value of the specified 'other' following the conversion rules as
        // defined by IEEE-754:
        //
        //: o If 'value' is zero then initialize this object to a zero with an
        //:   unspecified sign and an unspecified exponent.
        //:
        //: o Otherwise if 'other' has a value that is not exactly
        //:   representable using 'std::numeric_limits<Decimal32>::max_digit'
        //:   decimal digits then initialize this object to the value of
        //:   'other' rounded according to the rounding direction.
        //:
        //: o Otherwise initialize this object to the value of 'other' with
        //:   exponent 0.

    //! Decimal32_Type(const Decimal32_Type& original) = default;
        // Create a 'Decimal32_Type' object that is a copy of the specified
        // 'original' as defined by the 'copy' operation of IEEE-754 2008:
        //
        //: o If 'other' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise initialize this object to the value of the 'other'.
        //
        // Note that since floating-point types may be NaN, and NaNs are
        // unordered (do not compare equal even to themselves) it is possible
        // that a copy of a decimal will not compare equal to the original;
        // however it will behave as the original.

    //! ~Decimal32_Type() = default;
        // Destroy this object.

    // MANIPULATORS
    //! Decimal32_Type& operator=(const Decimal32_Type& rhs) = default;
        // Make this object a copy of the specified 'rhs' as defined by the
        // 'copy' operation of IEEE-754 2008 and return a reference providing
        // modifiable access to this object.
        //
        //: o If 'other' is NaN, set this object to a NaN.
        //:
        //: o Otherwise set this object to the value of the 'other'.
        //
        // Note that since floating-point types may be NaN, and NaNs are
        // unordered (do not compare equal even to themselves) it is possible
        // that, after an assignment, a decimal will not compare equal to the
        // original; however it will behave as the original.

    Decimal_Type32& operator++();
        // Add 1.0 to the value of this object and return a reference to it.
        // Note that this is a floating-point value so this operation may not
        // change the value of this object at all (if the value is large) or it
        // may just set it to 1.0 (if the original value is small).

    Decimal_Type32& operator--();
        // Add -1.0 to the value of this object and return a reference to it.
        // Note that this is a floating-point value so this operation may not
        // change the value of this object at all (if the value is large) or it
        // may just set it to -1.0 (if the original value is small).

    Decimal_Type32& operator+=(Decimal32  rhs);
    Decimal_Type32& operator+=(Decimal64  rhs);
    Decimal_Type32& operator+=(Decimal128 rhs);
        // Add the value of the specified 'rhs' object to the value of this as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinity value of
        //:   differing signs, store the value of the macro 'EDOM' into 'errno'
        //:   and set this object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinite values of the
        //:   same sign, then do not change this object.
        //:
        //: o Otherwise if 'rhs' has a zero value (positive or negative), do
        //:   not change this object.
        //:
        //: o Otherwise if the sum of this object and 'rhs' has an absolute
        //:   value that is larger than 'std::numeric_limits<Decimal32>::max()'
        //:   then store the value of the macro 'ERANGE' into 'errno' and
        //:   set this object to infinity with the same sign as that result.
        //:
        //: o Otherwise set this object to the sum of the number represented by
        //:   'rhs' and the number represented by this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).
        //
        // Also note that when 'rhs' is a 'Decimal64', this operation is
        // always performed with 64 bits precision to prevent loss of
        // precision of the 'rhs' operand (prior to the operation).  The
        // result is then rounded back to 32 bits and stored to this object.
        // See IEEE-754 2008, 5.1, first paragraph, second sentence for
        // specification.
        //
        // Also note that when 'rhs' is a 'Decimal128', this operation is
        // always performed with 128 bits precision to prevent loss of
        // precision of the 'rhs' operand (prior to the operation).  The
        // result is then rounded back to 32 bits and stored to this object.
        // See IEEE-754 2008, 5.1, first paragraph, second sentence for
        // specification.

    Decimal_Type32& operator+=(int                rhs);
    Decimal_Type32& operator+=(unsigned int       rhs);
    Decimal_Type32& operator+=(long               rhs);
    Decimal_Type32& operator+=(unsigned long      rhs);
    Decimal_Type32& operator+=(long long          rhs);
    Decimal_Type32& operator+=(unsigned long long rhs);
        // Add the specified 'rhs' to the value of this object as described by
        // IEEE-754, store the result in this object, and return a reference to
        // this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity, then do not change it.
        //:
        //: o Otherwise if the sum of this object and 'rhs' has an absolute
        //:   value that is larger than 'std::numeric_limits<Decimal32>::max()'
        //:   then store the value of the macro 'ERANGE' into 'errno' and
        //:   set this object to infinity with the same sign as that result.
        //:
        //: o Otherwise set this object to sum of adding 'rhs' and the number
        //:   represented by this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).
        //
        // Also note that this operation is always performed with 64 bits
        // precision to prevent loss of precision of the 'rhs' operand (prior
        // to the operation).  The result is then rounded back to 32 bits and
        // stored to this object.  See IEEE-754 2008, 5.1, first paragraph,
        // second sentence for specification.


    Decimal_Type32& operator-=(Decimal32  rhs);
    Decimal_Type32& operator-=(Decimal64  rhs);
    Decimal_Type32& operator-=(Decimal128 rhs);
        // Subtract the value of the specified 'rhs' from the value of this
        // object as described by IEEE-754, store the result in this object,
        // and return a reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinity value of the
        //:   same signs, store the value of the macro 'EDOM' into 'errno'
        //:   and set this object to a NaN.
        //:
        //: o Otherwise if this object and the 'rhs' have infinite values of
        //:   differing signs, then do not change this object.
        //:
        //: o Otherwise if the 'rhs' has a zero value (positive or negative),
        //:   do not change this object.
        //:
        //: o Otherwise if subtracting the value of the 'rhs' object from this
        //:   results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal32>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the result of subtracting the value
        //:   of 'rhs' from the value of this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).
        //
        // Also note that when 'rhs' is a 'Decimal64', this operation is
        // always performed with 64 bits precision to prevent loss of
        // precision of the 'rhs' operand (prior to the operation).  The
        // result is then rounded back to 32 bits and stored to this object.
        // See IEEE-754 2008, 5.1, first paragraph, second sentence for
        // specification.
        //
        // Also note that when 'rhs' is a 'Decimal128', this operation is
        // always performed with 128 bits precision to prevent loss of
        // precision of the 'rhs' operand (prior to the operation).  The
        // result is then rounded back to 32 bits and stored to this object.
        // See IEEE-754 2008, 5.1, first paragraph, second sentence for
        // specification.

    Decimal_Type32& operator-=(int                rhs);
    Decimal_Type32& operator-=(unsigned int       rhs);
    Decimal_Type32& operator-=(long               rhs);
    Decimal_Type32& operator-=(unsigned long      rhs);
    Decimal_Type32& operator-=(long long          rhs);
    Decimal_Type32& operator-=(unsigned long long rhs);
        // Subtract the specified 'rhs' from the value of this object as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity, then do not change it.
        //:
        //: o Otherwise if subtracting 'rhs' from this object's value results
        //:   in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal32>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the result of subtracting 'rhs' from
        //:   the value of this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).
        //
        // Also note that this operation is always performed with 64 bits
        // precision to prevent loss of precision of the 'rhs' operand (prior
        // to the operation).  The result is then rounded back to 32 bits and
        // stored to this object.  See IEEE-754 2008, 5.1, first paragraph,
        // second sentence for specification.

    Decimal_Type32& operator*=(Decimal32  rhs);
    Decimal_Type32& operator*=(Decimal64  rhs);
    Decimal_Type32& operator*=(Decimal128 rhs);
        // Multiply the value of the specified 'rhs' object by the value of
        // this as described by IEEE-754, store the result in this object, and
        // return a reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise, if one of this object and 'rhs' is zero (positive or
        //:   negative) and the other is infinity (positive or negative), store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise, if either this object or 'rhs' is positive or negative
        //:   infinity, set this object to infinity.  The sign of this object
        //:   will be positive if this object and 'rhs' had the same sign, and
        //:   negative otherwise.
        //:
        //: o Otherwise, if either this object or 'rhs' is zero, set this
        //:   object to zero.  The sign of this object will be positive if this
        //:   object and 'rhs' had the same sign, and negative otherwise.
        //:
        //: o Otherwise if the product of this object and 'rhs' has an absolute
        //:   value that is larger than 'std::numeric_limits<Decimal32>::max()'
        //:   then store the value of the macro 'ERANGE' into 'errno' and set
        //:   this object to infinity with the same sign of that result.
        //:
        //: o Otherwise if the product of this object and 'rhs' has an absolute
        //:   value that is smaller than
        //:   'std::numeric_limits<Decimal32>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to zero value
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the product of the value of 'rhs'
        //:   and the value of this object.
        //
        // Note that when 'rhs' is a 'Decimal64', this operation is always
        // performed with 64 bits precision to prevent loss of precision of the
        // 'rhs' operand (prior to the operation).  The result is then rounded
        // back to 32 bits and stored to this object.  See IEEE-754 2008, 5.1,
        // first paragraph, second sentence for specification.
        //
        // Also note that when 'rhs' is a 'Decimal128', this operation is
        // always performed with 128 bits precision to prevent loss of
        // precision of the 'rhs' operand (prior to the operation).  The
        // result is then rounded back to 32 bits and stored to this object.
        // See IEEE-754 2008, 5.1, first paragraph, second sentence for
        // specification.

    Decimal_Type32& operator*=(int                rhs);
    Decimal_Type32& operator*=(unsigned int       rhs);
    Decimal_Type32& operator*=(long               rhs);
    Decimal_Type32& operator*=(unsigned long      rhs);
    Decimal_Type32& operator*=(long long          rhs);
    Decimal_Type32& operator*=(unsigned long long rhs);
        // Multiply the specified 'rhs' by the value of this object as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity (positive or negative), and
        //:   'rhs' is zero, then store the value of the macro 'EDOM' into
        //:   'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is infinity (positive or negative), then
        //:   do not change it.
        //:
        //: o Otherwise if 'rhs' is zero, then set this object to zero with the
        //:   same sign as its value had prior to this operation.
        //:
        //: o Otherwise if the product of 'rhs' and the value of this object
        //:   results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal32>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise if the product of 'rhs' and the value of this object
        //:   results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal32>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to zero with
        //:   the same sign as that result.
        //:
        //: o Otherwise set this object to the product of the value of this
        //:   object and the value 'rhs'.
        //
        // Note that this operation is always performed with 64 bits precision
        // to prevent loss of precision of the 'rhs' operand (prior to the
        // operation).  The result is then rounded back to 32 bits and stored
        // to this object.  See IEEE-754 2008, 5.1, first paragraph,

    Decimal_Type32& operator/=(Decimal32  rhs);
    Decimal_Type32& operator/=(Decimal64  rhs);
    Decimal_Type32& operator/=(Decimal128 rhs);
        // Divide the value of this object by the value of the specified 'rhs'
        // as described by IEEE-754, store the result in this object, and
        // return a reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object 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.
        //:
        //: o Otherwise if 'rhs' has a positive zero value, then store the
        //:   value of the macro 'ERANGE' into 'errno' and set this object to
        //:   infinity with the same sign as its original value.
        //:
        //: o Otherwise if 'rhs' has a negative zero value, then store the
        //:   value of the macro 'ERANGE' into 'errno' and set this object to
        //:   infinity with the opposite sign as its original value.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in 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 that result.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal32>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno'and return zero with the same sign
        //:   as that result.
        //:
        //: o Otherwise set this object to the result of dividing the value of
        //:   this object by the value of 'rhs'.
        //
        // Note that when 'rhs' is a 'Decimal64', this operation is always
        // performed with 64 bits precision to prevent loss of precision of the
        // 'rhs' operand (prior to the operation).  The result is then rounded
        // back to 32 bits and stored to this object.  See IEEE-754 2008, 5.1,
        // first paragraph, second sentence for specification.
        //
        // Also note that when 'rhs' is a 'Decimal128', this operation is
        // always performed with 128 bits precision to prevent loss of
        // precision of the 'rhs' operand (prior to the operation).  The
        // result is then rounded back to 32 bits and stored to this object.
        // See IEEE-754 2008, 5.1, first paragraph, second sentence for
        // specification.

    Decimal_Type32& operator/=(int                rhs);
    Decimal_Type32& operator/=(unsigned int       rhs);
    Decimal_Type32& operator/=(long               rhs);
    Decimal_Type32& operator/=(unsigned long      rhs);
    Decimal_Type32& operator/=(long long          rhs);
    Decimal_Type32& operator/=(unsigned long long rhs);
        // Divide the value of this object by the specified 'rhs' as described
        // by IEEE-754, store the result in this object, and return a reference
        // to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN then set this object to a NaN.
        //:
        //: o Otherwise if this object is infinity (positive or negative) and
        //:   'rhs' is positive value then set this object to infinity value
        //:   with the same sign as its original value.
        //:
        //: o Otherwise if this object is infinity (positive or negative) and
        //:   'rhs' is negative value then set this object to infinity value
        //:   with the opposite sign as its original value.
        //:
        //: o Otherwise if 'rhs' is zero, store the value of the macro 'ERANGE'
        //:   into 'errno' and set this object to infinity with the same sign
        //:   it had prior to this operation.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in 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 that result.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal32>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno'and return zero with the same sign
        //:   as that result.
        //:
        //: o Otherwise set this object to the result of dividing the value of
        //:   this object by the value of 'rhs'.
        //
        // Note that this operation is always performed with 64 bits precision
        // to prevent loss of precision of the 'rhs' operand (prior to the
        // operation).  The result is then rounded back to 32 bits and stored
        // to this object.  See IEEE-754 2008, 5.1, first paragraph,

    DecimalImpUtil::ValueType32 *data();
        // Return a pointer providing modifiable access to the underlying
        // implementation.

                                  // Aspects

    template <class STREAM>
    STREAM& bdexStreamIn(STREAM& stream, int version);
        // Assign to this object the value read from the specified input
        // 'stream' using the specified 'version' format, and return a
        // reference to 'stream'.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'version' is not supported, this object
        // is unaltered and 'stream' is invalidated, but otherwise unmodified.
        // If 'version' is supported but 'stream' becomes invalid during this
        // operation, this object has an undefined, but valid, state.  Note
        // that no version is read from 'stream'.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    // ACCESSORS
    const DecimalImpUtil::ValueType32 *data() const;
        // Return a pointer providing non-modifiable access to the underlying
        // implementation.

    DecimalImpUtil::ValueType32 value() const;
        // Return the value of the underlying implementation.

                                  // Aspects

    template <class STREAM>
    STREAM& bdexStreamOut(STREAM& stream, int version) const;
        // Write the value of this object, using the specified 'version'
        // format, to the specified output 'stream', and return a reference to
        // 'stream'.  If 'stream' is initially invalid, this operation has no
        // effect.  If 'version' is not supported, 'stream' is invalidated, but
        // otherwise unmodified.  Note that 'version' is not written to
        // 'stream'.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.
};

// FREE OPERATORS
Decimal32 operator+(Decimal32 value);
    // Return a copy of the specified 'value' if the value is not negative
    // zero, and return positive zero otherwise.

Decimal32 operator-(Decimal32 value);
    // Return the result of applying the unary - operator to the specified
    // 'value' as described by IEEE-754, essentially reversing the sign bit.
    // Note that floating-point numbers have signed zero, so this operation is
    // not the same as '0 - value'.

Decimal32 operator++(Decimal32& value, int);
    // Apply the prefix ++ operator to the specified 'value' and return its
    // original value.  Note that this is a floating-point value so this
    // operation may not change the value of this object at all (if the value
    // is large) or it may just set it to 1.0 (if the original value is small).

Decimal32 operator--(Decimal32& value, int);
    // Apply the prefix -- operator to the specified 'value' and return its
    // original value.  Note that this is a floating-point value so this
    // operation may not change the value of this object at all (if the value
    // is large) or it may just set it to -1.0 (if the original value is
    // small).

Decimal32 operator+(Decimal32 lhs, Decimal32 rhs);
    // Add the value of the specified 'rhs' to the value of the specified 'lhs'
    // as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o Otherwise if 'lhs' and 'rhs' are infinities of differing signs, store
    //:   the value of the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' and 'rhs' are infinities of the same sign then
    //:   return infinity of that sign.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' has an absolute value that is
    //:   larger than 'std::numeric_limits<Decimal32>::max()' then store the
    //:   value of the macro 'ERANGE' into 'errno' and set this object to
    //:   infinity with the same sign as that result.
    //:
    //: o Otherwise return the sum of the number represented by 'lhs' and the
    //:   number represented by 'rhs'.

Decimal32 operator+(Decimal32 lhs, int                rhs);
Decimal32 operator+(Decimal32 lhs, unsigned int       rhs);
Decimal32 operator+(Decimal32 lhs, long               rhs);
Decimal32 operator+(Decimal32 lhs, unsigned long      rhs);
Decimal32 operator+(Decimal32 lhs, long long          rhs);
Decimal32 operator+(Decimal32 lhs, unsigned long long rhs);
    // Add the specified 'rhs' to the value of the specified 'lhs' as described
    // by IEEE-754 and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' object is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity, then return infinity.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' 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 that result.
    //:
    //: o Otherwise return the sum of 'rhs' and the number represented by
    //:   'lhs'.

Decimal32 operator+(int                lhs, Decimal32 rhs);
Decimal32 operator+(unsigned int       lhs, Decimal32 rhs);
Decimal32 operator+(long               lhs, Decimal32 rhs);
Decimal32 operator+(unsigned long      lhs, Decimal32 rhs);
Decimal32 operator+(long long          lhs, Decimal32 rhs);
Decimal32 operator+(unsigned long long lhs, Decimal32 rhs);
    // Add the specified 'lhs' to the value of the specified 'rhs' as described
    // by IEEE-754 and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' object is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity, then return infinity.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' 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 that result.
    //:
    //: o Otherwise return the sum of 'lhs' and the number represented by
    //:   'rhs'.

Decimal32 operator-(Decimal32 lhs, Decimal32 rhs);
    // Subtract the value of the specified 'rhs' from the value of the
    // specified 'lhs' as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o Otherwise if 'lhs' and the 'rhs' have infinity values of differing
    //:   signs, then return 'lhs'.
    //:
    //: o Otherwise if the subtracting of 'lhs' and 'rhs' 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 that result.
    //:
    //: o Otherwise return the result of subtracting the value of 'rhs' from
    //:   the value of 'lhs'.

Decimal32 operator-(Decimal32 lhs, int                rhs);
Decimal32 operator-(Decimal32 lhs, unsigned int       rhs);
Decimal32 operator-(Decimal32 lhs, long               rhs);
Decimal32 operator-(Decimal32 lhs, unsigned long      rhs);
Decimal32 operator-(Decimal32 lhs, long long          rhs);
Decimal32 operator-(Decimal32 lhs, unsigned long long rhs);
    // Subtract the specified 'rhs' from the value of the specified 'lhs' as
    // described by IEEE-754 and return a reference to this object.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity, then return infinity.
    //:
    //: o Otherwise if subtracting 'rhs' from 'lhs' object's value results in
    //:   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
    //:   that result.
    //:
    //: o Otherwise return the result of subtracting 'rhs' from the value of
    //:   'lhs'.

Decimal32 operator-(int                lhs, Decimal32 rhs);
Decimal32 operator-(unsigned int       lhs, Decimal32 rhs);
Decimal32 operator-(long               lhs, Decimal32 rhs);
Decimal32 operator-(unsigned long      lhs, Decimal32 rhs);
Decimal32 operator-(long long          lhs, Decimal32 rhs);
Decimal32 operator-(unsigned long long lhs, Decimal32 rhs);
    // Subtract the specified 'rhs' from the value of the specified 'lhs' as
    // described by IEEE-754 and return a reference to this object.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity, then return infinity.
    //:
    //: o Otherwise if subtracting 'rhs' from 'lhs' object's value results in
    //:   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
    //:   that result.
    //:
    //: o Otherwise return the result of subtracting the value of 'rhs' from
    //:   the number 'lhs'.

Decimal32 operator*(Decimal32 lhs, Decimal32 rhs);
    // Multiply the value of the specified 'lhs' object by the value of the
    // specified 'rhs' as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o 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.
    //:
    //: o 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.
    //:
    //: o Otherwise if the product of 'lhs' and 'rhs' 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 that result.
    //:
    //: o Otherwise if the product of 'lhs' and 'rhs' 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 zero
    //:   with the same sign as that result.
    //:
    //: o Otherwise return the product of the value of 'rhs' and the number
    //:   represented by 'rhs'.

Decimal32 operator*(Decimal32 lhs, int                rhs);
Decimal32 operator*(Decimal32 lhs, unsigned int       rhs);
Decimal32 operator*(Decimal32 lhs, long               rhs);
Decimal32 operator*(Decimal32 lhs, unsigned long      rhs);
Decimal32 operator*(Decimal32 lhs, long long          rhs);
Decimal32 operator*(Decimal32 lhs, unsigned long long rhs);
    // Multiply the specified 'rhs' by the value of the specified 'lhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative), and 'rhs' is
    //:   zero, then store the value of the macro 'EDOM' into 'errno' and
    //:   return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative), then return
    //:   'lhs'.
    //:
    //: o Otherwise if 'rhs' is zero, then return zero with the sign of 'lhs'.
    //:
    //: o Otherwise if the product of 'rhs' and the value of 'lhs' results in
    //:   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
    //:   that result.
    //:
    //: o Otherwise if the product of 'rhs' and the value of 'lhs' results in
    //:   an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal32>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the product of the value of 'lhs' and value 'rhs'.

Decimal32 operator*(int                lhs, Decimal32 rhs);
Decimal32 operator*(unsigned int       lhs, Decimal32 rhs);
Decimal32 operator*(long               lhs, Decimal32 rhs);
Decimal32 operator*(unsigned long      lhs, Decimal32 rhs);
Decimal32 operator*(long long          lhs, Decimal32 rhs);
Decimal32 operator*(unsigned long long lhs, Decimal32 rhs);
    // Multiply the specified 'lhs' by the value of the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), and 'lhs' is
    //:   zero, then store the value of the macro 'EDOM' into 'errno' and
    //:   return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), then return
    //:   'rhs'.
    //:
    //: o Otherwise if 'lhs' is zero, then return zero with the sign of 'rhs'.
    //:
    //: o Otherwise if the product of 'lhs' and the value of 'rhs' results in
    //:   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
    //:   that result.
    //:
    //: o Otherwise if the product of 'lhs' and the value of 'rhs' results in
    //:   an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal32>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the product of the value of 'lhs' and value 'rhs'.

Decimal32 operator/(Decimal32 lhs, Decimal32 rhs);
    // Divide the value of the specified 'lhs' by the value of the specified
    // 'rhs' as described by IEEE-754, and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o 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'.
    //:
    //: o 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'.
    //:
    //: o Otherwise if 'lhs' has infinity value and 'rhs' has a positive zero
    //:   value, return infinity with the sign of 'lhs'.
    //:
    //: o Otherwise if 'lhs' has infinity value and 'rhs' has a negative zero
    //:   value, return infinity with the opposite sign as 'lhs'.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in 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
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal32>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value of 'rhs'.

Decimal32 operator/(Decimal32 lhs, int                rhs);
Decimal32 operator/(Decimal32 lhs, unsigned int       rhs);
Decimal32 operator/(Decimal32 lhs, long               rhs);
Decimal32 operator/(Decimal32 lhs, unsigned long      rhs);
Decimal32 operator/(Decimal32 lhs, long long          rhs);
Decimal32 operator/(Decimal32 lhs, unsigned long long rhs);
    // Divide the value of the specified 'lhs' by the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative) and 'rhs' is
    //:   positive value then return infinity value with the same sign as its
    //:   original value.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative) and 'rhs' is
    //:   negative value then return infinity value with the opposite sign as
    //:   its original value.
    //:
    //: o Otherwise if 'rhs' is zero, store the value of the macro 'ERANGE'
    //:   into 'errno' and return infinity with the same sign it had prior to
    //:   this operation.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in 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
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal32>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value 'rhs'.

Decimal32 operator/(int                lhs, Decimal32 rhs);
Decimal32 operator/(unsigned int       lhs, Decimal32 rhs);
Decimal32 operator/(long               lhs, Decimal32 rhs);
Decimal32 operator/(unsigned long      lhs, Decimal32 rhs);
Decimal32 operator/(long long          lhs, Decimal32 rhs);
Decimal32 operator/(unsigned long long lhs, Decimal32 rhs);
    // Divide the specified 'lhs' by the value of the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), and 'lhs' is
    //:   zero, store the value of the macro 'ERANGE' into 'errno' and return a
    //:   NaN.
    //:
    //: o Otherwise if 'rhs' is zero (positive or negative), store the value of
    //:   the macro 'ERANGE' into 'errno' and return infinity with the sign of
    //:   'lhs'.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in 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
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal32>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value 'rhs'.  Note that this is a floating-point operation, not
    //:   integer.

bool operator==(Decimal32 lhs, Decimal32 rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and
    // 'false' otherwise.  Two 'Decimal32' 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 'Decimal32' objects have the same value if:
    //
    //: o both have a zero value (positive or negative), or
    //: o both have the same infinity value (both positive or negative), or
    //: o both have the value of a real number that are equal, even if they are
    //:   represented differently (cohorts have the same value)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.
    //
    // Note that a NaN is never equal to anything, including itself:
    //..
    //  Decimal32 aNaN = std::numeric_limits<Decimal32>::quiet_NaN();
    //  assert(!(aNan == aNan));
    //..

bool operator!=(Decimal32 lhs, Decimal32 rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' do not have the same
    // value, and 'false' otherwise.  Two 'Decimal32' objects do not have the
    // same value if the 'compareQuietEqual' operation (IEEE-754 defined,
    // non-total ordering comparison) considers the underlying IEEE
    // representations not equal.  In other words, two 'Decimal32' objects do
    // not have the same value if:
    //
    //: o both are NaN, or
    //: o one is zero (positive or negative) and the other is not, or
    //: o one is positive infinity and the other is not, or
    //: o one is negative infinity and the other is not, or
    //: o both have the value of a real number that are not equal, regardless
    //:   of their representation (cohorts are equal)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.
    //
    // Note that a NaN is never equal to anything, including itself:
    //..
    //  Decimal32 aNaN = std::numeric_limits<Decimal32>::quiet_NaN();
    //  assert(aNan != aNan);
    //..

bool operator<(Decimal32 lhs, Decimal32 rhs);
    // Return 'true' if the specified 'lhs' has a value less than the specified
    // 'rhs' and 'false' otherwise.  The value of a 'Decimal32' 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' positive, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' negative, or
    //: o 'lhs' is not positive infinity, or
    //: o 'lhs' is negative infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<=(Decimal32 lhs, Decimal32 rhs);
    // 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
    // 'Decimal32' 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are positive infinity, or
    //: o 'lhs' is negative infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>(Decimal32 lhs, Decimal32 rhs);
    // Return 'true' if the specified 'lhs' has a greater value than the
    // specified 'rhs' and 'false' otherwise.  The value of a 'Decimal32'
    // 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are not both zero (positive or negative), or
    //: o 'lhs' is not negative infinity, or
    //: o 'lhs' is positive infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>=(Decimal32 lhs, Decimal32 rhs);
    // 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 'Decimal32' object 'lhs' is greater or equal to a 'Decimal32' 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are negative infinity, or
    //: o 'lhs' is positive infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

template <class CHARTYPE, class TRAITS>
bsl::basic_istream<CHARTYPE, TRAITS>&
operator>>(bsl::basic_istream<CHARTYPE, TRAITS>& stream, Decimal32& object);
    // Read, into the specified 'object', from the specified input 'stream' an
    // IEEE 32 bit decimal floating-point value as described in the IEEE-754
    // 2008 standard (5.12 Details of conversions between floating point
    // numbers and external character sequences) and return a reference
    // providing modifiable access to 'stream'.  If 'stream' contains a NaN
    // value, it is unspecified if 'object' will receive a quiet or signaling
    // 'Nan'.  If 'stream' is not valid on entry 'stream.good() == false', this
    // operation has no effect other than setting 'stream.fail()' to 'true'.
    // If eof (end-of-file) is found before any non-whitespace characters
    // 'stream.fail()' is set to 'true' and 'object' remains unchanged.  If eof
    // is detected after some characters have been read (and successfully
    // interpreted as part of the textual representation of a floating-point
    // value as specified by IEEE-754) then 'stream.eof()' is set to true.  If
    // the first non-whitespace character sequence is not a valid textual
    // representation of a floating-point value (e.g., 12e or e12 or 1*2) the
    // 'stream.fail()' is set to true and 'object' will remain unchanged.  If a
    // real number value is represented by the character sequence but it is a
    // large positive or negative value that cannot be stored into 'object'
    // then store the value of the macro 'ERANGE' into 'errno' and positive or
    // negative infinity is stored into 'object', respectively.  If a real
    // number value is represented by the character sequence but it is a small
    // positive or negative value that cannot be stored into 'object' then
    // store the value of the macro 'ERANGE' into 'errno' and positive or
    // negative zero is stored into 'object', respectively.  If a real number
    // value is represented by the character sequence but it cannot be stored
    // exactly into 'object', the value is rounded according to the current
    // rounding direction (of the environment) and then stored into 'object'.
    //
    // NOTE: This method does not yet fully support iostream flags or the
    // decimal floating point exception context.

template <class CHARTYPE, class TRAITS>
bsl::basic_ostream<CHARTYPE, TRAITS>&
operator<<(bsl::basic_ostream<CHARTYPE, TRAITS>& stream, Decimal32 object);
    // Write the value of the specified 'object' to the specified output
    // 'stream' in a single line format as described in the IEEE-754 2008
    // standard (5.12 Details of conversions between floating point numbers and
    // external character sequences), and return a reference providing
    // modifiable access to 'stream'.  If 'stream' is not valid on entry, this
    // operation has no effect.
    //
    // NOTE: This method does not yet fully support iostream flags or the
    // decimal floating point exception context.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)  && \
    defined(BSLS_COMPILERFEATURES_SUPPORT_USER_DEFINED_LITERALS)
inline namespace literals {
inline namespace DecimalLiterals {
bdldfp::Decimal32  operator "" _d32 (const char *str);
bdldfp::Decimal32  operator "" _d32 (const char *str, bsl::size_t len);
    // Produce an object of the indicated return type by parsing the specified
    // 'str' having the specified 'len' excluding the terminating null
    // character that represents a floating-point number written in both fixed
    // and scientific notations.  These user-defined literal suffixes can be
    // applied to both numeric and string literals, (i.e., 1.2_d32, "1.2"_d32
    // or "inf"_d32). The resulting decimal object is initialized as follows:
    //
    //: o If 'str' does not represent a floating-point value, then return a
    //:   decimal object of the indicated return type initialized to a NaN.
    //:
    //: o Otherwise if 'str' represents infinity (positive or negative), then
    //:   return a decimal object of the indicated return type initialized to
    //:   infinity value with the same sign.
    //:
    //: o Otherwise if 'str' represents zero (positive or negative), then
    //:   return a decimal object of the indicated return type initialized to
    //:   zero with the same sign.
    //:
    //: o Otherwise if 'str' represents a value that has an absolute value that
    //:   is larger than the maximum value supported by the indicated return
    //:   type, then store the value of the macro 'ERANGE' into 'errno' and
    //:   return a decimal object of the return type initialized to infinity
    //:   with the same sign.
    //:
    //: o Otherwise if 'str' represents a value that has an absolute value that
    //:   is smaller than min value of the indicated return type, then store
    //:   the value of the macro 'ERANGE' into 'errno' and return a decimal
    //:   object of the return type initialized to zero with the same sign.
    //:
    //: o Otherwise if 'str' has a value that is not exactly representable
    //:   using the maximum digit number supported by the indicated return
    //:   type, then return a decimal object of the return type initialized to
    //:   the value represented by 'str' rounded according to the rounding
    //:   direction.
    //:
    //: o Otherwise return a decimal object of the indicated return type
    //:   initialized to the decimal value representation of 'str'.
    //
    // Note that the parsing follows the rules as specified for the 'strtod32'
    // function in section 9.6 of the ISO/EIC TR 247128 C Decimal
    // Floating-Point Technical Report.
    //
    // Also note that the numeric literal version omits the optional leading
    // sign in 'str'.  For example, if the string is -1.2_d32 then the string
    // "1.2" is passed to the one-argument form, not "-1.2", because leading
    // signs are operators, not parts of literals.  On the other hand, the
    // string literal version does not omit leading sign and if the string is
    // "-1.2"_d32 then the string "-1.2" is passed to the two-argument form.
    //
    // Also note that the quantum of the resultant value is affected by the
    // number of decimal places in 'str' string in both numeric and string
    // literal formats starting with the most significand digit and cannot
    // exceed the maximum number of digits necessary to differentiate all
    // values of the indicated return type, for example:
    //
    // '0.015_d32;     "0.015"_d32     =>      15e-3'
    // '1.5_d32;       "1.5"_d32       =>      15e-1'
    // '1.500_d32;     "1.500"d_32     =>    1500e-3'
    // '1.2345678_d32; "1.2345678_d32" => 1234568e-6'

}  // close DecimalLiterals namespace
}  // close literals namespace
#endif

// FREE FUNCTIONS
template <class HASHALG>
void hashAppend(HASHALG& hashAlg, const Decimal32& object);
    // Pass the specified 'object' to the specified 'hashAlg'.  This function
    // integrates with the 'bslh' modular hashing system and effectively
    // provides a 'bsl::hash' specialization for 'Decimal32'.  Note that two
    // objects which have the same value but different representations will
    // hash to the same value.

                            // ====================
                            // class Decimal_Type64
                            // ====================

class Decimal_Type64 {
    // This value-semantic class implements the IEEE-754 64 bit decimal
    // floating-point format arithmetic type.  This class is a standard layout
    // type that is 'const' thread-safe and exception-neutral.

  private:
    // DATA
    DecimalImpUtil::ValueType64 d_value; // The underlying IEEE representation

  public:
    // CLASS METHODS

                                  // Aspects

    static int maxSupportedBdexVersion();
    static int maxSupportedBdexVersion(int versionSelector);
        // Return the maximum valid BDEX format version, as indicated by the
        // specified 'versionSelector', to be passed to the 'bdexStreamOut'
        // method.  Note that it is highly recommended that 'versionSelector'
        // be formatted as "YYYYMMDD", a date representation.  Also note that
        // 'versionSelector' should be a *compile*-time-chosen value that
        // selects a format version supported by both externalizer and
        // unexternalizer.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(Decimal_Type64, bsl::is_trivially_copyable);


    // CREATORS
    Decimal_Type64();
        // Create a 'Decimal64_Type' object having the value positive zero and
        // the smallest exponent value.

    Decimal_Type64(DecimalImpUtil::ValueType64 value);              // IMPLICIT
        // Create a 'Decimal64_Type' object having the specified 'value'.

    Decimal_Type64(Decimal32 other);                                // IMPLICIT
        // Create a 'Decimal64_Type' object having the value of the specified
        // 'other' following the conversion rules as defined by IEEE-754:
        //
        //: o If 'other' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise if 'other' is infinity (positive or negative), then
        //:   initialize this object to infinity with the same sign.
        //:
        //: o Otherwise if 'other' is zero, then initialize this object to zero
        //:   with the same sign.
        //:
        //: o Otherwise initialize this object to the value of the 'other'.

    explicit Decimal_Type64(Decimal128 other);
        // Create a 'Decimal64_Type' object having the value closest to the
        // value of the specified 'other' following the conversion rules as
        // defined by IEEE-754:
        //
        //: o If 'other' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise if 'other' is infinity (positive or negative), then
        //:   initialize this object to infinity with the same sign.
        //:
        //: o Otherwise if 'other' is zero, then initialize this object to
        //:   zero with the same sign.
        //:
        //: o Otherwise if 'other' has an absolute value that is larger than
        //:   'std::numeric_limits<Decimal64>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and initialize this object to
        //:   infinity with the same sign as 'other'.
        //:
        //: o Otherwise if 'other' has an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal64>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and initialize this object to
        //:   zero with the same sign as 'other'.
        //:
        //: o Otherwise if 'other' has a value that has more significant
        //:   digits than 'std::numeric_limits<Decimal64>::max_digit' then
        //:   initialize this object to the value of 'other' rounded according
        //:   to the rounding direction.
        //:
        //: o Otherwise initialize this object to the value as the 'other'.

    explicit Decimal_Type64(float       other);
    explicit Decimal_Type64(double      other);
        // Create a 'Decimal64_Type' object having the value closest to the
        // value of the specified 'other' value.  *Warning:* clients requiring
        // a conversion for an exact decimal value should use
        // 'bdldfp_decimalconvertutil' (see *WARNING*: Conversions from
        // 'float' and 'double'}.  This conversion follows the conversion
        // rules as defined by IEEE-754:
        //
        //: o If 'other' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise if 'other' is infinity (positive or negative), then
        //:   initialize this object to infinity value with the same sign.
        //:
        //: o Otherwise if 'other' has a zero value, then initialize this
        //:   object to zero with the same sign.
        //:
        //: o Otherwise if 'other' has a value that needs more than
        //:   'std::numeric_limits<Decimal64>::max_digit' significant decimal
        //:   digits to represent then initialize this object to the value of
        //:   'other' rounded according to the rounding direction.
        //:
        //: o Otherwise initialize this object to the value of the 'other'.

    explicit Decimal_Type64(int                other);
    explicit Decimal_Type64(unsigned int       other);
    explicit Decimal_Type64(long               other);
    explicit Decimal_Type64(unsigned long      other);
    explicit Decimal_Type64(long long          other);
    explicit Decimal_Type64(unsigned long long other);
        // Create a 'Decimal64_Type' object having the value closest to the
        // value of the specified 'other' following the conversion rules as
        // defined by IEEE-754:
        //
        //: o Otherwise if 'other' has a value that is not exactly
        //:   representable using 'std::numeric_limits<Decimal64>::max_digit'
        //:   decimal digits then initialize this object to the value of
        //:   'other' rounded according to the rounding direction.
        //:
        //: o Otherwise initialize this object to the value of 'other' with
        //:   exponent 0.

    //! Decimal64_Type(const Decimal64_Type& original) = default;
        // Create a 'Decimal64_Type' object that is a copy of the specified
        // 'original' as defined by the 'copy' operation of IEEE-754 2008:
        //
        //: o If 'other' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise initialize this object to the value of the 'other'.
        //
        // Note that since floating-point types may be NaN, and NaNs are
        // unordered (do not compare equal even to themselves) it is possible
        // that a copy of a decimal will not compare equal to the original;
        // however it will behave as the original.

    //! ~Decimal64_Type() = default;
        // Destroy this object.

    // MANIPULATORS
    //! Decimal64_Type& operator=(const Decimal64_Type& rhs) = default;
        // Make this object a copy of the specified 'rhs' as defined by the
        // 'copy' operation of IEEE-754 2008 and return a reference providing
        // modifiable access to this object.
        //
        //: o If 'other' is NaN, set this object to a NaN.
        //:
        //: o Otherwise set this object to the value of the 'other'.
        //
        // Note that since floating-point types may be NaN, and NaNs are
        // unordered (do not compare equal even to themselves) it is possible
        // that, after an assignment, a decimal will not compare equal to the
        // original; however it will behave as the original.

    Decimal_Type64& operator++();
        // Add 1.0 to the value of this object and return a reference to it.
        // Note that this is a floating-point value so this operation may not
        // change the value of this object at all (if the value is large) or it
        // may just set it to 1.0 (if the original value is small).

    Decimal_Type64& operator--();
        // Add -1.0 to the value of this object and return a reference to it.
        // Note that this is a floating-point value so this operation may not
        // change the value of this object at all (if the value is large) or it
        // may just set it to -1.0 (if the original value is small).

    Decimal_Type64& operator+=(Decimal32  rhs);
    Decimal_Type64& operator+=(Decimal64  rhs);
    Decimal_Type64& operator+=(Decimal128 rhs);
        // Add the value of the specified 'rhs' object to the value of this as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinite values of
        //:   differing signs, store the value of the macro 'EDOM' into 'errno'
        //:   and set this object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinite values of the
        //:   same sign, then do not change this object.
        //:
        //: o Otherwise if 'rhs' has a zero value (positive or negative), do
        //:   not change this object.
        //:
        //: o Otherwise if the sum of this object and 'rhs' has an absolute
        //:   value that is larger than 'std::numeric_limits<Decimal64>::max()'
        //:   then store the value of the macro 'ERANGE' into 'errno' and
        //:   set this object to infinity with the same sign as that result.
        //:
        //: o Otherwise set this object to the sum of the number represented by
        //:   'rhs' and the number represented by this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).
        //
        // Note that when 'rhs' is a 'Decimal128', this operation is always
        // performed with 128 bits precision to prevent loss of precision of
        // the 'rhs' operand (prior to the operation).  The result is then
        // rounded back to 64 bits and stored to this object.  See IEEE-754
        // 2008, 5.1, first paragraph, second sentence for specification.

    Decimal_Type64& operator+=(int                rhs);
    Decimal_Type64& operator+=(unsigned int       rhs);
    Decimal_Type64& operator+=(long               rhs);
    Decimal_Type64& operator+=(unsigned long      rhs);
    Decimal_Type64& operator+=(long long          rhs);
    Decimal_Type64& operator+=(unsigned long long rhs);
        // Add the specified 'rhs' to the value of this object as described by
        // IEEE-754, store the result in this object, and return a reference to
        // this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity, then do not change it.
        //:
        //: o Otherwise if the sum of this object and 'rhs' has an absolute
        //:   value that is larger than 'std::numeric_limits<Decimal64>::max()'
        //:   then store the value of the macro 'ERANGE' into 'errno' and
        //:   set this object to infinity with the same sign as that result.
        //:
        //: o Otherwise set this object to sum of adding 'rhs' and the number
        //:   represented by this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).

    Decimal_Type64& operator-=(Decimal32  rhs);
    Decimal_Type64& operator-=(Decimal64  rhs);
    Decimal_Type64& operator-=(Decimal128 rhs);
        // Subtract the value of the specified 'rhs' from the value of this
        // object as described by IEEE-754, store the result in this object,
        // and return a reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinity value of the
        //:   same signs, store the value of the macro 'EDOM' into 'errno'
        //:   and set this object to a NaN.
        //:
        //: o Otherwise if this object and the 'rhs' have infinite values of
        //:   differing signs, then do not change this object.
        //:
        //: o Otherwise if the 'rhs' has a zero value (positive or negative),
        //:   do not change this object.
        //:
        //: o Otherwise if subtracting the value of the 'rhs' object from this
        //:   results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal64>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the result of subtracting the value
        //:   of 'rhs' from the value of this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).
        //
        // Note that when 'rhs' is a 'Decimal128', this operation is always
        // performed with 128 bits precision to prevent loss of precision of
        // the 'rhs' operand (prior to the operation).  The result is then
        // rounded back to 64 bits and stored to this object.  See IEEE-754
        // 2008, 5.1, first paragraph, second sentence for specification.

    Decimal_Type64& operator-=(int                rhs);
    Decimal_Type64& operator-=(unsigned int       rhs);
    Decimal_Type64& operator-=(long               rhs);
    Decimal_Type64& operator-=(unsigned long      rhs);
    Decimal_Type64& operator-=(long long          rhs);
    Decimal_Type64& operator-=(unsigned long long rhs);
        // Subtract the specified 'rhs' from the value of this object as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity, then do not change it.
        //:
        //: o Otherwise if subtracting 'rhs' from this object's value results
        //:   in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal64>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the result of subtracting 'rhs' from
        //:   the value of this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).

    Decimal_Type64& operator*=(Decimal32  rhs);
    Decimal_Type64& operator*=(Decimal64  rhs);
    Decimal_Type64& operator*=(Decimal128 rhs);
        // Multiply the value of the specified 'rhs' object by the value of
        // this as described by IEEE-754, store the result in this object, and
        // return a reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise, if one of this object and 'rhs' is zero (positive or
        //:   negative) and the other is infinity (positive or negative), store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise, if either this object or 'rhs' is positive or negative
        //:   infinity, set this object to infinity.  The sign of this object
        //:   will be positive if this object and 'rhs' had the same sign, and
        //:   negative otherwise.
        //:
        //: o Otherwise, if either this object or 'rhs' is zero, set this
        //:   object to zero.  The sign of this object will be positive if this
        //:   object and 'rhs' had the same sign, and negative otherwise.
        //:
        //: o Otherwise if the product of this object and 'rhs' has an absolute
        //:   value that is larger than 'std::numeric_limits<Decimal64>::max()'
        //:   then store the value of the macro 'ERANGE' into 'errno' and set
        //:   this object to infinity with the same sign of that result.
        //:
        //: o Otherwise if the product of this object and 'rhs' has an absolute
        //:   value that is smaller than
        //:   'std::numeric_limits<Decimal64>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to zero value
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the product of the value of 'rhs'
        //:   and the value of this object.
        //
        // Note that when 'rhs' is a 'Decimal128', this operation is always
        // performed with 128 bits precision to prevent loss of precision of
        // the 'rhs' operand (prior to the operation).  The result is then
        // rounded back to 64 bits and stored to this object.  See IEEE-754
        // 2008, 5.1, first paragraph, second sentence for specification.

    Decimal_Type64& operator*=(int                rhs);
    Decimal_Type64& operator*=(unsigned int       rhs);
    Decimal_Type64& operator*=(long               rhs);
    Decimal_Type64& operator*=(unsigned long      rhs);
    Decimal_Type64& operator*=(long long          rhs);
    Decimal_Type64& operator*=(unsigned long long rhs);
        // Multiply the specified 'rhs' by the value of this object as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity (positive or negative), and
        //:   'rhs' is zero, then store the value of the macro 'EDOM' into
        //:   'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is infinity (positive or negative), then
        //:   do not change it.
        //:
        //: o Otherwise if 'rhs' is zero, then set this object to zero with the
        //:   same sign as its value had prior to this operation.
        //:
        //: o Otherwise if the product of 'rhs' and the value of this object
        //:   results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal64>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise if the product of 'rhs' and the value of this object
        //:   results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal64>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to zero with
        //:   the same sign as that result.

    Decimal_Type64& operator/=(Decimal32  rhs);
    Decimal_Type64& operator/=(Decimal64  rhs);
    Decimal_Type64& operator/=(Decimal128 rhs);
        // Divide the value of this object by the value of the specified 'rhs'
        // as described by IEEE-754, store the result in this object, and
        // return a reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object 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.
        //:
        //: o Otherwise if 'rhs' has a positive zero value, then store the
        //:   value of the macro 'ERANGE' into 'errno' and set this object to
        //:   infinity with the same sign as its original value.
        //:
        //: o Otherwise if 'rhs' has a negative zero value, then store the
        //:   value of the macro 'ERANGE' into 'errno' and set this object to
        //:   infinity with the opposite sign as its original value.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal64>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and return infinity with the same
        //:   sign as that result.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal64>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno'and return zero with the same sign
        //:   as that result.
        //:
        //: o Otherwise set this object to the result of dividing the value of
        //:   this object by the value of 'rhs'.
        //
        // Note that when 'rhs' is a 'Decimal128', this operation is always
        // performed with 128 bits precision to prevent loss of precision of
        // the 'rhs' operand (prior to the operation).  The result is then
        // rounded back to 64 bits and stored to this object.  See IEEE-754
        // 2008, 5.1, first paragraph, second sentence for specification.

    Decimal_Type64& operator/=(int                rhs);
    Decimal_Type64& operator/=(unsigned int       rhs);
    Decimal_Type64& operator/=(long               rhs);
    Decimal_Type64& operator/=(unsigned long      rhs);
    Decimal_Type64& operator/=(long long          rhs);
    Decimal_Type64& operator/=(unsigned long long rhs);
        // Divide the value of this object by the specified 'rhs' as described
        // by IEEE-754, store the result in this object, and return a reference
        // to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN then set this object to a NaN.
        //:
        //: o Otherwise if this object is infinity (positive or negative) and
        //:   'rhs' is positive value then set this object to infinity value
        //:   with the same sign as its original value.
        //:
        //: o Otherwise if this object is infinity (positive or negative) and
        //:   'rhs' is negative value then set this object to infinity value
        //:   with the opposite sign as its original value.
        //:
        //: o Otherwise if 'rhs' is zero, store the value of the macro 'ERANGE'
        //:   into 'errno' and set this object to infinity with the same sign
        //:   it had prior to this operation.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal64>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and return infinity with the same
        //:   sign as that result.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal64>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno'and return zero with the same sign
        //:   as that result.
        //:
        //: o Otherwise set this object to the result of dividing the value of
        //:   this object by the value of 'rhs'.

    DecimalImpUtil::ValueType64 *data();
        // Return a modifiable pointer to the underlying implementation.

                                  // Aspects

    template <class STREAM>
    STREAM& bdexStreamIn(STREAM& stream, int version);
        // Assign to this object the value read from the specified input
        // 'stream' using the specified 'version' format, and return a
        // reference to 'stream'.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'version' is not supported, this object
        // is unaltered and 'stream' is invalidated, but otherwise unmodified.
        // If 'version' is supported but 'stream' becomes invalid during this
        // operation, this object has an undefined, but valid, state.  Note
        // that no version is read from 'stream'.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    // ACCESSORS
    const DecimalImpUtil::ValueType64 *data() const;
        // Return a non-modifiable pointer to the underlying implementation.

    DecimalImpUtil::ValueType64 value() const;
        // Return the value of the underlying implementation.

                                  // Aspects

    template <class STREAM>
    STREAM& bdexStreamOut(STREAM& stream, int version) const;
        // Write the value of this object, using the specified 'version'
        // format, to the specified output 'stream', and return a reference to
        // 'stream'.  If 'stream' is initially invalid, this operation has no
        // effect.  If 'version' is not supported, 'stream' is invalidated, but
        // otherwise unmodified.  Note that 'version' is not written to
        // 'stream'.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

    bsl::ostream& print(bsl::ostream& stream,
                        int           level = 0,
                        int           spacesPerLevel = 4) const;
        // Write the value of this object to the specified output 'stream' in a
        // human-readable format, and return a reference to 'stream'.
        // Optionally specify an initial indentation 'level', whose absolute
        // value is incremented recursively for nested objects.  If 'level' is
        // specified, optionally specify 'spacesPerLevel', whose absolute value
        // indicates the number of spaces per indentation level for this and
        // all of its nested objects.  If 'level' is negative, suppress
        // indentation of the first line.  If 'spacesPerLevel' is negative,
        // format the entire output on one line, suppressing all but the
        // initial indentation (as governed by 'level').  If 'stream' is not
        // valid on entry, this operation has no effect.  Note that this
        // human-readable format is not fully specified, and can change without
        // notice.
};

// FREE OPERATORS
Decimal64 operator+(Decimal64 value);
    // Return a copy of the specified 'value'.

Decimal64 operator-(Decimal64 value);
    // 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'.

Decimal64 operator++(Decimal64& value, int);
    // Apply the prefix ++ operator to the specified 'value' and return its
    // original value.  Note that this is a floating-point value so this
    // operations may not change the value of this object at all (if the value
    // is large) or it may just set it to 1.0 (if the original value is small).

Decimal64 operator--(Decimal64& value, int);
    // Apply the prefix -- operator to the specified 'value' and return its
    // original value.  Note that this is a floating-point value so this
    // operations may not change the value of this object at all (if the value
    // is large) or it may just set it to -1.0 (if the original value is
    // small).

Decimal64 operator+(Decimal64 lhs, Decimal64 rhs);
Decimal64 operator+(Decimal32 lhs, Decimal64 rhs);
Decimal64 operator+(Decimal64 lhs, Decimal32 rhs);
    // Add the value of the specified 'rhs' to the value of the specified 'lhs'
    // as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o Otherwise if 'lhs' and 'rhs' are infinities of differing signs, store
    //:   the value of the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' and 'rhs' are infinities of the same sign then
    //:   return infinity of that sign.
    //:
    //: o Otherwise if 'rhs' is zero (positive or negative), return 'lhs'.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' has an absolute value that is
    //:   larger than 'std::numeric_limits<Decimal64>::max()' then store the
    //:   value of the macro 'ERANGE' into 'errno' and set this object to
    //:   infinity with the same sign as that result.
    //:
    //: o Otherwise return the sum of the number represented by 'lhs' and the
    //:   number represented by 'rhs'.

Decimal64 operator+(Decimal64 lhs, int                rhs);
Decimal64 operator+(Decimal64 lhs, unsigned int       rhs);
Decimal64 operator+(Decimal64 lhs, long               rhs);
Decimal64 operator+(Decimal64 lhs, unsigned long      rhs);
Decimal64 operator+(Decimal64 lhs, long long          rhs);
Decimal64 operator+(Decimal64 lhs, unsigned long long rhs);
    // Add the specified 'rhs' to the value of the specified 'lhs' as described
    // by IEEE-754 and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' object is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity, then return infinity.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' has an absolute value that is
    //:   larger than 'std::numeric_limits<Decimal64>::max()' then store the
    //:   value of the macro 'ERANGE' into 'errno' and return infinity with the
    //:   same sign as that result.
    //:
    //: o Otherwise return the sum of 'rhs' and the number represented by
    //:   'lhs'.

Decimal64 operator+(int                lhs, Decimal64 rhs);
Decimal64 operator+(unsigned int       lhs, Decimal64 rhs);
Decimal64 operator+(long               lhs, Decimal64 rhs);
Decimal64 operator+(unsigned long      lhs, Decimal64 rhs);
Decimal64 operator+(long long          lhs, Decimal64 rhs);
Decimal64 operator+(unsigned long long lhs, Decimal64 rhs);
    // Add the specified 'lhs' to the value of the specified 'rhs' as described
    // by IEEE-754 and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' object is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity, then return infinity.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' has an absolute value that is
    //:   larger than 'std::numeric_limits<Decimal64>::max()' then store the
    //:   value of the macro 'ERANGE' into 'errno' and return infinity with the
    //:   same sign as that result.
    //:
    //: o Otherwise return the sum of 'lhs' and the number represented by
    //:   'rhs'.

Decimal64 operator-(Decimal64 lhs, Decimal64 rhs);
Decimal64 operator-(Decimal32 lhs, Decimal64 rhs);
Decimal64 operator-(Decimal64 lhs, Decimal32 rhs);
    // Subtract the value of the specified 'rhs' from the value of the
    // specified 'lhs' as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o Otherwise if 'lhs' and the 'rhs' have infinity values of differing
    //:   signs, then return 'lhs'.
    //:
    //: o Otherwise if the subtracting of 'lhs' and 'rhs' has an absolute value
    //:   that is larger than 'std::numeric_limits<Decimal64>::max()' then
    //:   store the value of the macro 'ERANGE' into 'errno' and return
    //:   infinity with the same sign as that result.
    //:
    //: o Otherwise return the result of subtracting the value of 'rhs'from the
    //:   value of 'lhs'.

Decimal64 operator-(Decimal64 lhs, int                rhs);
Decimal64 operator-(Decimal64 lhs, unsigned int       rhs);
Decimal64 operator-(Decimal64 lhs, long               rhs);
Decimal64 operator-(Decimal64 lhs, unsigned long      rhs);
Decimal64 operator-(Decimal64 lhs, long long          rhs);
Decimal64 operator-(Decimal64 lhs, unsigned long long rhs);
    // Subtract the specified 'rhs' from the value of the specified 'lhs' as
    // described by IEEE-754 and return a reference to this object.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity, then return infinity.
    //:
    //: o Otherwise if subtracting 'rhs' from 'lhs' object's value results in
    //:   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
    //:   that result.
    //:
    //: o Otherwise return the result of subtracting 'rhs' from the value of
    //:   'lhs'.

Decimal64 operator-(int                lhs, Decimal64 rhs);
Decimal64 operator-(unsigned int       lhs, Decimal64 rhs);
Decimal64 operator-(long               lhs, Decimal64 rhs);
Decimal64 operator-(unsigned long      lhs, Decimal64 rhs);
Decimal64 operator-(long long          lhs, Decimal64 rhs);
Decimal64 operator-(unsigned long long lhs, Decimal64 rhs);
    // Subtract the specified 'rhs' from the value of the specified 'lhs' as
    // described by IEEE-754 and return a reference to this object.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity, then return infinity.
    //:
    //: o Otherwise if subtracting 'rhs' from 'lhs' object's value results in
    //:   an absolute value that is larger than
    //:   'std::numeric_limits<Decimal64>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of subtracting the value of 'rhs' from
    //:   the number 'lhs'.

Decimal64 operator*(Decimal64 lhs, Decimal64 rhs);
Decimal64 operator*(Decimal32 lhs, Decimal64 rhs);
Decimal64 operator*(Decimal64 lhs, Decimal32 rhs);
    // Multiply the value of the specified 'lhs' object by the value of the
    // specified 'rhs' as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o 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.
    //:
    //: o 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.
    //:
    //: o Otherwise if the product of 'lhs' and 'rhs' has an absolute value
    //:   that is larger than 'std::numeric_limits<Decimal64>::max()' then
    //:   store the value of the macro 'ERANGE' into 'errno' and return an
    //:   infinity with the same sign as that result.
    //:
    //: o Otherwise if the product of 'lhs' and 'rhs' has an absolute value
    //:   that is smaller than 'std::numeric_limits<Decimal64>::min()' then
    //:   store the value of the macro 'ERANGE' into 'errno' and return zero
    //:   with the same sign as that result.
    //:
    //: o Otherwise return the product of the value of 'rhs' and the number
    //:   represented by 'rhs'.

Decimal64 operator*(Decimal64 lhs, int                rhs);
Decimal64 operator*(Decimal64 lhs, unsigned int       rhs);
Decimal64 operator*(Decimal64 lhs, long               rhs);
Decimal64 operator*(Decimal64 lhs, unsigned long      rhs);
Decimal64 operator*(Decimal64 lhs, long long          rhs);
Decimal64 operator*(Decimal64 lhs, unsigned long long rhs);
    // Multiply the specified 'rhs' by the value of the specified 'lhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative), and 'rhs' is
    //:   zero, then store the value of the macro 'EDOM' into'errno' and return
    //:   a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative), then return
    //:   'lhs'.
    //:
    //: o Otherwise if 'rhs' is zero, then return zero with the sign of 'lhs'.
    //:
    //: o Otherwise if the product of 'rhs' and the value of 'lhs' results in
    //:   an absolute value that is larger than
    //:   'std::numeric_limits<Decimal64>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if the product of 'rhs' and the value of 'lhs' results in
    //:   an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal64>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the product of the value of 'lhs' and value 'rhs'.

Decimal64 operator*(int                lhs, Decimal64 rhs);
Decimal64 operator*(unsigned int       lhs, Decimal64 rhs);
Decimal64 operator*(long               lhs, Decimal64 rhs);
Decimal64 operator*(unsigned long      lhs, Decimal64 rhs);
Decimal64 operator*(long long          lhs, Decimal64 rhs);
Decimal64 operator*(unsigned long long lhs, Decimal64 rhs);
    // Multiply the specified 'lhs' by the value of the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), and 'lhs' is
    //:   zero, then store the value of the macro 'EDOM' into'errno' and return
    //:   a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), then return
    //:   'rhs'.
    //:
    //: o Otherwise if 'lhs' is zero, then return zero with the sign of 'rhs'.
    //:
    //: o Otherwise if the product of 'lhs' and the value of 'rhs' results in
    //:   an absolute value that is larger than
    //:   'std::numeric_limits<Decimal64>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if the product of 'lhs' and the value of 'rhs' results in
    //:   an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal64>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the product of the value of 'lhs' and value 'rhs'.

Decimal64 operator/(Decimal64 lhs, Decimal64 rhs);
Decimal64 operator/(Decimal32 lhs, Decimal64 rhs);
Decimal64 operator/(Decimal64 lhs, Decimal32 rhs);
    // Divide the value of the specified 'lhs' by the value of the specified
    // 'rhs' as described by IEEE-754, and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o 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'.
    //:
    //: o 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'.
    //:
    //: o Otherwise if 'lhs' has infinity value and 'rhs' has a positive zero
    //:   value, return infinity with the sign of 'lhs'.
    //:
    //: o Otherwise if 'lhs' has infinity value and 'rhs' has a negative zero
    //:   value, return infinity with the opposite sign as 'lhs'.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is larger than
    //:   'std::numeric_limits<Decimal64>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal64>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value of 'rhs'.

Decimal64 operator/(Decimal64 lhs, int                rhs);
Decimal64 operator/(Decimal64 lhs, unsigned int       rhs);
Decimal64 operator/(Decimal64 lhs, long               rhs);
Decimal64 operator/(Decimal64 lhs, unsigned long      rhs);
Decimal64 operator/(Decimal64 lhs, long long          rhs);
Decimal64 operator/(Decimal64 lhs, unsigned long long rhs);
    // Divide the value of the specified 'lhs' by the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative) and 'rhs' is
    //:   positive value then return infinity value with the same sign as its
    //:   original value.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative) and 'rhs' is
    //:   negative value then return infinity value with the opposite sign as
    //:   its original value.
    //:
    //: o Otherwise if 'rhs' is zero, store the value of the macro 'ERANGE'
    //:   into 'errno' and return infinity with the same sign it had prior to
    //:   this operation.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is larger than
    //:   'std::numeric_limits<Decimal64>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal64>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value 'rhs'.

Decimal64 operator/(int                lhs, Decimal64 rhs);
Decimal64 operator/(unsigned int       lhs, Decimal64 rhs);
Decimal64 operator/(long               lhs, Decimal64 rhs);
Decimal64 operator/(unsigned long      lhs, Decimal64 rhs);
Decimal64 operator/(long long          lhs, Decimal64 rhs);
Decimal64 operator/(unsigned long long lhs, Decimal64 rhs);
    // Divide the specified 'lhs' by the value of the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), and 'lhs' is
    //:   zero, store the value of the macro 'ERANGE' into 'errno' and return a
    //:   NaN.
    //:
    //: o Otherwise if 'rhs' is zero (positive or negative), store the value of
    //:   the macro 'ERANGE' into 'errno' and return infinity with the sign of
    //:   'lhs'.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is larger than
    //:   'std::numeric_limits<Decimal64>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal64>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value of 'rhs'.  Note that this is a floating-point operation, not
    //:   integer.

bool operator==(Decimal64 lhs, Decimal64 rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and
    // 'false' otherwise.  Two 'Decimal64' 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 'Decimal64' objects have the same value if:
    //
    //: o both have a zero value (positive or negative), or
    //: o both have the same infinity value (both positive or negative), or
    //: o both have the value of a real number that are equal, even if they are
    //:   represented differently (cohorts have the same value)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.
    //
    // Note that a NaN is never equal to anything, including itself:
    //..
    //  Decimal64 aNaN = std::numeric_limits<Decimal64>::quiet_NaN();
    //  assert(!(aNan == aNan));
    //..

bool operator==(Decimal32 lhs, Decimal64 rhs);
bool operator==(Decimal64 lhs, Decimal32 rhs);
    // 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:
    //
    //: o both have a zero value (positive or negative), or
    //: o both have the same infinity value (both positive or negative), or
    //: o both have the value of a real number that are equal, even if they are
    //:   represented differently (cohorts have the same value)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator!=(Decimal64 lhs, Decimal64 rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' do not have the same
    // value, and 'false' otherwise.  Two 'Decimal64' objects do not have the
    // same value if the 'compareQuietEqual' operation (IEEE-754 defined,
    // non-total ordering comparison) considers the underlying IEEE
    // representations not equal.  In other words, two 'Decimal64' objects do
    // not have the same value if:
    //
    //: o both are a NaN, or
    //: o one has zero value (positive or negative) and the other does not, or
    //: o one has the value of positive infinity and the other does not, or
    //: o one has the value of negative infinity and the other does not, or
    //: o both have the value of a real number that are not equal, regardless
    //:   of their representation (cohorts are equal)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.
    //
    // Note that a NaN is never equal to anything, including itself:
    //..
    //  Decimal64 aNaN = std::numeric_limits<Decimal64>::quiet_NaN();
    //  assert(aNan != aNan);
    //..

bool operator!=(Decimal32 lhs, Decimal64 rhs);
bool operator!=(Decimal64 lhs, Decimal32 rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' do not have the same
    // value, and 'false' otherwise.  Two decimal objects do not have the same
    // value if the 'compareQuietEqual' operation (IEEE-754 defined, non-total
    // ordering comparison) considers the underlying IEEE representations not
    // equal.  In other words, two decimal objects do not have the same value
    // if:
    //
    //: o both are NaN, or
    //: o one has zero value (positive or negative) and the other does not, or
    //: o one has the value of positive infinity and the other does not, or
    //: o one has the value of negative infinity and the other does not, or
    //: o both have the value of a real number that are not equal, regardless
    //:   of their representation (cohorts are equal)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<(Decimal64 lhs, Decimal64 rhs);
    // 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' is positive, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' negative, or
    //: o 'lhs' is not positive infinity, or
    //: o 'lhs' is negative infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<(Decimal32 lhs, Decimal64 rhs);
bool operator<(Decimal64 lhs, Decimal32 rhs);
    // Return 'true' if the specified 'lhs' has a value less than the specified
    // 'rhs' and 'false' otherwise.  The value of a decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' is positive, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' negative, or
    //: o 'lhs' is not positive infinity, or
    //: o 'lhs' is negative infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<=(Decimal64 lhs, Decimal64 rhs);
    // 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are positive infinity, or
    //: o 'lhs' is negative infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<=(Decimal32 lhs, Decimal64 rhs);
bool operator<=(Decimal64 lhs, Decimal32 rhs);
    // 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
    // decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are positive infinity, or
    //: o 'lhs' is negative infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>(Decimal64 lhs, Decimal64 rhs);
    // 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' positive, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' negative, or
    //: o 'lhs' is not negative infinity, or
    //: o 'lhs' is positive infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>(Decimal32 lhs, Decimal64 rhs);
bool operator>(Decimal64 lhs, Decimal32 rhs);
    // Return 'true' if the specified 'lhs' has a greater value than the
    // specified 'rhs' and 'false' otherwise.  The value of a decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' positive, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' negative, or
    //: o 'lhs' is not negative infinity, or
    //: o 'lhs' is positive infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>=(Decimal64 lhs, Decimal64 rhs);
    // 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are negative infinity, or
    //: o 'lhs' is positive infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>=(Decimal32 lhs, Decimal64 rhs);
bool operator>=(Decimal64 lhs, Decimal32 rhs);
    // 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 decimal object 'lhs' is greater or equal to a decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are negative infinity, or
    //: o 'lhs' is positive infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

template <class CHARTYPE, class TRAITS>
bsl::basic_istream<CHARTYPE, TRAITS>&
operator>> (bsl::basic_istream<CHARTYPE, TRAITS>& stream, Decimal64& object);
    // Read, into the specified 'object', from the specified input 'stream' an
    // IEEE 64 bit decimal floating-point value as described in the IEEE-754
    // 2008 standard (5.12 Details of conversions between floating point
    // numbers and external character sequences) and return a reference
    // providing modifiable access to 'stream'.  If 'stream' contains a Nan
    // value, it is unspecified if 'object' will receive a quiet or signaling
    // 'Nan'.  If 'stream' is not valid on entry 'stream.good() == false', this
    // operation has no effect other than setting 'stream.fail()' to 'true'.
    // If eof (end-of-file) is found before any non-whitespace characters
    // 'stream.fail()' is set to 'true' and 'object' remains unchanged.  If eof
    // is detected after some characters have been read (and successfully
    // interpreted as part of the textual representation of a floating-point
    // value as specified by IEEE-754) then 'stream.eof()' is set to true.  If
    // the first non-whitespace character sequence is not a valid textual
    // representation of a floating-point value (e.g., 12e or e12 or 1*2) the
    // 'stream.fail()' is set to true and 'object' will remain unchanged.  If a
    // real number value is represented by the character sequence but it is a
    // large positive or negative value that cannot be stored into 'object'
    // then store the value of the macro 'ERANGE' into 'errno' and positive or
    // negative infinity is stored into 'object', respectively.  If a real
    // number value is represented by the character sequence but it is a small
    // positive or negative value that cannot be stored into 'object' then
    // store the value of the macro 'ERANGE' into 'errno' and positive or
    // negative zero is stored into 'object', respectively.  If a real number
    // value is represented by the character sequence but it cannot be stored
    // exactly into 'object', the value is rounded according to the current
    // rounding direction (of the environment) and then stored into 'object'.
    //
    // NOTE: This method does not yet fully support iostream flags or the
    // decimal floating point exception context.

template <class CHARTYPE, class TRAITS>
bsl::basic_ostream<CHARTYPE, TRAITS>&
operator<< (bsl::basic_ostream<CHARTYPE, TRAITS>& stream, Decimal64 object);
    // Write the value of the specified 'object' to the specified output
    // 'stream' in a single line format as described in the IEEE-754 2008
    // standard (5.12 Details of conversions between floating point numbers and
    // external character sequences), and return a reference providing
    // modifiable access to 'stream'.  If 'stream' is not valid on entry, this
    // operation has no effect.
    //
    // NOTE: This method does not yet fully support iostream flags or the
    // decimal floating point exception context.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)  && \
    defined(BSLS_COMPILERFEATURES_SUPPORT_USER_DEFINED_LITERALS)
inline namespace literals {
inline namespace DecimalLiterals {
bdldfp::Decimal64  operator "" _d64 (const char *str);
bdldfp::Decimal64  operator "" _d64 (const char *str, bsl::size_t len);
    // Produce an object of the indicated return type by parsing the specified
    // 'str' having the specified 'len' excluding the terminating null
    // character that represents a floating-point number written in both fixed
    // and scientific notations.  These user-defined literal suffixes can be
    // applied to both numeric and string literals, (i.e., 1.2_d128, "1.2"_d64
    // or "inf"_d64). The resulting decimal object is initialized as follows:
    //
    //: o If 'str' does not represent a floating-point value, then return a
    //:   decimal object of the indicated return type initialized to a NaN.
    //:
    //: o Otherwise if 'str' represents infinity (positive or negative), then
    //:   return a decimal object of the indicated return type initialized to
    //:   infinity value with the same sign.
    //:
    //: o Otherwise if 'str' represents zero (positive or negative), then
    //:   return a decimal object of the indicated return type initialized to
    //:   zero with the same sign.
    //:
    //: o Otherwise if 'str' represents a value that has an absolute value that
    //:   is larger than the maximum value supported by the indicated return
    //:   type, then store the value of the macro 'ERANGE' into 'errno' and
    //:   return a decimal object of the return type initialized to infinity
    //:   with the same sign.
    //:
    //: o Otherwise if 'str' represents a value that has an absolute value that
    //:   is smaller than min value of the indicated return type, then store
    //:   the value of the macro 'ERANGE' into 'errno' and return a decimal
    //:   object of the return type initialized to zero with the same sign.
    //:
    //: o Otherwise if 'str' has a value that is not exactly representable
    //:   using the maximum digit number supported by the indicated return
    //:   type, then return a decimal object of the return type initialized to
    //:   the value represented by 'str' rounded according to the rounding
    //:   direction.
    //:
    //: o Otherwise return a decimal object of the indicated return type
    //:   initialized to the decimal value representation of 'str'.
    //
    // Note that the parsing follows the rules as specified for the 'strtod64'
    // function in section 9.6 of the ISO/EIC TR 247128 C Decimal
    // Floating-Point Technical Report.
    //
    // Also note that the numeric literal version omits the optional leading
    // sign in 'str'.  For example, if the string is -1.2_d64 then the string
    // "1.2" is passed to the one-argument form, not "-1.2", because leading
    // signs are operators, not parts of literals.  On the other hand, the
    // string literal version does not omit leading sign and if the string is
    // "-1.2"_d64 then the string "-1.2" is passed to the two-argument form.
    //
    // Also note that the quantum of the resultant value is affected by the
    // number of decimal places in 'str' string in both numeric and string
    // literal formats starting with the most significand digit and cannot
    // exceed the maximum number of digits necessary to differentiate all
    // values of the indicated return type, for example:
    //
    // '0.015_d64;               =>              15e-3'
    // '1.5_d64;                 =>              15e-1'
    // '1.500_d64;               =>            1500e-3'
    // '1.2345678901234567_d64;  => 1234567890123458-15'

}  // close DecimalLiterals namespace
}  // close literals namespace
#endif

// FREE FUNCTIONS
template <class HASHALG>
void hashAppend(HASHALG& hashAlg, const Decimal64& object);
    // Pass the specified 'object' to the specified 'hashAlg'.  This function
    // integrates with the 'bslh' modular hashing system and effectively
    // provides a 'bsl::hash' specialization for 'Decimal64'.  Note that two
    // objects which have the same value but different representations will
    // hash to the same value.


                           // =====================
                           // class Decimal_Type128
                           // =====================

class Decimal_Type128 {
    // This value-semantic class implements the IEEE-754 128 bit decimal
    // floating-point format arithmetic type.  This class is a standard layout
    // type that is 'const' thread-safe and exception-neutral.

  private:
    // DATA
    DecimalImpUtil::ValueType128 d_value;
                                          // The underlying IEEE representation

  public:
    // CLASS METHODS

                                  // Aspects

    static int maxSupportedBdexVersion();
    static int maxSupportedBdexVersion(int versionSelector);
        // Return the maximum valid BDEX format version, as indicated by the
        // specified 'versionSelector', to be passed to the 'bdexStreamOut'
        // method.  Note that it is highly recommended that 'versionSelector'
        // be formatted as "YYYYMMDD", a date representation.  Also note that
        // 'versionSelector' should be a *compile*-time-chosen value that
        // selects a format version supported by both externalizer and
        // unexternalizer.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.

    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(Decimal_Type128,
                                   bsl::is_trivially_copyable);

    // CREATORS
    Decimal_Type128();
        // Create a 'Decimal128_Type' object having the value positive zero and
        // the smallest exponent value.

    Decimal_Type128(DecimalImpUtil::ValueType128 value);            // IMPLICIT
        // Create a 'Decimal128_Type' object having the specified 'value'.

    Decimal_Type128(Decimal32 value);                               // IMPLICIT
    Decimal_Type128(Decimal64 value);                               // IMPLICIT
        // Create a 'Decimal128_Type' object having the specified 'value',
        // subject to the conversion rules as defined by IEEE-754:
        //
        //: o If 'value' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise if 'value' is infinity, then initialize this object to
        //:   infinity with the same sign.
        //:
        //: o Otherwise if 'value' is zero, then initialize this object to zero
        //:   with the same sign.
        //:
        //: o Otherwise initialize this object to 'value'.

    explicit Decimal_Type128(float  other);
    explicit Decimal_Type128(double other);
        // Create a 'Decimal128_Type' object having the value closest to the
        // specified 'other' value.  *Warning:* clients requiring a conversion
        // for an exact decimal value should use 'bdldfp_decimalconvertutil'
        // (see *WARNING*: Conversions from 'float' and 'double'}.  This
        // conversion follows the conversion rules as defined by IEEE-754:
        //
        //: o If 'value' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise if 'value' is infinity, then initialize this object to
        //:   infinity value with the same sign.
        //:
        //: o Otherwise if 'value' has a zero value, then initialize this
        //:   object to zero with the same sign.
        //:
        //: o Otherwise initialize this object to 'value'.

    explicit Decimal_Type128(int                value);
    explicit Decimal_Type128(unsigned int       value);
    explicit Decimal_Type128(long               value);
    explicit Decimal_Type128(unsigned long      value);
    explicit Decimal_Type128(long long          value);
    explicit Decimal_Type128(unsigned long long value);
        // Create a 'Decimal128_Type' object having the value closest to the
        // specified 'value' subject to the conversion rules as defined by
        // IEEE-754:
        //
        //: o If 'value' has an absolute value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and initialize this object to
        //:   infinity with the same sign as 'other'.
        //:
        //: o Otherwise if 'value' has a value that is not exactly
        //:   representable using 'std::numeric_limits<Decimal128>::max_digit'
        //:   decimal digits then initialize this object to the value of
        //:   'value' rounded according to the rounding direction.
        //:
        //: o Otherwise initialize this object to 'value' with exponent 0.

    //! Decimal128_Type(const Decimal128_Type& original) = default;
        // Create a 'Decimal128_Type' object that is a copy of the specified
        // 'original' as defined by the 'copy' operation of IEEE-754 2008:
        //
        //: o If 'original' is NaN, initialize this object to a NaN.
        //:
        //: o Otherwise initialize this object to the value of the 'original'.
        //
        // Note that since floating-point types may be NaN, and NaNs are
        // unordered (do not compare equal even to themselves) it is possible
        // that a copy of a decimal will not compare equal to the original;
        // however it will behave as the original.

    //! ~Decimal128_Type() = default;
        // Destroy this object.

    // MANIPULATORS
    //! Decimal128_Type& operator=(const Decimal128_Type& rhs) = default;
        // Make this object a copy of the specified 'rhs' as defined by the
        // 'copy' operation of IEEE-754 2008 and return a reference providing
        // modifiable access to this object.
        //
        //: o If 'rhs' is NaN, set this object to a NaN.
        //:
        //: o Otherwise set this object to the value of the 'other'.
        //
        // Note that since floating-point types may be NaN, and NaNs are
        // unordered (do not compare equal even to themselves) it is possible
        // that, after an assignment, a decimal will not compare equal to the
        // original; however it will behave as the original.

    Decimal_Type128& operator++();
        // Add 1.0 to the value of this object and return a reference to it.
        // Note that this is a floating-point value so this operation may not
        // change the value of this object at all (if the value is large) or it
        // may just set it to 1.0 (if the original value is small).

    Decimal_Type128& operator--();
        // Add -1.0 to the value of this object and return a reference to it.
        // Note that this is a floating-point value so this operation may not
        // change the value of this object at all (if the value is large) or it
        // may just set it to -1.0 (if the original value is small).

    Decimal_Type128& operator+=(Decimal32  rhs);
    Decimal_Type128& operator+=(Decimal64  rhs);
    Decimal_Type128& operator+=(Decimal128 rhs);
        // Add the value of the specified 'rhs' object to the value of this as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinity value of
        //:   differing signs, store the value of the macro 'EDOM' into 'errno'
        //:   and set this object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinite values of the
        //:   same sign, then do not change this object.
        //:
        //: o Otherwise if 'rhs' has a zero value (positive or negative), do
        //:   not change this object.
        //:
        //: o Otherwise if the sum of this object and 'rhs' has an absolute
        //:   value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the sum of the number represented by
        //:   'rhs' and the number represented by this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).

    Decimal_Type128& operator+=(int                rhs);
    Decimal_Type128& operator+=(unsigned int       rhs);
    Decimal_Type128& operator+=(long               rhs);
    Decimal_Type128& operator+=(unsigned long      rhs);
    Decimal_Type128& operator+=(long long          rhs);
    Decimal_Type128& operator+=(unsigned long long rhs);
        // Add the specified 'rhs' to the value of this object as described by
        // IEEE-754, store the result in this object, and return a reference to
        // this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity, then do not change it.
        //:
        //: o Otherwise if the sum of this object and 'rhs' has an absolute
        //:   value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to sum of adding 'rhs' and the number
        //:   represented by this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).

    Decimal_Type128& operator-=(Decimal32  rhs);
    Decimal_Type128& operator-=(Decimal64  rhs);
    Decimal_Type128& operator-=(Decimal128 rhs);
        // Subtract the value of the specified 'rhs' from the value of this
        // object as described by IEEE-754, store the result in this object,
        // and return a reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object and 'rhs' have infinity value of the
        //:   same signs, store the value of the macro 'EDOM' into 'errno'
        //:   and set this object to a NaN.
        //:
        //: o Otherwise if this object and the 'rhs' have infinite values of
        //:   differing signs, then do not change this object.
        //:
        //: o Otherwise if the 'rhs' has a zero value (positive or negative),
        //:   do not change this object.
        //:
        //: o Otherwise if subtracting the value of the 'rhs' object from this
        //:   results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the result of subtracting the value
        //:   of 'rhs' from the value of this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).

    Decimal_Type128& operator-=(int                rhs);
    Decimal_Type128& operator-=(unsigned int       rhs);
    Decimal_Type128& operator-=(long               rhs);
    Decimal_Type128& operator-=(unsigned long      rhs);
    Decimal_Type128& operator-=(long long          rhs);
    Decimal_Type128& operator-=(unsigned long long rhs);
        // Subtract the specified 'rhs' from the value of this object as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity, then do not change it.
        //:
        //: o Otherwise if subtracting 'rhs' from this object's value results
        //:   in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the result of subtracting 'rhs' from
        //:   the value of this object.
        //
        // Note that this is a floating-point value so this operations may not
        // change the value of this object at all (if the value is large) or it
        // may seem to update it to the value of the 'other' (if the original
        // value is small).

    Decimal_Type128& operator*=(Decimal32  rhs);
    Decimal_Type128& operator*=(Decimal64  rhs);
    Decimal_Type128& operator*=(Decimal128 rhs);
        // Multiply the value of the specified 'rhs' object by the value of
        // this as described by IEEE-754, store the result in this object, and
        // return a reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise, if one of this object and 'rhs' is zero (positive or
        //:   negative) and the other is infinity (positive or negative), store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise, if either this object or 'rhs' is positive or negative
        //:   infinity, set this object to infinity.  The sign of this object
        //:   will be positive if this object and 'rhs' had the same sign, and
        //:   negative otherwise.
        //:
        //: o Otherwise, if either this object or 'rhs' is zero, set this
        //:   object to zero.  The sign of this object will be positive if this
        //:   object and 'rhs' had the same sign, and negative otherwise.
        //:
        //: o Otherwise if the product of this object and 'rhs' has an absolute
        //:   value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign of that result.
        //:
        //: o Otherwise if the product of this object and 'rhs' has an absolute
        //:   value that is smaller than
        //:   'std::numeric_limits<Decimal128>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to zero value
        //:   with the same sign as that result.
        //:
        //: o Otherwise set this object to the product of the value of 'rhs'
        //:   and the value of this object.

    Decimal_Type128& operator*=(int                rhs);
    Decimal_Type128& operator*=(unsigned int       rhs);
    Decimal_Type128& operator*=(long               rhs);
    Decimal_Type128& operator*=(unsigned long      rhs);
    Decimal_Type128& operator*=(long long          rhs);
    Decimal_Type128& operator*=(unsigned long long rhs);
        // Multiply the specified 'rhs' by the value of this object as
        // described by IEEE-754, store the result in this object, and return a
        // reference to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN, then do not change this object.
        //:
        //: o Otherwise if this object is infinity (positive or negative), and
        //:   'rhs' is zero, then store the value of the macro 'EDOM' into
        //:   'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is infinity (positive or negative), then
        //:   do not change it.
        //:
        //: o Otherwise if 'rhs' is zero, then set this object to zero with the
        //:   same sign as its value had prior to this operation.
        //:
        //: o Otherwise if the product of 'rhs' and the value of this object
        //:   results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to infinity
        //:   with the same sign as that result.
        //:
        //: o Otherwise if the product of 'rhs' and the value of this object
        //:   results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal128>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and set this object to zero with
        //:   the same sign as that result.
        //:
        //: o Otherwise set this object to the product of the value of this
        //:   object and the value 'rhs'.

    Decimal_Type128& operator/=(Decimal32  rhs);
    Decimal_Type128& operator/=(Decimal64  rhs);
    Decimal_Type128& operator/=(Decimal128 rhs);
        // Divide the value of this object by the value of the specified 'rhs'
        // as described by IEEE-754, store the result in this object, and
        // return a reference to this object.
        //
        //: o If either of this object or 'rhs' is signaling NaN, then store
        //:   the value of the macro 'EDOM' into 'errno' and set this object to
        //:   a NaN.
        //:
        //: o Otherwise if either of this object or 'rhs' is NaN then set this
        //:   object to a NaN.
        //:
        //: o Otherwise if this object 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.
        //:
        //: o Otherwise if 'rhs' has a positive zero value, then store the
        //:   value of the macro 'ERANGE' into 'errno' and set this object to
        //:   infinity with the same sign as its original value.
        //:
        //: o Otherwise if 'rhs' has a negative zero value, then store the
        //:   value of the macro 'ERANGE' into 'errno' and set this object to
        //:   infinity with the opposite sign as its original value.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and return infinity with the same
        //:   sign as that result.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal128>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno'and return zero with the same sign
        //:   as that result.
        //:
        //: o Otherwise set this object to the result of dividing the value of
        //:   this object by the value of 'rhs'.

    Decimal_Type128& operator/=(int                rhs);
    Decimal_Type128& operator/=(unsigned int       rhs);
    Decimal_Type128& operator/=(long               rhs);
    Decimal_Type128& operator/=(unsigned long      rhs);
    Decimal_Type128& operator/=(long long          rhs);
    Decimal_Type128& operator/=(unsigned long long rhs);
        // Divide the value of this object by the specified 'rhs' as described
        // by IEEE-754, store the result in this object, and return a reference
        // to this object.
        //
        //: o If this object is signaling NaN, then store the value of the
        //:   macro 'EDOM' into 'errno' and set this object to a NaN.
        //:
        //: o Otherwise if this object is NaN then set this object to a NaN.
        //:
        //: o Otherwise if this object is infinity (positive or negative) and
        //:   'rhs' is positive value then set this object to infinity value
        //:   with the same sign as its original value.
        //:
        //: o Otherwise if this object is infinity (positive or negative) and
        //:   'rhs' is negative value then set this object to infinity value
        //:   with the opposite sign as its original value.
        //:
        //: o Otherwise if 'rhs' is zero, store the value of the macro 'ERANGE'
        //:   into 'errno' and set this object to infinity with the same sign
        //:   it had prior to this operation.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is larger than
        //:   'std::numeric_limits<Decimal128>::max()' then store the value of
        //:   the macro 'ERANGE' into 'errno' and return infinity with the same
        //:   sign as that result.
        //:
        //: o Otherwise if dividing the value of this object by the value of
        //:   'rhs' results in an absolute value that is smaller than
        //:   'std::numeric_limits<Decimal128>::min()' then store the value of
        //:   the macro 'ERANGE' into 'errno'and return zero with the same sign
        //:   as that result.
        //:
        //: o Otherwise set this object to the result of dividing the value of
        //:   this object by the value of 'rhs'.

    DecimalImpUtil::ValueType128 *data();
        // Return a modifiable pointer to the underlying implementation.

                                  // Aspects

    template <class STREAM>
    STREAM& bdexStreamIn(STREAM& stream, int version);
        // Assign to this object the value read from the specified input
        // 'stream' using the specified 'version' format, and return a
        // reference to 'stream'.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'version' is not supported, this object
        // is unaltered and 'stream' is invalidated, but otherwise unmodified.
        // If 'version' is supported but 'stream' becomes invalid during this
        // operation, this object has an undefined, but valid, state.  Note
        // that no version is read from 'stream'.  See the 'bslx' package-level
        // documentation for more information on BDEX streaming of
        // value-semantic types and containers.

    // ACCESSORS
    const DecimalImpUtil::ValueType128 *data() const;
        // Return a non-modifiable pointer to the underlying implementation.

    DecimalImpUtil::ValueType128 value() const;
        // Return the value of the underlying implementation.

                                  // Aspects

    template <class STREAM>
    STREAM& bdexStreamOut(STREAM& stream, int version) const;
        // Write the value of this object, using the specified 'version'
        // format, to the specified output 'stream', and return a reference to
        // 'stream'.  If 'stream' is initially invalid, this operation has no
        // effect.  If 'version' is not supported, 'stream' is invalidated, but
        // otherwise unmodified.  Note that 'version' is not written to
        // 'stream'.  See the 'bslx' package-level documentation for more
        // information on BDEX streaming of value-semantic types and
        // containers.
};

// FREE OPERATORS
Decimal128 operator+(Decimal128 value);
    // Return a copy of the specified 'value' if the value is not negative
    // zero, and return positive zero otherwise.

Decimal128 operator-(Decimal128 value);
    // 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'.

Decimal128 operator++(Decimal128& value, int);
    // Apply the prefix ++ operator to the specified 'value' and return its
    // original value.  Note that this is a floating-point value so this
    // operations may not change the value of this object at all (if the value
    // is large) or it may just set it to 1.0 (if the original value is small).

Decimal128 operator--(Decimal128& value, int);
    // Apply the prefix -- operator to the specified 'value' and return its
    // original value.  Note that this is a floating-point value so this
    // operations may not change the value of this object at all (if the value
    // is large) or it may just set it to -1.0 (if the original value is
    // small).

Decimal128 operator+(Decimal128 lhs, Decimal128 rhs);
Decimal128 operator+(Decimal32  lhs, Decimal128 rhs);
Decimal128 operator+(Decimal128 lhs, Decimal32  rhs);
Decimal128 operator+(Decimal64  lhs, Decimal128 rhs);
Decimal128 operator+(Decimal128 lhs, Decimal64  rhs);
    // Add the value of the specified 'rhs' to the value of the specified 'lhs'
    // as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o Otherwise if 'lhs' and 'rhs' are infinities of differing signs, store
    //:   the value of the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' and 'rhs' are infinities of the same sign then
    //:   return infinity of that sign.
    //:
    //: o Otherwise if 'rhs' is zero (positive or negative), return 'lhs'.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' has an absolute value that is
    //:   larger than 'std::numeric_limits<Decimal128>::max()' then store the
    //:   value of the macro 'ERANGE' into 'errno' and set this object to
    //:   infinity with the same sign as that result.
    //:
    //: o Otherwise return the sum of the number represented by 'lhs' and the
    //:   number represented by 'rhs'.

Decimal128 operator+(Decimal128 lhs, int                rhs);
Decimal128 operator+(Decimal128 lhs, unsigned int       rhs);
Decimal128 operator+(Decimal128 lhs, long               rhs);
Decimal128 operator+(Decimal128 lhs, unsigned long      rhs);
Decimal128 operator+(Decimal128 lhs, long long          rhs);
Decimal128 operator+(Decimal128 lhs, unsigned long long rhs);
    // Add the specified 'rhs' to the value of the specified 'lhs' as described
    // by IEEE-754 and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' object is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity, then return infinity.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' has an absolute value that is
    //:   larger than 'std::numeric_limits<Decimal128>::max()' then store the
    //:   value of the macro 'ERANGE' into 'errno' and return infinity with the
    //:   same sign as that result.
    //:
    //: o Otherwise return the sum of 'rhs' and the number represented by
    //:   'lhs'.

Decimal128 operator+(int                lhs, Decimal128 rhs);
Decimal128 operator+(unsigned int       lhs, Decimal128 rhs);
Decimal128 operator+(long               lhs, Decimal128 rhs);
Decimal128 operator+(unsigned long      lhs, Decimal128 rhs);
Decimal128 operator+(long long          lhs, Decimal128 rhs);
Decimal128 operator+(unsigned long long lhs, Decimal128 rhs);
    // Add the specified 'lhs' to the value of the specified 'rhs' as described
    // by IEEE-754 and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' object is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity, then return infinity.
    //:
    //: o Otherwise if the sum of 'lhs' and 'rhs' has an absolute value that is
    //:   larger than 'std::numeric_limits<Decimal128>::max()' then store the
    //:   value of the macro 'ERANGE' into 'errno' and return infinity with the
    //:   same sign as that result.
    //:
    //: o Otherwise return the sum of 'lhs' and the number represented by
    //:   'rhs'.

Decimal128 operator-(Decimal128 lhs, Decimal128 rhs);
Decimal128 operator-(Decimal32  lhs, Decimal128 rhs);
Decimal128 operator-(Decimal128 lhs, Decimal32  rhs);
Decimal128 operator-(Decimal64  lhs, Decimal128 rhs);
Decimal128 operator-(Decimal128 lhs, Decimal64  rhs);
    // Subtract the value of the specified 'rhs' from the value of the
    // specified 'lhs' as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o Otherwise if 'lhs' and the 'rhs' have infinity values of differing
    //:   signs, then return 'lhs'.
    //:
    //: o Otherwise if the subtracting of 'lhs' and 'rhs' has an absolute value
    //:   that is larger than 'std::numeric_limits<Decimal128>::max()' then
    //:   store the value of the macro 'ERANGE' into 'errno' and return
    //:   infinity with the same sign as that result.
    //:
    //: o Otherwise return the result of subtracting the value of 'rhs'from the
    //:   value of 'lhs'.

Decimal128 operator-(Decimal128 lhs, int                rhs);
Decimal128 operator-(Decimal128 lhs, unsigned int       rhs);
Decimal128 operator-(Decimal128 lhs, long               rhs);
Decimal128 operator-(Decimal128 lhs, unsigned long      rhs);
Decimal128 operator-(Decimal128 lhs, long long          rhs);
Decimal128 operator-(Decimal128 lhs, unsigned long long rhs);
    // Subtract the specified 'rhs' from the value of the specified 'lhs' as
    // described by IEEE-754 and return a reference to this object.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity, then return infinity.
    //:
    //: o Otherwise if subtracting 'rhs' from 'lhs' object's value results in
    //:   an absolute value that is larger than
    //:   'std::numeric_limits<Decimal128>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of subtracting 'rhs' from the value of
    //:   'lhs'.

Decimal128 operator-(int                lhs, Decimal128 rhs);
Decimal128 operator-(unsigned int       lhs, Decimal128 rhs);
Decimal128 operator-(long               lhs, Decimal128 rhs);
Decimal128 operator-(unsigned long      lhs, Decimal128 rhs);
Decimal128 operator-(long long          lhs, Decimal128 rhs);
Decimal128 operator-(unsigned long long lhs, Decimal128 rhs);
    // Subtract the specified 'rhs' from the value of the specified 'lhs' as
    // described by IEEE-754 and return a reference to this object.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity, then return infinity.
    //:
    //: o Otherwise if subtracting 'rhs' from 'lhs' object's value results in
    //:   an absolute value that is larger than
    //:   'std::numeric_limits<Decimal128>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of subtracting the value of 'rhs' from
    //:   the number 'lhs'.

Decimal128 operator*(Decimal128 lhs, Decimal128 rhs);
Decimal128 operator*(Decimal32  lhs, Decimal128 rhs);
Decimal128 operator*(Decimal128 lhs, Decimal32  rhs);
Decimal128 operator*(Decimal64  lhs, Decimal128 rhs);
Decimal128 operator*(Decimal128 lhs, Decimal64  rhs);
    // Multiply the value of the specified 'lhs' object by the value of the
    // specified 'rhs' as described by IEEE-754 and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o 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.
    //:
    //: o 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.
    //:
    //: o Otherwise if the product of 'lhs' and 'rhs' has an absolute value
    //:   that is larger than 'std::numeric_limits<Decimal128>::max()' then
    //:   store the value of the macro 'ERANGE' into 'errno' and return an
    //:   infinity with the same sign as that result.
    //:
    //: o Otherwise if the product of 'lhs' and 'rhs' has an absolute value
    //:   that is smaller than 'std::numeric_limits<Decimal128>::min()' then
    //:   store the value of the macro 'ERANGE' into 'errno' and return zero
    //:   with the same sign as that result.
    //:
    //: o Otherwise return the product of the value of 'rhs' and the number
    //:   represented by 'rhs'.

Decimal128 operator*(Decimal128 lhs, int                rhs);
Decimal128 operator*(Decimal128 lhs, unsigned int       rhs);
Decimal128 operator*(Decimal128 lhs, long               rhs);
Decimal128 operator*(Decimal128 lhs, unsigned long      rhs);
Decimal128 operator*(Decimal128 lhs, long long          rhs);
Decimal128 operator*(Decimal128 lhs, unsigned long long rhs);
    // Multiply the specified 'rhs' by the value of the specified 'lhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative), and 'rhs' is
    //:   zero, then store the value of the macro 'EDOM' into'errno' and return
    //:   a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative), then return
    //:   'lhs'.
    //:
    //: o Otherwise if 'rhs' is zero, then return zero with the sign of 'lhs'.
    //:
    //: o Otherwise if the product of 'rhs' and the value of 'lhs' results in
    //:   an absolute value that is larger than
    //:   'std::numeric_limits<Decimal128>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if the product of 'rhs' and the value of 'lhs' results in
    //:   an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal128>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the product of the value of 'lhs' and value 'rhs'.

Decimal128 operator*(int                lhs, Decimal128 rhs);
Decimal128 operator*(unsigned int       lhs, Decimal128 rhs);
Decimal128 operator*(long               lhs, Decimal128 rhs);
Decimal128 operator*(unsigned long      lhs, Decimal128 rhs);
Decimal128 operator*(long long          lhs, Decimal128 rhs);
Decimal128 operator*(unsigned long long lhs, Decimal128 rhs);
    // Multiply the specified 'lhs' by the value of the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN, then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), and 'lhs' is
    //:   zero, then store the value of the macro 'EDOM' into'errno' and return
    //:   a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), then return
    //:   'rhs'.
    //:
    //: o Otherwise if 'lhs' is zero, then return zero with the sign of 'rhs'.
    //:
    //: o Otherwise if the product of 'lhs' and the value of 'rhs' results in
    //:   an absolute value that is larger than
    //:   'std::numeric_limits<Decimal128>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if the product of 'lhs' and the value of 'rhs' results in
    //:   an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal128>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the product of the value of 'lhs' and value 'rhs'.

Decimal128 operator/(Decimal128 lhs, Decimal128 rhs);
Decimal128 operator/(Decimal32  lhs, Decimal128 rhs);
Decimal128 operator/(Decimal128 lhs, Decimal32  rhs);
Decimal128 operator/(Decimal64  lhs, Decimal128 rhs);
Decimal128 operator/(Decimal128 lhs, Decimal64  rhs);
    // Divide the value of the specified 'lhs' by the value of the specified
    // 'rhs' as described by IEEE-754, and return the result.
    //
    //: o If either of 'lhs' or 'rhs' is signaling NaN, then store the value of
    //:   the macro 'EDOM' into 'errno' and return a NaN.
    //:
    //: o Otherwise if either of 'lhs' or 'rhs' is NaN, return a NaN.
    //:
    //: o 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.
    //:
    //: o 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'.
    //:
    //: o 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'.
    //:
    //: o Otherwise if 'lhs' has infinity value and 'rhs' has a positive zero
    //:   value, return infinity with the sign of 'lhs'.
    //:
    //: o Otherwise if 'lhs' has infinity value and 'rhs' has a negative zero
    //:   value, return infinity with the opposite sign as 'lhs'.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is larger than
    //:   'std::numeric_limits<Decimal128>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal128>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value of 'rhs'.

Decimal128 operator/(Decimal128 lhs, int                rhs);
Decimal128 operator/(Decimal128 lhs, unsigned int       rhs);
Decimal128 operator/(Decimal128 lhs, long               rhs);
Decimal128 operator/(Decimal128 lhs, unsigned long      rhs);
Decimal128 operator/(Decimal128 lhs, long long          rhs);
Decimal128 operator/(Decimal128 lhs, unsigned long long rhs);
    // Divide the value of the specified 'lhs' by the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'lhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'lhs' is NaN then return a NaN.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative) and 'rhs' is
    //:   positive value then return infinity value with the same sign as its
    //:   original value.
    //:
    //: o Otherwise if 'lhs' is infinity (positive or negative) and 'rhs' is
    //:   negative value then return infinity value with the opposite sign as
    //:   its original value.
    //:
    //: o Otherwise if 'rhs' is zero, store the value of the macro 'ERANGE'
    //:   into 'errno' and return infinity with the same sign it had prior to
    //:   this operation.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is larger than
    //:   'std::numeric_limits<Decimal128>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal128>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value of 'rhs'.

Decimal128 operator/(int                lhs, Decimal128 rhs);
Decimal128 operator/(unsigned int       lhs, Decimal128 rhs);
Decimal128 operator/(long               lhs, Decimal128 rhs);
Decimal128 operator/(unsigned long      lhs, Decimal128 rhs);
Decimal128 operator/(long long          lhs, Decimal128 rhs);
Decimal128 operator/(unsigned long long lhs, Decimal128 rhs);
    // Divide the specified 'lhs' by the value of the specified 'rhs' as
    // described by IEEE-754, and return the result.
    //
    //: o If 'rhs' is signaling NaN, then store the value of the macro 'EDOM'
    //:   into 'errno' and return a NaN.
    //:
    //: o Otherwise if 'rhs' is NaN then return a NaN.
    //:
    //: o Otherwise if 'rhs' is infinity (positive or negative), and 'lhs' is
    //:   zero, store the value of the macro 'ERANGE' into 'errno' and return a
    //:   NaN.
    //:
    //: o Otherwise if 'rhs' is zero (positive or negative), store the value of
    //:   the macro 'ERANGE' into 'errno' and return infinity with the sign of
    //:   'lhs'.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is larger than
    //:   'std::numeric_limits<Decimal128>::max()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return infinity with the same sign as
    //:   that result.
    //:
    //: o Otherwise if dividing the value of 'lhs' by the value of 'rhs'
    //:   results in an absolute value that is smaller than
    //:   'std::numeric_limits<Decimal128>::min()' then store the value of the
    //:   macro 'ERANGE' into 'errno' and return zero with the same sign as
    //:   that result.
    //:
    //: o Otherwise return the result of dividing the value of 'lhs' by the
    //:   value of 'rhs'.  Note that this is a floating-point operation, not
    //:   integer.

bool operator==(Decimal128 lhs, Decimal128 rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' have the same value, and
    // 'false' otherwise.  Two 'Decimal128' 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 'Decimal128' objects have the same value if:
    //
    //: o both have a zero value (positive or negative), or
    //: o both have the same infinity value (both positive or negative), or
    //: o both have the value of a real number that are equal, even if they are
    //:   represented differently (cohorts have the same value)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.
    //
    // Note that a NaN is never equal to anything, including itself:
    //..
    //  Decimal128 aNaN = std::numeric_limits<Decimal128>::quiet_NaN();
    //  assert(!(aNan == aNan));
    //..

bool operator==(Decimal32  lhs, Decimal128 rhs);
bool operator==(Decimal128 lhs, Decimal32  rhs);
bool operator==(Decimal64  lhs, Decimal128 rhs);
bool operator==(Decimal128 lhs, Decimal64  rhs);
    // 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:
    //
    //: o both have a zero value (positive or negative), or
    //: o both have the same infinity value (both positive or negative), or
    //: o both have the value of a real number that are equal, even if they are
    //:   represented differently (cohorts have the same value)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator!=(Decimal128 lhs, Decimal128 rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' do not have the same
    // value, and 'false' otherwise.  Two 'Decimal128' objects do not have the
    // same value if the 'compareQuietEqual' operation (IEEE-754 defined,
    // non-total ordering comparison) considers the underlying IEEE
    // representations not equal.  In other words, two 'Decimal128' objects do
    // not have the same value if:
    //
    //: o both are a NaN, or
    //: o one has zero value (positive or negative) and the other does not, or
    //: o one has the value of positive infinity and the other does not, or
    //: o one has the value of negative infinity and the other does not, or
    //: o both have the value of a real number that are not equal, regardless
    //:   of their representation (cohorts are equal)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.
    //
    // Note that a NaN is never equal to anything, including itself:
    //..
    //  Decimal128 aNaN = std::numeric_limits<Decimal128>::quiet_NaN();
    //  assert(aNan != aNan);
    //..

bool operator!=(Decimal32  lhs, Decimal128 rhs);
bool operator!=(Decimal128 lhs, Decimal32  rhs);
bool operator!=(Decimal64  lhs, Decimal128 rhs);
bool operator!=(Decimal128 lhs, Decimal64  rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' do not have the same
    // value, and 'false' otherwise.  Two decimal objects do not have the same
    // value if the 'compareQuietEqual' operation (IEEE-754 defined, non-total
    // ordering comparison) considers the underlying IEEE representations not
    // equal.  In other words, two decimal objects do not have the same value
    // if:
    //
    //: o both are NaN, or
    //: o one has zero value (positive or negative) and the other does not, or
    //: o one has the value of positive infinity and the other does not, or
    //: o one has the value of negative infinity and the other does not, or
    //: o both have the value of a real number that are not equal, regardless
    //:   of their representation (cohorts are equal)
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<(Decimal128 lhs, Decimal128 rhs);
    // Return 'true' if the specified 'lhs' has a value less than the specified
    // 'rhs' and 'false' otherwise.  The value of a 'Decimal128' 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' is positive, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' negative, or
    //: o 'lhs' is not positive infinity, or
    //: o 'lhs' is negative infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<(Decimal32  lhs, Decimal128 rhs);
bool operator<(Decimal128 lhs, Decimal32  rhs);
bool operator<(Decimal64  lhs, Decimal128 rhs);
bool operator<(Decimal128 lhs, Decimal64  rhs);
    // Return 'true' if the specified 'lhs' has a value less than the specified
    // 'rhs' and 'false' otherwise.  The value of a decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' is positive, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' negative, or
    //: o 'lhs' is not positive infinity, or
    //: o 'lhs' is negative infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs'is less than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<=(Decimal128 lhs, Decimal128 rhs);
    // 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
    // 'Decimal128' 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are positive infinity, or
    //: o 'lhs' is negative infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator<=(Decimal32  lhs, Decimal128 rhs);
bool operator<=(Decimal128 lhs, Decimal32  rhs);
bool operator<=(Decimal64  lhs, Decimal128 rhs);
bool operator<=(Decimal128 lhs, Decimal64  rhs);
    // 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
    // decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are positive infinity, or
    //: o 'lhs' is negative infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is less or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>(Decimal128 lhs, Decimal128 rhs);
    // Return 'true' if the specified 'lhs' has a greater value than the
    // specified 'rhs' and 'false' otherwise.  The value of a 'Decimal128'
    // 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' positive, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' negative, or
    //: o 'lhs' is not negative infinity, or
    //: o 'lhs' is positive infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>(Decimal32  lhs, Decimal128 rhs);
bool operator>(Decimal128 lhs, Decimal32  rhs);
bool operator>(Decimal64  lhs, Decimal128 rhs);
bool operator>(Decimal128 lhs, Decimal64  rhs);
    // Return 'true' if the specified 'lhs' has a greater value than the
    // specified 'rhs' and 'false' otherwise.  The value of a decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'rhs' is zero (positive or negative) and 'lhs' positive, or
    //: o 'lhs' is zero (positive or negative) and 'rhs' negative, or
    //: o 'lhs' is not negative infinity, or
    //: o 'lhs' is positive infinity and 'rhs' is not, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater than that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>=(Decimal128 lhs, Decimal128 rhs);
    // 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 'Decimal128' object 'lhs' is greater or equal to a 'Decimal128' 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are negative infinity, or
    //: o 'lhs' is positive infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

bool operator>=(Decimal32  lhs, Decimal128 rhs);
bool operator>=(Decimal128 lhs, Decimal32  rhs);
bool operator>=(Decimal64  lhs, Decimal128 rhs);
bool operator>=(Decimal128 lhs, Decimal64  rhs);
    // 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 decimal object 'lhs' is greater or equal to a decimal 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:
    //
    //: o neither 'lhs' nor 'rhs' are NaN, or
    //: o 'lhs' and 'rhs' are both zero (positive or negative), or
    //: o both 'lhs' and 'rhs' are negative infinity, or
    //: o 'lhs' is positive infinity, or
    //: o 'lhs' and 'rhs' both represent a real number and the real number of
    //:   'lhs' is greater or equal to that of 'rhs'
    //
    // This operation stores the value of the macro 'EDOM' into 'errno' if
    // either or both operands are signaling NaN.

template <class CHARTYPE, class TRAITS>
bsl::basic_istream<CHARTYPE, TRAITS>&
operator>> (bsl::basic_istream<CHARTYPE, TRAITS>& stream, Decimal128& object);
    // Read, into the specified 'object', from the specified input 'stream' an
    // IEEE 128 bit decimal floating-point value as described in the IEEE-754
    // 2008 standard (5.12 Details of conversions between floating point
    // numbers and external character sequences) and return a reference
    // providing modifiable access to 'stream'.  If 'stream' contains a Nan
    // value, it is unspecified if 'object' will receive a quiet or signaling
    // 'Nan'.  If 'stream' is not valid on entry 'stream.good() == false', this
    // operation has no effect other than setting 'stream.fail()' to 'true'.
    // If eof (end-of-file) is found before any non-whitespace characters
    // 'stream.fail()' is set to 'true' and 'object' remains unchanged.  If eof
    // is detected after some characters have been read (and successfully
    // interpreted as part of the textual representation of a floating-point
    // value as specified by IEEE-754) then 'stream.eof()' is set to true.  If
    // the first non-whitespace character sequence is not a valid textual
    // representation of a floating-point value (e.g., 12e or e12 or 1*2) the
    // 'stream.fail()' is set to true and 'object' will remain unchanged.  If a
    // real number value is represented by the character sequence but it is a
    // large positive or negative value that cannot be stored into 'object'
    // then store the value of the macro 'ERANGE' into 'errno' and positive or
    // negative infinity is stored into 'object', respectively.  If a real
    // number value is represented by the character sequence but it is a small
    // positive or negative value that cannot be stored into 'object' then
    // store the value of the macro 'ERANGE' into 'errno' and positive or
    // negative zero is stored into 'object', respectively.  If a real number
    // value is represented by the character sequence but it cannot be stored
    // exactly into 'object', the value is rounded according to the current
    // rounding direction (of the environment) and then stored into 'object'.
    //
    // NOTE: This method does not yet fully support iostream flags or the
    // decimal floating point exception context.

template <class CHARTYPE, class TRAITS>
bsl::basic_ostream<CHARTYPE, TRAITS>&
operator<< (bsl::basic_ostream<CHARTYPE, TRAITS>& stream, Decimal128 object);
    // Write the value of the specified 'object' to the specified output
    // 'stream' in a single line format as described in the IEEE-754 2008
    // standard (5.12 Details of conversions between floating point numbers and
    // external character sequences), and return a reference providing
    // modifiable access to 'stream'.  If 'stream' is not valid on entry, this
    // operation has no effect.
    //
    // NOTE: This method does not yet fully support iostream flags or the
    // decimal floating point exception context.

#if defined(BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)  && \
    defined(BSLS_COMPILERFEATURES_SUPPORT_USER_DEFINED_LITERALS)
inline namespace literals {
inline namespace DecimalLiterals {
bdldfp::Decimal128 operator "" _d128(const char *str);
bdldfp::Decimal128 operator "" _d128(const char *str, bsl::size_t len);
    // Produce an object of the indicated return type by parsing the specified
    // 'str' having the specified 'len' excluding the terminating null
    // character that represents a floating-point number written in both fixed
    // and scientific notations.  These user-defined literal suffixes can be
    // applied to both numeric and string literals, (i.e., 1.2_d128, "1.2"_d128
    // or "inf"_d128). The resulting decimal object is initialized as follows:
    //
    //: o If 'str' does not represent a floating-point value, then return a
    //:   decimal object of the indicated return type initialized to a NaN.
    //:
    //: o Otherwise if 'str' represents infinity (positive or negative), then
    //:   return a decimal object of the indicated return type initialized to
    //:   infinity value with the same sign.
    //:
    //: o Otherwise if 'str' represents zero (positive or negative), then
    //:   return a decimal object of the indicated return type initialized to
    //:   zero with the same sign.
    //:
    //: o Otherwise if 'str' represents a value that has an absolute value that
    //:   is larger than the maximum value supported by the indicated return
    //:   type, then store the value of the macro 'ERANGE' into 'errno' and
    //:   return a decimal object of the return type initialized to infinity
    //:   with the same sign.
    //:
    //: o Otherwise if 'str' represents a value that has an absolute value that
    //:   is smaller than min value of the indicated return type, then store
    //:   the value of the macro 'ERANGE' into 'errno' and return a decimal
    //:   object of the return type initialized to zero with the same sign.
    //:
    //: o Otherwise if 'str' has a value that is not exactly representable
    //:   using the maximum digit number supported by the indicated return
    //:   type, then return a decimal object of the return type initialized to
    //:   the value represented by 'str' rounded according to the rounding
    //:   direction.
    //:
    //: o Otherwise return a decimal object of the indicated return type
    //:   initialized to the decimal value representation of 'str'.
    //
    // Note that the parsing follows the rules as specified for the 'strtod128'
    // function in section 9.6 of the ISO/EIC TR 247128 C Decimal
    // Floating-Point Technical Report.
    //
    // Also note that the numeric literal version omits the optional leading
    // sign in 'str'.  For example, if the string is -1.2_d128 then the string
    // "1.2" is passed to the one-argument form, not "-1.2", because leading
    // signs are operators, not parts of literals.  On the other hand, the
    // string literal version does not omit leading sign and if the string is
    // "-1.2"_d128 then the string "-1.2" is passed to the two-argument form.
    //
    // Also note that the quantum of the resultant value is affected by the
    // number of decimal places in 'str' string in both numeric and string
    // literal formats starting with the most significand digit and cannot
    // exceed the maximum number of digits necessary to differentiate all
    // values of the indicated return type, for example:
    //
    // '0.015_d128;                  =>                                 15e-3'
    // '1.5_d128;                    =>                                 15e-1'
    // '1.500_d128;                  =>                               1500e-3'
    // '1.2345678901234567890123456789012349_d128;
    //                               => 1234567890123456789012345678901235e-33'

}  // close DecimalLiterals namespace
}  // close literals namespace
#endif

// FREE FUNCTIONS
template <class HASHALG>
void hashAppend(HASHALG& hashAlg, const Decimal128& object);
    // Pass the specified 'object' to the specified 'hashAlg'.  This function
    // integrates with the 'bslh' modular hashing system and effectively
    // provides a 'bsl::hash' specialization for 'Decimal128'.  Note that two
    // objects which have the same value but different representations will
    // hash to the same value.

                        // MISCELLANEOUS RELATED TYPES

                          // ===================
                          // class DecimalNumGet
                          // ===================

template <class CHARTYPE,
          class INPUTITERATOR = bsl::istreambuf_iterator<CHARTYPE> >
class DecimalNumGet : public bsl::locale::facet {
    // A facet type (mechanism) used in reading decimal floating-point types.
    // Note that this type does not follow BDE conventions because its content
    // is dictated by the C++ standard and native standard library
    // implementations.  See ISO/IEC TR 24733 3.10.2 for details.

#if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD)
  private:
    // ACCESSORS
    bsl::locale::id& __get_id() const;
         // The function __get_id() is a pure virtual function in the Rogue
         // Wave implementation of locales.  It is in violation with the
         // standard.  We have to define it as a workaround.
#endif

  public:
    // -dk:TODO make private while making the output operator a friend

    // CLASS METHODS
    static const DecimalNumGet<CHARTYPE, INPUTITERATOR>& object();
        // TBD

  public:
    // PUBLIC TYPES
    static bsl::locale::id id; // The locale identifier

    typedef CHARTYPE      char_type;
    typedef INPUTITERATOR iter_type;

    // CREATORS
    explicit DecimalNumGet(bsl::size_t refs = 0);
        // Constructs a 'DecimalNumGet' object.  Optionally specify starting
        // reference count 'refs', which will default to 0.  If 'refs' is
        // non-zero, the 'DecimalNumGet' object will not be deleted when the
        // last locale referencing it goes out of scope.

    // ACCESSORS
    iter_type get(iter_type               begin,
                  iter_type               end,
                  bsl::ios_base&          str,
                  bsl::ios_base::iostate& err,
                  Decimal32&              value) const;
    iter_type get(iter_type               begin,
                  iter_type               end,
                  bsl::ios_base&          str,
                  bsl::ios_base::iostate& err,
                  Decimal64&              value) const;
    iter_type get(iter_type               begin,
                  iter_type               end,
                  bsl::ios_base&          str,
                  bsl::ios_base::iostate& err,
                  Decimal128&             value) const;
        // Forward to, and return using the specified 'begin', 'end', 'str',
        // 'err', and 'value', the results of
        // 'this->do_get(begin, end, str, err, value)'.

  protected:
    // CREATORS
    ~DecimalNumGet();
        // Destroy this object.  Note that the destructor is virtual.

    // ACCESSORS
    virtual iter_type do_get(iter_type               begin,
                             iter_type               end,
                             bsl::ios_base&          str,
                             bsl::ios_base::iostate& err,
                             Decimal32&              value) const;
    virtual iter_type do_get(iter_type               begin,
                             iter_type               end,
                             bsl::ios_base&          str,
                             bsl::ios_base::iostate& err,
                             Decimal64&              value) const;
    virtual iter_type do_get(iter_type               begin,
                             iter_type               end,
                             bsl::ios_base&          str,
                             bsl::ios_base::iostate& err,
                             Decimal128&             value) const;
        // Interpret characters from the half-open iterator range denoted by
        // the specified 'begin' and 'end', generate a decimal floating-point
        // number and store it into the specified 'value'.  During conversion
        // the formatting flags of the specified 'str' ('str.flags()') are
        // obeyed; character classifications are determined by the 'bsl::ctype'
        // while punctuation characters are determined by the 'bsl::numpunct'
        // facet imbued to the 'str' stream-base.  Use the specified 'err' to
        // report back failure or EOF streams states.  For further, more
        // detailed information please consult the section
        // [lib.facet.num.get.virtuals] of the C++ Standard.  Note that for the
        // conversions to the 'Decimal32', 64 and 128 types the conversion
        // specifiers are %Hg, %Dg and %DDg, respectively.  Also note that
        // these (possibly overridden) 'do_get' virtual function are used by
        // every formatted C++ stream input operator call ('in >> aDecNumber').
};

                // ============================================
                // template <class CHARTYPE, bool WCHAR_8_BITS>
                // class WideBufferWrapper
                // ============================================

template <class CHARTYPE, bool WCHAR_8_BITS>
class DecimalNumPut_WideBufferWrapper;
    // This class provides a wrapper around a buffer of the specified (template
    // parameter) 'CHARTYPE'.  'CHARTYPE' shall be either plain character type
    // 'char' or wide character type 'wchar_t'.  The width of 'wchar_t' is
    // compiler-specific and can be as small as 8 bits.  The template parameter
    // 'WCHAR_8_BITS' shall be 'true' if 'wchar_t' and 'char' widths are the
    // same, i.e. 8 bits, and 'false' otherwise.  This class provides accessors
    // to the beginning and the end of the buffer of 'CHARTYPE' characters.

            // ========================================================
            // template <bool WCHAR_8_BIT>
            // class DecimalNumPut_WideBufferWrapper<char, WCHAR_8_BIT>
            // ========================================================

template <bool WCHAR_8_BIT>
class DecimalNumPut_WideBufferWrapper<char, WCHAR_8_BIT> {
    // This class is specialization of the template
    // 'WideBufferWrapper<CHARTYPE, WCHAR_8_BITS>' for 'char' type and
    // 'wchar_t' type which width is 8 bits.

    // DATA
    const char *d_begin;  // pointer to the beginning of plain character buffer
    const char *d_end;    // pointer to the end of plain character buffer

    // NOT IMPLEMENTED
    DecimalNumPut_WideBufferWrapper(const DecimalNumPut_WideBufferWrapper&);
    DecimalNumPut_WideBufferWrapper& operator=(
                                    const DecimalNumPut_WideBufferWrapper&);

  public:
    // CREATORS
    DecimalNumPut_WideBufferWrapper(const char         *buffer,
                                    int                 len,
                                    const bsl::locale&);
        // Create a wide buffer wrapper for the specified 'buffer' of the
        // specified length 'len'.

    // ACCESSORS
    const char *begin() const;
        // Return a pointer to the beginning of the buffer of plain characters
        // provided in this class constructor.

    const char *end() const;
        // Return a pointer to the end of the buffer of plain characters
        // provided in this class constructor.
};

            // =====================================================
            // template <>
            // class DecimalNumPut_WideBufferWrapper<wchar_t, false>
            // =====================================================

template <>
class DecimalNumPut_WideBufferWrapper<wchar_t, false> {
    // This class is specialization of the template
    // 'WideBufferWrapper<CHARTYPE, WCHAR_8_BIT>' for 'wchar_t' type which
    // width exceeds 8 bits.

    // DATA
    wchar_t *d_buffer_p;  // Buffer of wide characters
    size_t   d_len;       // Length of the buffer

    // NOT IMPLEMENTED
    DecimalNumPut_WideBufferWrapper(const DecimalNumPut_WideBufferWrapper&);
    DecimalNumPut_WideBufferWrapper& operator=(
                                    const DecimalNumPut_WideBufferWrapper&);

  public:
    // CREATORS
    inline
    DecimalNumPut_WideBufferWrapper(const char         *buffer,
                                    int                 len,
                                    const bsl::locale&  loc);
        // Create a wide buffer wrapper for the specified 'buffer' of the
        // specified length 'len'.  Use the specified locale 'loc' to widen
        // character in the buffer into wide characters representation.

    ~DecimalNumPut_WideBufferWrapper();
        // Destroy this object.

    // ACCESSORS
    const wchar_t *begin() const;
        // Return a pointer to the beginning of the buffer of wide characters.

    const wchar_t *end() const;
        // Return a pointer to the end the buffer of wide characters.
};

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

                // -------------------------------------------
                // class DecimalNumPut_WideBufferWrapper<char>
                // -------------------------------------------

//CREATORS
template <bool WCHAR_8_BIT>
inline
DecimalNumPut_WideBufferWrapper<char, WCHAR_8_BIT>::
DecimalNumPut_WideBufferWrapper(const char         *buffer,
                                int                 len,
                                const bsl::locale&)
: d_begin(buffer)
, d_end(buffer + len)
{
    BSLS_ASSERT(buffer);
    BSLS_ASSERT(len >= 0);
}

// ACCESSORS
template <bool WCHAR_8_BIT>
inline
const char *DecimalNumPut_WideBufferWrapper<char, WCHAR_8_BIT>::begin() const
{
    return d_begin;
}

template <bool WCHAR_8_BIT>
inline
const char *DecimalNumPut_WideBufferWrapper<char, WCHAR_8_BIT>::end() const
{
    return d_end;
}

                // ----------------------------------------------
                // class DecimalNumPut_WideBufferWrapper<wchar_t>
                // ----------------------------------------------

//CREATORS
inline
DecimalNumPut_WideBufferWrapper<wchar_t, false>::
DecimalNumPut_WideBufferWrapper(const char         *buffer,
                                int                 len,
                                const bsl::locale&  loc)
: d_buffer_p(0)
, d_len(len)
{
    BSLS_ASSERT(buffer);
    BSLS_ASSERT(len >= 0);

    bslma::Allocator *allocator = bslma::Default::allocator();

    d_buffer_p = (wchar_t *)allocator->allocate(sizeof(wchar_t) * len);

    bsl::use_facet<std::ctype<wchar_t> >(loc).widen(buffer,
                                                    buffer + len,
                                                    d_buffer_p);
}

inline
DecimalNumPut_WideBufferWrapper<wchar_t, false>::
~DecimalNumPut_WideBufferWrapper()
{
    bslma::Allocator *allocator = bslma::Default::allocator();
    allocator->deallocate(d_buffer_p);
}

    // ACCESSORS
inline
const wchar_t *DecimalNumPut_WideBufferWrapper<wchar_t, false>::begin() const
{
    return d_buffer_p;
}

inline
const wchar_t *DecimalNumPut_WideBufferWrapper<wchar_t, false>::end() const
{
    return d_buffer_p + d_len;
}

                          // ===================
                          // class DecimalNumPut
                          // ===================

template <class CHARTYPE,
          class OUTPUTITERATOR = bsl::ostreambuf_iterator<CHARTYPE> >
class DecimalNumPut : public bsl::locale::facet {
    // A facet type (mechanism) used in writing decimal floating-point types.
    // Note that this type does not follow BDE conventions because its content
    // is dictated by the C++ standard and native standard library
    // implementations.  See ISO/IEC TR 24733 3.10.3 for details.

#if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD)
  private:
    // ACCESSORS
    bsl::locale::id& __get_id() const;
        // The function __get_id() is a pure virtual function in the Rogue Wave
        // implementation of locales.  It is in violation with the standard.
        // We have to define it as a workaround.
#endif

  public:
    // -dk:TODO make private while making the output operator a friend

    // CLASS METHODS
    static const DecimalNumPut<CHARTYPE, OUTPUTITERATOR>& object();
        // TBD

  public:
    // PUBLIC TYPES
    static bsl::locale::id id; // The locale identifier

    typedef CHARTYPE       char_type;
    typedef OUTPUTITERATOR iter_type;

    // CREATORS
    explicit DecimalNumPut(bsl::size_t refs = 0);
        // Constructs a 'DecimalNumPut' object.  Optionally specify starting
        // reference count 'refs', which will default to 0.  If 'refs' is
        // non-zero, the 'DecimalNumPut' object will not be deleted when the
        // last locale referencing it goes out of scope.

    // ACCESSORS
    iter_type put(iter_type      out,
                  bsl::ios_base& str,
                  char_type      fill,
                  Decimal32      value) const;
    iter_type put(iter_type      out,
                  bsl::ios_base& str,
                  char_type      fill,
                  Decimal64      value) const;
    iter_type put(iter_type      out,
                  bsl::ios_base& str,
                  char_type      fill,
                  Decimal128     value) const;
        // Forward to, and return using the specified 'out', 'str', 'fill', and
        // 'value', the results of 'this->do_put(out, str, fill, value)'.

  protected:
    // CREATORS
    ~DecimalNumPut();
        // Destroy this object.  Note that the destructor is virtual.

    // ACCESSORS

    virtual iter_type do_put(iter_type      out,
                             bsl::ios_base& ios_format,
                             char_type      fill,
                             Decimal32      value) const;
    virtual iter_type do_put(iter_type      out,
                             bsl::ios_base& ios_format,
                             char_type      fill,
                             Decimal64      value) const;
    virtual iter_type do_put(iter_type      out,
                             bsl::ios_base& ios_format,
                             char_type      fill,
                             Decimal128     value) const;
        // Write characters (of 'char_type') that represent the specified
        // 'value' to the output stream determined by the specified 'out'
        // output iterator.  Use the 'bsl::ctype' and the 'bsl::numpunct'
        // facets imbued to the specified stream-base 'ios_format' as well as
        // the formatting flags of the 'ios_format' ('bsl.flags()') to generate
        // the properly localized output.  The specified 'fill' character will
        // be used as a placeholder character in padded output.  For further,
        // more detailed information please consult the section
        // [lib.facet.num.put.virtuals] of the C++ Standard noting that the
        // length modifiers "H", "D" and "DD" are added to the conversion
        // specifiers of for the types Decimal32, 64 and 128, respectively.
        // Also note that these (possibly overridden) 'do_put' virtual function
        // are used by every formatted C++ stream output operator call
        // ('out << aDecNumber').  Note that currently, only the width,
        // capitalization, justification, fixed and scientific formatting flags
        // are supported, and the operators only support code pages that
        // include the ASCII sub-range.  Because of potential future
        // improvements to support additional formatting flags, the operations
        // should not be used for serialization.

    template <class DECIMAL>
    iter_type do_put_impl(iter_type      out,
                          bsl::ios_base& ios_format,
                          char_type      fill,
                          DECIMAL        value) const;
        // Write characters that represent the specified 'value' into a string
        // of the specified 'char_type', and output the represented decimal
        // number to the specified 'out', adjusting for the formatting flags in
        // the specified 'ios_format' and using the specified 'fill' character.
        // Currently, formatting for the formatting flags of justification,
        // width, uppercase, showpos, fixed and scientific are supported.
};

                   // =====================================
                   // class Decimal_StandardNamespaceCanary
                   // =====================================

class Decimal_StandardNamespaceCanary {
    // An empty class used for error detection when looking for the original
    // name of the standard namespace.  Do not use it.
};

    // =================================================================
    // template<...> class faux_numeric_limits<NUMERIC_TYPE, DUMMY_TYPE>
    // =================================================================

template<class NUMERIC_TYPE, class DUMMY_TYPE = void>
class faux_numeric_limits;
    // This class is used as a base-class for manifest constants in the
    // 'std::numeric_limits' specializations to overcome a Sun compiler issue.

      // ===============================================================
      // class faux_numeric_limits<Decimal_StandardNamespaceCanary, ...>
      // ===============================================================

template<class DUMMY_TYPE>
class faux_numeric_limits<Decimal_StandardNamespaceCanary, DUMMY_TYPE>
{
    // Explicit full specialization of the standard "traits" template
    // 'std::numeric_limits' for the type
    // 'BloombergLP::bdldfp::Decimal_StandardNamespaceCanary'.  Note that this
    // specialization is required for technical reasons and it is identical to
    // the non-specialized default traits.

  public:
    // CLASS DATA
    static const bool is_specialized = false;
        // 'BloombergLP::bdldfp::Decimal_StandardNamespaceCanary' is not a
        // numeric type.
};

    // ==============================================================
    // template<...> class faux_numeric_limits<Decimal32, DUMMY_TYPE>
    // ==============================================================

template<class DUMMY_TYPE>
class faux_numeric_limits<BloombergLP::bdldfp::Decimal32, DUMMY_TYPE> {
        // Explicit full specialization of the standard "traits" template
        // 'std::numeric_limits' for the type 'BloombergLP::bdldfp::Decimal32'.

  public:
    // CLASS DATA
    static const bool is_specialized = true;
        // The template instance
        // 'std::numeric_limits<BloombergLP::bdldfp::Decimal32>' is
        // meaningfully specialized.  Also means that
        // 'BloombergLP::bdldfp::Decimal32' is a numeric type.

    static const int digits = 7;
        // The maximum number of significant digits, in the native (10) radix
        // of the 'BloombergLP::bdldfp::Decimal32' type that the type is able
        // to represent.  Defined to be 7 by IEEE-754.

    static const int digits10 = digits;
        // The maximum number of significant decimal digits that the
        // 'BloombergLP::bdldfp::Decimal32' type is able to represent.  Defined
        // to be 7 by IEEE-754.

    static const int max_digits10 = digits;
        // The number of significant decimal digits necessary to uniquely
        // represent the significant digits of any
        // 'BloombergLP::bdldfp::Decimal32' value.  Note that max_digit10 is
        // the same as digits10 for decimal floating-point values.

    static const bool is_signed = true;
        // 'BloombergLP::bdldfp::Decimal32' is a signed type.

    static const bool is_integer = false;
        // 'BloombergLP::bdldfp::Decimal32' is not an integer type.

    static const bool is_exact = false;
        // 'BloombergLP::bdldfp::Decimal32' is not an exact type, i.e.:
        // calculations done on the type are not free of rounding errors.  Note
        // that integer and possibly rational types may be exact,
        // floating-point types are never exact.

    static const int radix = 10;
        // The base for 'BloombergLP::bdldfp::Decimal32' is decimal or 10.

    static const int min_exponent = -95;
        // The lowest possible negative exponent for the native base of the
        // 'BloombergLP::bdldfp::Decimal32' type that does not yet represent a
        // denormal number.  Defined to be -95 by IEEE-754.

    static const int min_exponent10 = min_exponent;
        // The lowest possible negative decimal exponent in the
        // 'BloombergLP::bdldfp::Decimal32' type that does not yet represent a
        // denormal number.  Defined to be -95 by IEEE-754.  Note that
        // 'min_exponent10' is the same as 'min_exponent' for decimal types.

    static const int max_exponent = 96;
        // The highest possible positive exponent for the native base of the
        // 'BloombergLP::bdldfp::Decimal32' type that represents a finite
        // value.  Defined to be 96 by IEEE-754.

    static const int max_exponent10 = max_exponent;
        // The highest possible positive decimal exponent of the
        // 'BloombergLP::bdldfp::Decimal32' type that represents a finite
        // value.  Defined to be 97 by IEEE-754.  Note that 'max_exponent10' is
        // the same as 'max_exponent' for decimal types.

    static const bool has_infinity = true;
        // 'BloombergLP::bdldfp::Decimal32' can represent infinity.

    static const bool has_quiet_NaN = true;
        // 'BloombergLP::bdldfp::Decimal32' can be a non-signaling Not a
        // Number.

    static const bool has_signaling_NaN = true;
        // 'BloombergLP::bdldfp::Decimal32' can be a signaling Not a Number.

    static const std::float_denorm_style has_denorm = std::denorm_present;
        // 'BloombergLP::bdldfp::Decimal32' may contain denormal values.

    static const bool has_denorm_loss = true;
        // 'BloombergLP::bdldfp::Decimal32' is able to distinguish loss of
        // precision (floating-point underflow) due to denormalization from
        // other causes.

    static const bool is_bounded = true;
        // Decimal floating-point types represent a finite set of values.

    static const bool is_iec559 = false;
        // Decimal floating-point is not covered by the IEC 559 standard.

    static const bool is_modulo = false;
        // Decimal floating-point types do not have modulo representation.

    static const bool tinyness_before = true;
        // Decimal floating-point types are able to detect if a value is too
        // small to represent as a normalized value before rounding it.

    static const bool traps = true;
        // Decimal floating-point types implement traps to report arithmetic
        // exceptions (required by IEEE-754).

    static const int max_precision = digits10 - 1 + (-min_exponent10);
        // The highest possible precision in the
        // 'BloombergLP::bdldfp::Decimal32' type that is large enough to
        // output the smallest non-zero denormalized value in fixed notation.

                        // Rounding style

    static const std::float_round_style round_style = std::round_indeterminate;
        // Decimal floating-point rounding style is defined to be indeterminate
        // by the C and C++ Decimal TRs.
};

    // ==============================================================
    // template<...> class faux_numeric_limits<Decimal64, DUMMY_TYPE>
    // ==============================================================

template<class DUMMY_TYPE>
class faux_numeric_limits<BloombergLP::bdldfp::Decimal64, DUMMY_TYPE> {
        // Explicit full specialization of the standard "traits" template
        // 'std::numeric_limits' for the type 'BloombergLP::bdldfp::Decimal64'.

  public:
    // CLASS DATA
    static const bool is_specialized = true;
        // The template instance
        // 'std::numeric_limits<BloombergLP::bdldfp::Decimal64>' is
        // meaningfully specialized.  Also means that
        // 'BloombergLP::bdldfp::Decimal64' is a numeric type.

    static const int digits = 16;
        // The maximum number of significant digits, in the native (10) radix
        // of the 'BloombergLP::bdldfp::Decimal64' type that the type is able
        // to represent.  Defined to be 16 by IEEE-754.

    static const int digits10 = digits;
        // The maximum number of significant decimal digits that the
        // 'BloombergLP::bdldfp::Decimal64' type is able to represent.  Defined
        // to be 16 by IEEE-754.

    static const int max_digits10 = digits;
        // The number of significant decimal digits necessary to uniquely
        // represent the significant digits of any
        // 'BloombergLP::bdldfp::Decimal64' value.  Note that max_digit10 is
        // the same as digits10 for decimal floating-point values.

    static const bool is_signed = true;
        // 'BloombergLP::bdldfp::Decimal64' is a signed type.

    static const bool is_integer = false;
        // 'BloombergLP::bdldfp::Decimal64' is not an integer type.

    static const bool is_exact = false;
        // 'BloombergLP::bdldfp::Decimal64' is not an exact type, i.e.:
        // calculations done on the type are not free of rounding errors.  Note
        // that integer and possibly rational types may be exact,
        // floating-point types are never exact.

    static const int radix = 10;
        // The base for 'BloombergLP::bdldfp::Decimal64' is decimal or 10.

    static const int min_exponent = -383;
        // The lowest possible negative exponent for the native base of the
        // 'BloombergLP::bdldfp::Decimal64' type that does not yet represent a
        // denormal number.  Defined to be -383 by IEEE-754.

    static const int min_exponent10 = min_exponent;
        // The lowest possible negative decimal exponent in the
        // 'BloombergLP::bdldfp::Decimal64' type that does not yet represent a
        // denormal number.  Defined to be -382 by IEEE-754.  Note that
        // 'min_exponent10' is the same as 'min_exponent' for decimal types.

    static const int max_exponent = 384;
        // The highest possible positive exponent for the native base of the
        // 'BloombergLP::bdldfp::Decimal64' type that represents a finite
        // value.  Defined to be 384 by IEEE-754.

    static const int max_exponent10 = max_exponent;
        // The highest possible positive decimal exponent of the
        // 'BloombergLP::bdldfp::Decimal64' type that represents a finite
        // value.  Defined to be 384 by IEEE-754.  Note that 'max_exponent10'
        // is the same as 'max_exponent' for decimal types.

    static const bool has_infinity = true;
        // 'BloombergLP::bdldfp::Decimal64' can represent infinity.

    static const bool has_quiet_NaN = true;
        // 'BloombergLP::bdldfp::Decimal64' can be a non-signaling Not a
        // Number.

    static const bool has_signaling_NaN = true;
        // 'BloombergLP::bdldfp::Decimal64' can be a signaling Not a Number.

    static const std::float_denorm_style has_denorm = std::denorm_present;
        // 'BloombergLP::bdldfp::Decimal64' may contain denormal values.

    static const bool has_denorm_loss = true;
        // 'BloombergLP::bdldfp::Decimal64' is able to distinguish loss of
        // precision (floating-point underflow) due to denormalization from
        // other causes.

    static const bool is_iec559 = false;
        // Decimal floating-point is not covered by the IEC 559 standard.

    static const bool is_bounded = true;
        // Decimal floating-point types represent a finite set of values.

    static const bool is_modulo = false;
        // Decimal floating-point types do not have modulo representation.

    static const bool traps = true;
        // Decimal floating-point types implement traps to report arithmetic
        // exceptions (required by IEEE-754).

    static const bool tinyness_before = true;
        // Decimal floating-point types are able to detect if a value is too
        // small to represent as a normalized value before rounding it.

    static const int max_precision = digits10 - 1 + (-min_exponent10);
        // The highest possible precision in the
        // 'BloombergLP::bdldfp::Decimal64' type that is large enough to
        // output the smallest non-zero denormalized value in fixed notation.

    static const std::float_round_style round_style = std::round_indeterminate;
        // Decimal floating-point rounding style is defined to be indeterminate
        // by the C and C++ Decimal TRs.
};

    // ===============================================================
    // template<...> class faux_numeric_limits<Decimal128, DUMMY_TYPE>
    // ===============================================================

template<class DUMMY_TYPE>
class faux_numeric_limits<BloombergLP::bdldfp::Decimal128, DUMMY_TYPE> {
        // Explicit full specialization of the standard "traits" template
        // 'std::numeric_limits' for the type
        // 'BloombergLP::bdldfp::Decimal128'.

  public:
    // CLASS DATA
    static const bool is_specialized = true;
        // The template instance
        // 'std::numeric_limits<BloombergLP::bdldfp::Decimal128>' is
        // meaningfully specialized.  Also means that
        // 'BloombergLP::bdldfp::Decimal128' is a numeric type.

    static const int digits = 34;
        // The maximum number of significant digits, in the native (10) radix
        // of the 'BloombergLP::bdldfp::Decimal128' type that the type is able
        // to represent.  Defined to be 34 by IEEE-754.

    static const int digits10 = digits;
        // The maximum number of significant decimal digits that the
        // 'BloombergLP::bdldfp::Decimal128' type is able to represent.
        // Defined to be 34 by IEEE-754.

    static const int max_digits10 = digits;
        // The number of significant decimal digits necessary to uniquely
        // represent the significant digits of any
        // 'BloombergLP::bdldfp::Decimal128' value.  Note that max_digit10 is
        // the same as digits10 for decimal floating-point values.

    static const bool is_signed = true;
        // 'BloombergLP::bdldfp::Decimal128' is a signed type.

    static const bool is_integer = false;
        // 'BloombergLP::bdldfp::Decimal128' is not an integer type.

    static const bool is_exact = false;
        // 'BloombergLP::bdldfp::Decimal128' is not an exact type, i.e.:
        // calculations done on the type are not free of rounding errors.  Note
        // that integer and possibly rational types may be exact,
        // floating-point types are never exact.

    static const int radix = 10;
        // The base for 'BloombergLP::bdldfp::Decimal128' is decimal or 10.

    static const int min_exponent = -6143;
        // The lowest possible negative exponent for the native base of the
        // 'BloombergLP::bdldfp::Decimal128' type that does not yet represent a
        // denormal number.  Defined to be -6143 by IEEE-754.

    static const int min_exponent10 = min_exponent;
        // The lowest possible negative decimal exponent in the
        // 'BloombergLP::bdldfp::Decimal128' type that does not yet represent a
        // denormal number.  Defined to be -6142 by IEEE-754.  Note that
        // 'min_exponent10' is the same as 'min_exponent' for decimal types.

    static const int max_exponent = 6144;
        // The highest possible positive exponent for the native base of the
        // 'BloombergLP::bdldfp::Decimal128' type that represents a finite
        // value.  Defined to be 385 by IEEE-754.

    static const int max_exponent10 = max_exponent;
        // The highest possible positive decimal exponent of the
        // 'BloombergLP::bdldfp::Decimal128' type that represents a finite
        // value.  Defined to be 6145 by IEEE-754.  Note that 'max_exponent10'
        // is the same as 'max_exponent' for decimal types.

    static const bool has_infinity = true;
        // 'BloombergLP::bdldfp::Decimal128' can represent infinity.

    static const bool has_quiet_NaN = true;
        // 'BloombergLP::bdldfp::Decimal128' can be a non-signaling Not a
        // Number.

    static const bool has_signaling_NaN = true;
        // 'BloombergLP::bdldfp::Decimal128' can be a signaling Not a Number.

    static const std::float_denorm_style has_denorm = std::denorm_present;
        // 'BloombergLP::bdldfp::Decimal128' may contain denormal values.

    static const bool has_denorm_loss = true;
        // 'BloombergLP::bdldfp::Decimal128' is able to distinguish loss of
        // precision (floating-point underflow) due to denormalization from
        // other causes.

    static const bool is_iec559 = false;
        // Decimal floating-point is not covered by the IEC 559 standard.

    static const bool is_bounded = true;
        // Decimal floating-point types represent a finite set of values.

    static const bool is_modulo = false;
        // Decimal floating-point types do not have modulo representation.

    static const bool traps = true;
        // Decimal floating-point types implement traps to report arithmetic
        // exceptions (required by IEEE-754).

    static const bool tinyness_before = true;
        // Decimal floating-point types are able to detect if a value is too
        // small to represent as a normalized value before rounding it.

    static const int max_precision = digits10 - 1 + (-min_exponent10);
        // The highest possible precision in the
        // 'BloombergLP::bdldfp::Decimal128' type that is large enough to
        // output the smallest non-zero denormalized value in fixed notation.

    static const std::float_round_style round_style = std::round_indeterminate;
        // Decimal floating-point rounding style is defined to be indeterminate
        // by the C and C++ Decimal TRs.

};

             // --------------------------------------------------
             // faux_numeric_limits<Decimal32, ...> member storage
             // --------------------------------------------------

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::is_specialized;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::digits;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::digits10;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::max_digits10;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::is_signed;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::is_integer;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::is_exact;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::radix;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::min_exponent;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::min_exponent10;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::max_exponent;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal32, DUMMY_TYPE>::max_exponent10;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::has_infinity;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::has_quiet_NaN;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::has_signaling_NaN;

template<class DUMMY_TYPE>
const std::float_denorm_style
faux_numeric_limits<Decimal32, DUMMY_TYPE>::has_denorm;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::has_denorm_loss;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::is_iec559;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::is_bounded;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::is_modulo;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::traps;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal32, DUMMY_TYPE>::tinyness_before;

template<class DUMMY_TYPE>
const std::float_round_style
faux_numeric_limits<Decimal32, DUMMY_TYPE>::round_style;

             // --------------------------------------------------
             // faux_numeric_limits<Decimal64, ...> member storage
             // --------------------------------------------------

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::is_specialized;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::digits;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::digits10;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::max_digits10;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::is_signed;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::is_integer;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::is_exact;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::radix;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::min_exponent;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::min_exponent10;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::max_exponent;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal64, DUMMY_TYPE>::max_exponent10;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::has_infinity;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::has_quiet_NaN;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::has_signaling_NaN;

template<class DUMMY_TYPE>
const std::float_denorm_style
faux_numeric_limits<Decimal64, DUMMY_TYPE>::has_denorm;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::has_denorm_loss;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::is_iec559;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::is_bounded;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::is_modulo;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::traps;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal64, DUMMY_TYPE>::tinyness_before;

template<class DUMMY_TYPE>
const std::float_round_style
faux_numeric_limits<Decimal64, DUMMY_TYPE>::round_style;

            // ---------------------------------------------------
            // faux_numeric_limits<Decimal128, ...> member storage
            // ---------------------------------------------------

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::is_specialized;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::digits;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::digits10;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::max_digits10;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::is_signed;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::is_integer;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::is_exact;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::radix;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::min_exponent;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::min_exponent10;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::max_exponent;

template<class DUMMY_TYPE>
const int faux_numeric_limits<Decimal128, DUMMY_TYPE>::max_exponent10;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::has_infinity;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::has_quiet_NaN;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::has_signaling_NaN;

template<class DUMMY_TYPE>
const std::float_denorm_style
faux_numeric_limits<Decimal128, DUMMY_TYPE>::has_denorm;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::has_denorm_loss;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::is_iec559;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::is_bounded;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::is_modulo;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::traps;

template<class DUMMY_TYPE>
const bool faux_numeric_limits<Decimal128, DUMMY_TYPE>::tinyness_before;

template<class DUMMY_TYPE>
const std::float_round_style
faux_numeric_limits<Decimal128, DUMMY_TYPE>::round_style;

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

namespace std {

  // ========================================================================
  // template<> class numeric_limits<bdldfp::Decimal_StandardNamespaceCanary>
  // ========================================================================

template<>
class numeric_limits<BloombergLP::bdldfp::Decimal_StandardNamespaceCanary>
    : public BloombergLP::bdldfp::faux_numeric_limits<
        BloombergLP::bdldfp::Decimal_StandardNamespaceCanary> {
    // Explicit full specialization of the standard "traits" template
    // 'std::numeric_limits' for the type
    // 'BloombergLP::bdldfp::Decimal_StandardNamespaceCanary'.  Note that this
    // specialization is required for technical reasons and it is identical to
    // the non-specialized default traits.
};

             // ==================================================
             // template<> class numeric_limits<bdldfp::Decimal32>
             // ==================================================

template<>
class numeric_limits<BloombergLP::bdldfp::Decimal32>
    : public BloombergLP::bdldfp::faux_numeric_limits<
        BloombergLP::bdldfp::Decimal32> {
        // Explicit full specialization of the standard "traits" template
        // 'std::numeric_limits' for the type 'BloombergLP::bdldfp::Decimal32'.

  public:
    // CLASS METHODS
    static BloombergLP::bdldfp::Decimal32 min() BSLS_KEYWORD_NOEXCEPT;
        // Return the smallest positive (also non-zero) number
        // 'BloombergLP::bdldfp::Decimal32' can represent (IEEE-754: +1e-95).

    static BloombergLP::bdldfp::Decimal32 max() BSLS_KEYWORD_NOEXCEPT;
        // Return the largest number 'BloombergLP::bdldfp::Decimal32' can
        // represent (IEEE-754: +9.999999e+96).

    static BloombergLP::bdldfp::Decimal32 epsilon() BSLS_KEYWORD_NOEXCEPT;
        // Return the difference between 1 and the smallest value representable
        // by the 'BloombergLP::bdldfp::Decimal32' type.  (IEEE-754: +1e-6)

    static BloombergLP::bdldfp::Decimal32 round_error() BSLS_KEYWORD_NOEXCEPT;
        // Return the maximum rounding error for the
        // 'BloombergLP::bdldfp::Decimal32' type.  The actual value returned
        // depends on the current decimal floating point rounding setting.

    static BloombergLP::bdldfp::Decimal32 denorm_min() BSLS_KEYWORD_NOEXCEPT;
        // Return the smallest non-zero denormalized value for the
        // 'BloombergLP::bdldfp::Decimal32' type.  (IEEE-754: +0.000001E-95)

    static BloombergLP::bdldfp::Decimal32 infinity() BSLS_KEYWORD_NOEXCEPT;
        // Return the value that represents positive infinity for the
        // 'BloombergLP::bdldfp::Decimal32' type.

    static BloombergLP::bdldfp::Decimal32 quiet_NaN() BSLS_KEYWORD_NOEXCEPT;
        // Return a value that represents non-signaling NaN for the
        // 'BloombergLP::bdldfp::Decimal32' type.

    static
    BloombergLP::bdldfp::Decimal32 signaling_NaN() BSLS_KEYWORD_NOEXCEPT;
        // Return a value that represents signaling NaN for the
        // 'BloombergLP::bdldfp::Decimal32' type.
};

             // ==================================================
             // template<> class numeric_limits<bdldfp::Decimal64>
             // ==================================================

template<>
class numeric_limits<BloombergLP::bdldfp::Decimal64>
    : public BloombergLP::bdldfp::faux_numeric_limits<
        BloombergLP::bdldfp::Decimal64> {
        // Explicit full specialization of the standard "traits" template
        // 'std::numeric_limits' for the type 'BloombergLP::bdldfp::Decimal64'.

  public:
    // CLASS METHODS
    static BloombergLP::bdldfp::Decimal64 min() BSLS_KEYWORD_NOEXCEPT;
        // Return the smallest positive (also non-zero) number
        // 'BloombergLP::bdldfp::Decimal64' can represent (IEEE-754: +1e-383).

    static BloombergLP::bdldfp::Decimal64 max() BSLS_KEYWORD_NOEXCEPT;
        // Return the largest number 'BloombergLP::bdldfp::Decimal64' can
        // represent (IEEE-754: +9.999999999999999e+384).

    static BloombergLP::bdldfp::Decimal64 epsilon() BSLS_KEYWORD_NOEXCEPT;
        // Return the difference between 1 and the smallest value representable
        // by the 'BloombergLP::bdldfp::Decimal64' type.  (IEEE-754: +1e-15)

    static BloombergLP::bdldfp::Decimal64 round_error() BSLS_KEYWORD_NOEXCEPT;
        // Return the maximum rounding error for the
        // 'BloombergLP::bdldfp::Decimal64' type.  The actual value returned
        // depends on the current decimal floating point rounding setting.

    static BloombergLP::bdldfp::Decimal64 denorm_min() BSLS_KEYWORD_NOEXCEPT;
        // Return the smallest non-zero denormalized value for the
        // 'BloombergLP::bdldfp::Decimal64' type.  (IEEE-754:
        // +0.000000000000001e-383)

    static BloombergLP::bdldfp::Decimal64 infinity() BSLS_KEYWORD_NOEXCEPT;
        // Return the value that represents positive infinity for the
        // 'BloombergLP::bdldfp::Decimal64' type.

    static BloombergLP::bdldfp::Decimal64 quiet_NaN() BSLS_KEYWORD_NOEXCEPT;
        // Return a value that represents non-signaling NaN for the
        // 'BloombergLP::bdldfp::Decimal64' type.

    static
    BloombergLP::bdldfp::Decimal64 signaling_NaN() BSLS_KEYWORD_NOEXCEPT;
        // Return a value that represents signaling NaN for the
        // 'BloombergLP::bdldfp::Decimal64' type.

};

            // ===================================================
            // template<> class numeric_limits<bdldfp::Decimal128>
            // ===================================================

template<>
class numeric_limits<BloombergLP::bdldfp::Decimal128>
    : public BloombergLP::bdldfp::faux_numeric_limits<
        BloombergLP::bdldfp::Decimal128> {
        // Explicit full specialization of the standard "traits" template
        // 'std::numeric_limits' for the type
        // 'BloombergLP::bdldfp::Decimal128'.

  public:
    // CLASS METHODS
    static BloombergLP::bdldfp::Decimal128 min() BSLS_KEYWORD_NOEXCEPT;
        // Return the smallest positive (also non-zero) number
        // 'BloombergLP::bdldfp::Decimal128' can represent (IEEE-754:
        // +1e-6143).

    static BloombergLP::bdldfp::Decimal128 max() BSLS_KEYWORD_NOEXCEPT;
        // Return the largest number 'BloombergLP::bdldfp::Decimal128' can
        // represent (IEEE-754: +9.999999999999999999999999999999999e+6144).

    static BloombergLP::bdldfp::Decimal128 epsilon() BSLS_KEYWORD_NOEXCEPT;
        // Return the difference between 1 and the smallest value representable
        // by the 'BloombergLP::bdldfp::Decimal128' type.  (IEEE-754: +1e-33)

    static BloombergLP::bdldfp::Decimal128 round_error() BSLS_KEYWORD_NOEXCEPT;
        // Return the maximum rounding error for the
        // 'BloombergLP::bdldfp::Decimal128' type.  The actual value returned
        // depends on the current decimal floating point rounding setting.

    static BloombergLP::bdldfp::Decimal128 denorm_min() BSLS_KEYWORD_NOEXCEPT;
        // Return the smallest non-zero denormalized value for the
        // 'BloombergLP::bdldfp::Decimal128' type.  (IEEE-754:
        // +0.000000000000000000000000000000001e-6143)

    static BloombergLP::bdldfp::Decimal128 infinity() BSLS_KEYWORD_NOEXCEPT;
        // Return the value that represents positive infinity for the
        // 'BloombergLP::bdldfp::Decimal128' type.

    static BloombergLP::bdldfp::Decimal128 quiet_NaN() BSLS_KEYWORD_NOEXCEPT;
        // Return a value that represents non-signaling NaN for the
        // 'BloombergLP::bdldfp::Decimal128' type.

    static
    BloombergLP::bdldfp::Decimal128 signaling_NaN() BSLS_KEYWORD_NOEXCEPT;
        // Return a value that represents signaling NaN for the
        // 'BloombergLP::bdldfp::Decimal128' type.
};

}  // close namespace std

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

namespace BloombergLP {
namespace bdldfp {

                      // THE DECIMAL FLOATING-POINT TYPES

                            // --------------------
                            // class Decimal_Type32
                            // --------------------

// CLASS METHODS

                                  // Aspects
inline
int Decimal_Type32::maxSupportedBdexVersion()
{
    return 1;
}

inline
int Decimal_Type32::maxSupportedBdexVersion(int /* versionSelector */)
{
    return 1;
}

// CREATORS
inline
Decimal_Type32::Decimal_Type32()
{
    bsl::memset(&d_value, 0, sizeof(d_value));
}

inline
Decimal_Type32::Decimal_Type32(DecimalImpUtil::ValueType32 value)
: d_value(value)
{
}

inline
Decimal_Type32::Decimal_Type32(Decimal_Type64 other)
: d_value(DecimalImpUtil::convertToDecimal32(*other.data()))
{
}

inline
Decimal_Type32::Decimal_Type32(Decimal_Type128 other)
: d_value(DecimalImpUtil::convertToDecimal32(*other.data()))
{
}

inline
Decimal_Type32::Decimal_Type32(float other)
: d_value(DecimalImpUtil::binaryToDecimal32(other))
{
}

inline
Decimal_Type32::Decimal_Type32(double other)
: d_value(DecimalImpUtil::binaryToDecimal32(other))
{
}

inline
Decimal_Type32::Decimal_Type32(int other)
: d_value(DecimalImpUtil::int32ToDecimal32(other))
{
}

inline
Decimal_Type32::Decimal_Type32(unsigned int other)
: d_value(DecimalImpUtil::uint32ToDecimal32(other))
{
}

inline
Decimal_Type32::Decimal_Type32(long int other)
: d_value(DecimalImpUtil::int64ToDecimal32(other))
{
}

inline
Decimal_Type32::Decimal_Type32(unsigned long int other)
: d_value(DecimalImpUtil::uint64ToDecimal32(other))
{
}

inline
Decimal_Type32::Decimal_Type32(long long other)
: d_value(DecimalImpUtil::int64ToDecimal32(other))
{
}

inline
Decimal_Type32::Decimal_Type32(unsigned long long other)
: d_value(DecimalImpUtil::uint64ToDecimal32(other))
{
}

// MANIPULATORS

                     // Incrementation and Decrementation

inline Decimal_Type32& Decimal_Type32::operator++()
{
    return *this += Decimal32(1);
}

inline Decimal_Type32& Decimal_Type32::operator--()
{
    return *this -= Decimal32(1);
}

                                  // Addition

inline Decimal_Type32& Decimal_Type32::operator+=(Decimal32 rhs)
{
    this->d_value = DecimalImpUtil::add(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type32& Decimal_Type32::operator+=(Decimal64 rhs)
{
    return *this = Decimal32(Decimal64(*this) + rhs);
}

inline Decimal_Type32& Decimal_Type32::operator+=(Decimal128 rhs)
{
    return *this = Decimal32(Decimal128(*this) + rhs);
}

inline Decimal_Type32& Decimal_Type32::operator+=(int rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator+=(unsigned int rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator+=(long rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator+=(unsigned long rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator+=(long long rhs)
{
    return *this += Decimal128(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator+=(unsigned long long rhs)
{
    return *this += Decimal128(rhs);
}

                                // Subtraction

inline Decimal_Type32& Decimal_Type32::operator-=(Decimal32 rhs)
{
    this->d_value = DecimalImpUtil::subtract(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type32& Decimal_Type32::operator-=(Decimal64 rhs)
{
    return *this = Decimal32(Decimal64(*this) - rhs);
}

inline Decimal_Type32& Decimal_Type32::operator-=(Decimal128 rhs)
{
    return *this = Decimal32(Decimal128(*this) - rhs);
}

inline Decimal_Type32& Decimal_Type32::operator-=(int rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator-=(unsigned int rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator-=(long rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator-=(unsigned long rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator-=(long long rhs)
{
    return *this -= Decimal128(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator-=(unsigned long long rhs)
{
    return *this -= Decimal128(rhs);
}

                               // Multiplication

inline Decimal_Type32& Decimal_Type32::operator*=(Decimal32 rhs)
{
    this->d_value = DecimalImpUtil::multiply(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type32& Decimal_Type32::operator*=(Decimal64 rhs)
{
    return *this = Decimal32(Decimal64(*this) * rhs);
}

inline Decimal_Type32& Decimal_Type32::operator*=(Decimal128 rhs)
{
    return *this = Decimal32(Decimal128(*this) * rhs);
}

inline Decimal_Type32& Decimal_Type32::operator*=(int rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator*=(unsigned int rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator*=(long rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator*=(unsigned long rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator*=(long long rhs)
{
    return *this *= Decimal128(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator*=(unsigned long long rhs)
{
    return *this *= Decimal128(rhs);
}

                                  // Division

inline Decimal_Type32& Decimal_Type32::operator/=(Decimal32 rhs)
{
    this->d_value = DecimalImpUtil::divide(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type32& Decimal_Type32::operator/=(Decimal64 rhs)
{
    return *this = Decimal32(Decimal64(*this) / rhs);
}

inline Decimal_Type32& Decimal_Type32::operator/=(Decimal128 rhs)
{
    return *this = Decimal32(Decimal128(*this) / rhs);
}

inline Decimal_Type32& Decimal_Type32::operator/=(int rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator/=(unsigned int rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator/=(long rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator/=(unsigned long rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator/=(long long rhs)
{
    return *this /= Decimal128(rhs);
}

inline Decimal_Type32& Decimal_Type32::operator/=(unsigned long long rhs)
{
    return *this /= Decimal128(rhs);
}


inline
DecimalImpUtil::ValueType32 *Decimal_Type32::data()
{
    return &d_value;
}

                                  // Aspects

template <class STREAM>
STREAM& Decimal_Type32::bdexStreamIn(STREAM& stream, int version)
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            DecimalStorage::Type32 bidVal;
            stream.getUint32(bidVal);

            if (stream) {
                d_value.d_raw = bidVal;
            }
            else {
                stream.invalidate();
            }
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }
    return stream;
}

inline
const DecimalImpUtil::ValueType32 *Decimal_Type32::data() const
{
    return &d_value;
}

inline
DecimalImpUtil::ValueType32 Decimal_Type32::value() const
{
    return d_value;
}

                                  // Aspects

template <class STREAM>
STREAM& Decimal_Type32::bdexStreamOut(STREAM& stream, int version) const
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            stream.putUint32(d_value.d_raw);
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }
    return stream;
}

                            // --------------------
                            // class Decimal_Type64
                            // --------------------

// CLASS METHODS

                                  // Aspects
inline
int Decimal_Type64::maxSupportedBdexVersion()
{
    return 1;
}

inline
int Decimal_Type64::maxSupportedBdexVersion(int /* versionSelector */)
{
    return 1;
}

// CREATORS
inline
Decimal_Type64::Decimal_Type64()
{
    bsl::memset(&d_value, 0, sizeof(d_value));
}

inline
Decimal_Type64::Decimal_Type64(DecimalImpUtil::ValueType64 value)
: d_value(value)
{
}

inline
Decimal_Type64::Decimal_Type64(Decimal32 other)
: d_value(DecimalImpUtil::convertToDecimal64(*other.data()))
{
}

inline
Decimal_Type64::Decimal_Type64(Decimal128 other)
: d_value(DecimalImpUtil::convertToDecimal64(*other.data()))
{
}

                     // Numerical Conversion Constructors

inline
Decimal_Type64::Decimal_Type64(float other)
: d_value(DecimalImpUtil::binaryToDecimal64(other))
{
}

inline
Decimal_Type64::Decimal_Type64(double other)
: d_value(DecimalImpUtil::binaryToDecimal64(other))
{
}

                      // Integral Conversion Constructors

inline
Decimal_Type64::Decimal_Type64(int other)
: d_value(DecimalImpUtil::int32ToDecimal64(other))
{
}

inline
Decimal_Type64::Decimal_Type64(unsigned int other)
: d_value(DecimalImpUtil::uint32ToDecimal64(other))
{
}

inline
Decimal_Type64::Decimal_Type64(long other)
: d_value(DecimalImpUtil::int64ToDecimal64(other))
{
}

inline
Decimal_Type64::Decimal_Type64(unsigned long other)
: d_value(DecimalImpUtil::uint64ToDecimal64(other))
{
}

inline
Decimal_Type64::Decimal_Type64(long long other)
: d_value(DecimalImpUtil::int64ToDecimal64(other))
{
}

inline
Decimal_Type64::Decimal_Type64(unsigned long long other)
: d_value(DecimalImpUtil::uint64ToDecimal64(other))
{
}


// MANIPULATORS

                     // Incrementation and Decrementation

inline Decimal_Type64& Decimal_Type64::operator++()
{
    return *this += Decimal64(1);
}

inline Decimal_Type64& Decimal_Type64::operator--()
{
    return *this -= Decimal64(1);
}

                                  // Addition

inline Decimal_Type64& Decimal_Type64::operator+=(Decimal32 rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator+=(Decimal64 rhs)
{
    this->d_value = DecimalImpUtil::add(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type64& Decimal_Type64::operator+=(Decimal128 rhs)
{
    return *this = Decimal64(Decimal128(*this) + rhs);
}

inline Decimal_Type64& Decimal_Type64::operator+=(int rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator+=(unsigned int rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator+=(long rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator+=(unsigned long rhs)
{
    return *this += Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator+=(long long rhs)
{
    return *this += Decimal128(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator+=(unsigned long long rhs)
{
    return *this += Decimal128(rhs);
}

                                // Subtraction

inline Decimal_Type64& Decimal_Type64::operator-=(Decimal32 rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator-=(Decimal64 rhs)
{
    this->d_value = DecimalImpUtil::subtract(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type64& Decimal_Type64::operator-=(Decimal128 rhs)
{
    return *this = Decimal64(Decimal128(*this) - rhs);
}

inline Decimal_Type64& Decimal_Type64::operator-=(int rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator-=(unsigned int rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator-=(long rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator-=(unsigned long rhs)
{
    return *this -= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator-=(long long rhs)
{
    return *this -= Decimal128(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator-=(unsigned long long rhs)
{
    return *this -= Decimal128(rhs);
}

                               // Multiplication

inline Decimal_Type64& Decimal_Type64::operator*=(Decimal32 rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator*=(Decimal64 rhs)
{
    this->d_value = DecimalImpUtil::multiply(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type64& Decimal_Type64::operator*=(Decimal128 rhs)
{
    return *this = Decimal64(Decimal128(*this) * rhs);
}

inline Decimal_Type64& Decimal_Type64::operator*=(int rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator*=(unsigned int rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator*=(long rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator*=(unsigned long rhs)
{
    return *this *= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator*=(long long rhs)
{
    return *this *= Decimal128(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator*=(unsigned long long rhs)
{
    return *this *= Decimal128(rhs);
}

                                  // Division

inline Decimal_Type64& Decimal_Type64::operator/=(Decimal32 rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator/=(Decimal64 rhs)
{
    this->d_value = DecimalImpUtil::divide(this->d_value, rhs.d_value);
    return *this;
}

inline Decimal_Type64& Decimal_Type64::operator/=(Decimal128 rhs)
{
    return *this = Decimal64(Decimal128(*this) / rhs);
}

inline Decimal_Type64& Decimal_Type64::operator/=(int rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator/=(unsigned int rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator/=(long rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator/=(unsigned long rhs)
{
    return *this /= Decimal64(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator/=(long long rhs)
{
    return *this /= Decimal128(rhs);
}

inline Decimal_Type64& Decimal_Type64::operator/=(unsigned long long rhs)
{
    return *this /= Decimal128(rhs);
}

                                  // Aspects

template <class STREAM>
STREAM& Decimal_Type64::bdexStreamIn(STREAM& stream, int version)
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            DecimalStorage::Type64 bidVal;
            stream.getUint64(bidVal);

            if (stream) {
                d_value.d_raw = bidVal;
            }
            else {
                stream.invalidate();
            }
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }

    return stream;
}

//ACCESSORS

                            // Internals Accessors

inline DecimalImpUtil::ValueType64 *Decimal_Type64::data()
{
    return &d_value;
}

inline const DecimalImpUtil::ValueType64 *Decimal_Type64::data() const
{
    return &d_value;
}

inline DecimalImpUtil::ValueType64 Decimal_Type64::value() const
{
    return d_value;
}

                                  // Aspects

template <class STREAM>
STREAM& Decimal_Type64::bdexStreamOut(STREAM& stream, int version) const
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            stream.putUint64(d_value.d_raw);
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }
    return stream;
}

                           // ---------------------
                           // class Decimal_Type128
                           // ---------------------

// CLASS METHODS

                                  // Aspects
inline
int Decimal_Type128::maxSupportedBdexVersion()
{
    return 1;
}

inline
int Decimal_Type128::maxSupportedBdexVersion(int /* versionSelector */)
{
    return 1;
}

// CREATORS
inline
Decimal_Type128::Decimal_Type128()
{
    bsl::memset(&d_value, 0, sizeof(d_value));
}

inline
Decimal_Type128::Decimal_Type128(DecimalImpUtil::ValueType128 value)
: d_value(value)
{
}

inline
Decimal_Type128::Decimal_Type128(Decimal32 value)
: d_value(DecimalImpUtil::convertToDecimal128(*value.data()))
{
}

inline
Decimal_Type128::Decimal_Type128(Decimal64 value)
: d_value(DecimalImpUtil::convertToDecimal128(*value.data()))
{
}

inline
Decimal_Type128::Decimal_Type128(float other)
: d_value(DecimalImpUtil::binaryToDecimal128(other))
{
}

inline
Decimal_Type128::Decimal_Type128(double other)
: d_value(DecimalImpUtil::binaryToDecimal128(other))
{
}

inline
Decimal_Type128::Decimal_Type128(int value)
: d_value(DecimalImpUtil::int32ToDecimal128(value))
{
}

inline Decimal_Type128::Decimal_Type128(unsigned int value)
: d_value(DecimalImpUtil::uint32ToDecimal128(value))
{
}

inline Decimal_Type128::Decimal_Type128(long value)
: d_value(DecimalImpUtil::int64ToDecimal128(value))
{
}

inline Decimal_Type128::Decimal_Type128(unsigned long value)
: d_value(DecimalImpUtil::uint64ToDecimal128(value))
{
}

inline Decimal_Type128::Decimal_Type128(long long value)
: d_value(DecimalImpUtil::int64ToDecimal128(value))
{
}

inline Decimal_Type128::Decimal_Type128(unsigned long long value)
: d_value(DecimalImpUtil::uint64ToDecimal128(value))
{
}


inline
Decimal_Type128& Decimal_Type128::operator++()
{
    return *this += Decimal128(1);
}

inline
Decimal_Type128& Decimal_Type128::operator--()
{
    return *this -= Decimal128(1);
}

                                  // Addition

inline
Decimal_Type128& Decimal_Type128::operator+=(Decimal32 rhs)
{
    return *this += Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator+=(Decimal64 rhs)
{
    return *this += Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator+=(Decimal128 rhs)
{
    this->d_value = DecimalImpUtil::add(this->d_value, rhs.d_value);
    return *this;
}

inline
Decimal_Type128& Decimal_Type128::operator+=(int rhs)
{
    return *this += Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator+=(unsigned int rhs)
{
    return *this += Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator+=(long rhs)
{
    return *this += Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator+=(unsigned long rhs)
{
    return *this += Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator+=(long long rhs)
{
    return *this += Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator+=(unsigned long long rhs)
{
    return *this += Decimal128(rhs);
}

                                // Subtraction

inline
Decimal_Type128& Decimal_Type128::operator-=(Decimal32 rhs)
{
    return *this -= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator-=(Decimal64 rhs)
{
    return *this -= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator-=(Decimal128 rhs)
{
    this->d_value = DecimalImpUtil::subtract(this->d_value, rhs.d_value);
    return *this;
}


inline
Decimal_Type128& Decimal_Type128::operator-=(int rhs)
{
    return *this -= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator-=(unsigned int rhs)
{
    return *this -= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator-=(long rhs)
{
    return *this -= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator-=(unsigned long rhs)
{
    return *this -= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator-=(long long rhs)
{
    return *this -= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator-=(unsigned long long rhs)
{
    return *this -= Decimal128(rhs);
}

                               // Multiplication

inline
Decimal_Type128& Decimal_Type128::operator*=(Decimal32 rhs)
{
    return *this *= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator*=(Decimal64 rhs)
{
    return *this *= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator*=(Decimal128 rhs)
{
    this->d_value = DecimalImpUtil::multiply(this->d_value, rhs.d_value);
    return *this;
}


inline
Decimal_Type128& Decimal_Type128::operator*=(int rhs)
{
    return *this *= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator*=(unsigned int rhs)
{
    return *this *= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator*=(long rhs)
{
    return *this *= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator*=(unsigned long rhs)
{
    return *this *= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator*=(long long rhs)
{
    return *this *= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator*=(unsigned long long rhs)
{
    return *this *= Decimal128(rhs);
}

                                  // Division

inline
Decimal_Type128& Decimal_Type128::operator/=(Decimal32 rhs)
{
    return *this /= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator/=(Decimal64 rhs)
{
    return *this /= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator/=(Decimal128 rhs)
{
    this->d_value = DecimalImpUtil::divide(this->d_value, rhs.d_value);
    return *this;
}


inline
Decimal_Type128& Decimal_Type128::operator/=(int rhs)
{
    return *this /= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator/=(unsigned int rhs)
{
    return *this /= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator/=(long rhs)
{
    return *this /= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator/=(unsigned long rhs)
{
    return *this /= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator/=(long long rhs)
{
    return *this /= Decimal128(rhs);
}

inline
Decimal_Type128& Decimal_Type128::operator/=(unsigned long long rhs)
{
    return *this /= Decimal128(rhs);
}

                            // Internals Accessors

inline
DecimalImpUtil::ValueType128 *Decimal_Type128::data()
{
    return &d_value;
}

                                  // Aspects

template <class STREAM>
STREAM& Decimal_Type128::bdexStreamIn(STREAM& stream, int version)
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            DecimalStorage::Type128 bidVal;
            const int len = sizeof(DecimalStorage::Type128)
                            / sizeof(unsigned char);

            unsigned char *value_p =
                                    reinterpret_cast<unsigned char *>(&bidVal);

#ifdef BSLS_PLATFORM_IS_BIG_ENDIAN
            for (int i(0); i < len; ++i) {
                stream.getUint8(*(value_p + i));
            }
#elif defined(BSLS_PLATFORM_IS_LITTLE_ENDIAN)
            for (int i(len - 1); i >= 0; --i) {
                stream.getUint8(*(value_p + i));
            }
#endif
            if (stream) {
                d_value.d_raw = bidVal;
            }
            else {
                stream.invalidate();
            }
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }
    return stream;
}

inline
const DecimalImpUtil::ValueType128 *Decimal_Type128::data() const
{
    return &d_value;
}

inline
DecimalImpUtil::ValueType128 Decimal_Type128::value() const
{
    return d_value;
}

                                  // Aspects

template <class STREAM>
STREAM& Decimal_Type128::bdexStreamOut(STREAM& stream, int version) const
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            const int len = sizeof(DecimalStorage::Type128)
                            / sizeof(unsigned char);

            const unsigned char *value_p =
                       reinterpret_cast<const unsigned char *>(&d_value.d_raw);

#ifdef BSLS_PLATFORM_IS_BIG_ENDIAN
            for (int i(0); i < len; ++i) {
                stream.putUint8(*(value_p + i));
            }
#elif defined(BSLS_PLATFORM_IS_LITTLE_ENDIAN)
            for (int i(len - 1); i >= 0; --i) {
                stream.putUint8(*(value_p + i));
            }
#endif
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }
    return stream;
}
}  // close package namespace


// FREE OPERATORS

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32 value)
{
    return value;
}

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32 value)
{
    return Decimal32(DecimalImpUtil::negate(value.value()));
}

inline
bdldfp::Decimal32 bdldfp::operator++(bdldfp::Decimal32& value, int)
{
    bdldfp::Decimal32 result(value);
    ++value;
    return result;
}

inline
bdldfp::Decimal32 bdldfp::operator--(bdldfp::Decimal32& value, int)
{
    bdldfp::Decimal32 result(value);
    --value;
    return result;
}

                                  // Addition

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32 lhs,
                                    bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::add(*lhs.data(), *rhs.data());
}

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32 lhs,
                                    int               rhs)
{
    return Decimal32(lhs + Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32 lhs,
                                    unsigned int      rhs)
{
    return Decimal32(lhs + Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32 lhs,
                                    long              rhs)
{
    return Decimal32(lhs + Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32 lhs,
                                    unsigned long     rhs)
{
    return Decimal32(lhs + Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32 lhs,
                                    long long         rhs)
{
    return Decimal32(lhs + Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator+(bdldfp::Decimal32  lhs,
                                    unsigned long long rhs)
{
    return Decimal32(lhs + Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator+(int               lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) + rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator+(unsigned int      lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) + rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator+(long              lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) + rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator+(unsigned long     lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) + rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator+(long long         lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal128(lhs) + rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator+(unsigned long long lhs,
                                    bdldfp::Decimal32  rhs)
{
    return Decimal32(Decimal128(lhs) + rhs);
}


                                // Subtraction

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32 lhs,
                                    bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::subtract(*lhs.data(), *rhs.data());
}

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32 lhs,
                                    int               rhs)
{
    return Decimal32(lhs - Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32 lhs,
                                    unsigned int      rhs)
{
    return Decimal32(lhs - Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32 lhs,
                                    long              rhs)
{
    return Decimal32(lhs - Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32 lhs,
                                    unsigned long     rhs)
{
    return Decimal32(lhs - Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32 lhs,
                                    long long         rhs)
{
    return Decimal32(lhs - Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator-(bdldfp::Decimal32  lhs,
                                    unsigned long long rhs)
{
    return Decimal32(lhs - Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator-(int               lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) - rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator-(unsigned int      lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) - rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator-(long              lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) - rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator-(unsigned long     lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) - rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator-(long long         lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal128(lhs) - Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator-(unsigned long long lhs,
                                    bdldfp::Decimal32  rhs)
{
    return Decimal32(Decimal128(lhs) - Decimal64(rhs));
}

                               // Multiplication

inline bdldfp::Decimal32 bdldfp::operator*(bdldfp::Decimal32 lhs,
                                           bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::multiply(*lhs.data(), *rhs.data());
}

inline
bdldfp::Decimal32 bdldfp::operator*(bdldfp::Decimal32 lhs,
                                    int               rhs)
{
    return Decimal32(lhs * Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator*(bdldfp::Decimal32 lhs,
                                    unsigned int      rhs)
{
    return Decimal32(lhs * Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator*(bdldfp::Decimal32 lhs,
                                    long              rhs)
{
    return Decimal32(lhs * Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator*(bdldfp::Decimal32 lhs,
                                    unsigned long     rhs)
{
    return Decimal32(lhs * Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator*(bdldfp::Decimal32 lhs,
                                    long long         rhs)
{
    return Decimal32(lhs * Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator*(bdldfp::Decimal32  lhs,
                                    unsigned long long rhs)
{
    return Decimal32(lhs * Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator*(int               lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) * rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator*(unsigned int      lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) * rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator*(long              lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) * rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator*(unsigned long     lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) * rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator*(long long         lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal128(lhs) * rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator*(unsigned long long lhs,
                                    bdldfp::Decimal32  rhs)
{
    return Decimal32(Decimal128(lhs) * rhs);
}

                               // Division

inline
bdldfp::Decimal32 bdldfp::operator/(bdldfp::Decimal32 lhs,
                                    bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::divide(*lhs.data(), *rhs.data());
}

inline
bdldfp::Decimal32 bdldfp::operator/(bdldfp::Decimal32 lhs,
                                    int               rhs)
{
    return Decimal32(lhs / Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator/(bdldfp::Decimal32 lhs,
                                    unsigned int      rhs)
{
    return Decimal32(lhs / Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator/(bdldfp::Decimal32 lhs,
                                    long              rhs)
{
    return Decimal32(lhs / Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator/(bdldfp::Decimal32 lhs,
                                    unsigned long     rhs)
{
    return Decimal32(lhs / Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator/(bdldfp::Decimal32 lhs,
                                    long long         rhs)
{
    return Decimal32(lhs / Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator/(bdldfp::Decimal32  lhs,
                                    unsigned long long rhs)
{
    return Decimal32(lhs / Decimal128(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator/(int               lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) / rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator/(unsigned int      lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) / rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator/(long              lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) / Decimal64(rhs));
}

inline
bdldfp::Decimal32 bdldfp::operator/(unsigned long     lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal64(lhs) / rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator/(long long         lhs,
                                    bdldfp::Decimal32 rhs)
{
    return Decimal32(Decimal128(lhs) / rhs);
}

inline
bdldfp::Decimal32 bdldfp::operator/(unsigned long long lhs,
                                    bdldfp::Decimal32  rhs)
{
    return Decimal32(Decimal128(lhs) / rhs);
}


inline
bool bdldfp::operator==(bdldfp::Decimal32 lhs, bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::equal(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator!=(bdldfp::Decimal32 lhs, bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::notEqual(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator<(bdldfp::Decimal32 lhs, bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::less(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator<=(bdldfp::Decimal32 lhs, bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::lessEqual(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator>(bdldfp::Decimal32 lhs, bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::greater(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator>=(bdldfp::Decimal32 lhs, bdldfp::Decimal32 rhs)
{
    return DecimalImpUtil::greaterEqual(*lhs.data(), *rhs.data());
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)  && \
    defined(BSLS_COMPILERFEATURES_SUPPORT_USER_DEFINED_LITERALS)
inline
bdldfp::Decimal32 bdldfp::DecimalLiterals::operator "" _d32(const char *str)
{
    return DecimalImpUtil::parse32(str);
}

inline
bdldfp::Decimal32 bdldfp::DecimalLiterals::operator "" _d32(
                                                  const char *str, bsl::size_t)
{
    return DecimalImpUtil::parse32(str);
}
#endif

// FREE OPERATORS
inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 value)
{
    return value;
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 value)
{
    return DecimalImpUtil::negate(*value.data());
}

inline
bdldfp::Decimal64 bdldfp::operator++(bdldfp::Decimal64& value, int)
{
    bdldfp::Decimal64 result(value);
    ++value;
    return result;
}

inline
bdldfp::Decimal64 bdldfp::operator--(bdldfp::Decimal64& value, int)
{
    bdldfp::Decimal64 result(value);
    --value;
    return result;
}

                                  // Addition

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(DecimalImpUtil::add(*lhs.data(), *rhs.data()));
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal32 lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) + rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 lhs,
                                    bdldfp::Decimal32 rhs)
{
    return lhs + Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 lhs,
                                    int               rhs)
{
    return lhs + Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 lhs,
                                    unsigned int      rhs)
{
    return lhs + Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 lhs,
                                    long              rhs)
{
    return lhs + Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 lhs,
                                    unsigned long     rhs)
{
    return lhs + Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64 lhs,
                                    long long         rhs)
{
    return Decimal64(lhs + Decimal128(rhs));
}

inline
bdldfp::Decimal64 bdldfp::operator+(bdldfp::Decimal64  lhs,
                                    unsigned long long rhs)
{
    return Decimal64(lhs + Decimal128(rhs));
}

inline
bdldfp::Decimal64 bdldfp::operator+(int               lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) + rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator+(unsigned int      lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) + rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator+(long              lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) + rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator+(unsigned long     lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) + rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator+(long long         lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(Decimal128(lhs) + rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator+(unsigned long long lhs,
                                    bdldfp::Decimal64  rhs)
{
    return Decimal64(Decimal128(lhs) + rhs);
}

                                // Subtraction

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(DecimalImpUtil::subtract(*lhs.data(), *rhs.data()));
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal32 lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) - rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 lhs,
                                    bdldfp::Decimal32 rhs)
{
    return lhs - Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 lhs,
                                    int               rhs)
{
    return lhs - Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 lhs,
                                    unsigned int      rhs)
{
    return lhs - Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 lhs,
                                    long              rhs)
{
    return lhs - Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 lhs,
                                    unsigned long     rhs)
{
    return lhs - Decimal64(rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64 lhs,
                                    long long         rhs)
{
    return Decimal64(lhs - Decimal128(rhs));
}

inline
bdldfp::Decimal64 bdldfp::operator-(bdldfp::Decimal64  lhs,
                                    unsigned long long rhs)
{
    return Decimal64(lhs - Decimal128(rhs));
}

inline
bdldfp::Decimal64 bdldfp::operator-(int               lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) - rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator-(unsigned int      lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) - rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator-(long              lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) - rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator-(unsigned long     lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) - rhs;
}

inline
bdldfp::Decimal64 bdldfp::operator-(long long         lhs,
                                    bdldfp::Decimal64 rhs)
{
    return Decimal64(Decimal128(lhs) - rhs);
}

inline
bdldfp::Decimal64 bdldfp::operator-(unsigned long long lhs,
                                    bdldfp::Decimal64  rhs)
{
    return Decimal64(Decimal128(lhs) - rhs);
}

                               // Multiplication

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64 lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(DecimalImpUtil::multiply(*lhs.data(), *rhs.data()));
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal32 lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) * rhs;
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64 lhs,
                                           bdldfp::Decimal32 rhs)
{
    return lhs * Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64 lhs,
                                           int               rhs)
{
    return lhs * Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64 lhs,
                                           unsigned int      rhs)
{
    return lhs * Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64 lhs,
                                           long              rhs)
{
    return lhs * Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64 lhs,
                                           unsigned long     rhs)
{
    return lhs * Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64 lhs,
                                           long long         rhs)
{
    return Decimal64(lhs * Decimal128(rhs));
}

inline bdldfp::Decimal64 bdldfp::operator*(bdldfp::Decimal64  lhs,
                                           unsigned long long rhs)
{
    return Decimal64(lhs * Decimal128(rhs));
}

inline bdldfp::Decimal64 bdldfp::operator*(int               lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) * rhs;
}

inline bdldfp::Decimal64 bdldfp::operator*(unsigned int      lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) * rhs;
}

inline bdldfp::Decimal64 bdldfp::operator*(long              lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) * rhs;
}

inline bdldfp::Decimal64 bdldfp::operator*(unsigned long     lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) * rhs;
}

inline bdldfp::Decimal64 bdldfp::operator*(long long         lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(Decimal128(lhs) * rhs);
}

inline bdldfp::Decimal64 bdldfp::operator*(unsigned long long lhs,
                                           bdldfp::Decimal64  rhs)
{
    return Decimal64(Decimal128(lhs) * rhs);
}

                                  // Division

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64 lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(DecimalImpUtil::divide(*lhs.data(), *rhs.data()));
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal32 lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) / rhs;
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64 lhs,
                                           bdldfp::Decimal32 rhs)
{
    return lhs / Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64 lhs,
                                           int               rhs)
{
    return lhs / Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64 lhs,
                                           unsigned int      rhs)
{
    return lhs / Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64 lhs,
                                           long              rhs)
{
    return lhs / Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64 lhs,
                                           unsigned long     rhs)
{
    return lhs / Decimal64(rhs);
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64 lhs,
                                           long long         rhs)
{
    return Decimal64(lhs / Decimal128(rhs));
}

inline bdldfp::Decimal64 bdldfp::operator/(bdldfp::Decimal64  lhs,
                                           unsigned long long rhs)
{
    return Decimal64(lhs / Decimal128(rhs));
}

inline bdldfp::Decimal64 bdldfp::operator/(int               lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) / rhs;
}

inline bdldfp::Decimal64 bdldfp::operator/(unsigned int      lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) / rhs;
}

inline bdldfp::Decimal64 bdldfp::operator/(long              lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) / rhs;
}

inline bdldfp::Decimal64 bdldfp::operator/(unsigned long     lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) / rhs;
}

inline bdldfp::Decimal64 bdldfp::operator/(long long         lhs,
                                           bdldfp::Decimal64 rhs)
{
    return Decimal64(Decimal128(lhs) / rhs);
}

inline bdldfp::Decimal64 bdldfp::operator/(unsigned long long lhs,
                                           bdldfp::Decimal64  rhs)
{
    return Decimal64(Decimal128(lhs) / rhs);
}

                                  // Equality

inline bool bdldfp::operator==(bdldfp::Decimal64 lhs, bdldfp::Decimal64 rhs)
{
    return DecimalImpUtil::equal(*lhs.data(), *rhs.data());
}

inline bool bdldfp::operator==(bdldfp::Decimal32 lhs, bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) == rhs;
}

inline bool bdldfp::operator==(bdldfp::Decimal64 lhs, bdldfp::Decimal32 rhs)
{
    return lhs == Decimal64(rhs);
}

                                 // Inequality

inline bool bdldfp::operator!=(bdldfp::Decimal64 lhs, bdldfp::Decimal64 rhs)
{
    return DecimalImpUtil::notEqual(*lhs.data(), *rhs.data());
}

inline bool bdldfp::operator!=(bdldfp::Decimal32 lhs, bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) != rhs;
}

inline bool bdldfp::operator!=(bdldfp::Decimal64 lhs, bdldfp::Decimal32 rhs)
{
    return lhs != Decimal64(rhs);
}

                                 // Less Than

inline bool bdldfp::operator<(bdldfp::Decimal64 lhs, bdldfp::Decimal64 rhs)
{
    return DecimalImpUtil::less(*lhs.data(), *rhs.data());
}

inline bool bdldfp::operator<(bdldfp::Decimal32 lhs, bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) < rhs;
}

inline bool bdldfp::operator<(bdldfp::Decimal64 lhs, bdldfp::Decimal32 rhs)
{
    return lhs < Decimal64(rhs);
}

                                 // Less Equal

inline bool bdldfp::operator<=(bdldfp::Decimal64 lhs, bdldfp::Decimal64 rhs)
{
    return DecimalImpUtil::lessEqual(*lhs.data(), *rhs.data());
}

inline bool bdldfp::operator<=(bdldfp::Decimal32 lhs, bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) <= rhs;
}

inline bool bdldfp::operator<=(bdldfp::Decimal64 lhs, bdldfp::Decimal32 rhs)
{
    return lhs <= Decimal64(rhs);
}

                                // Greater Than

inline bool bdldfp::operator>(bdldfp::Decimal64 lhs, bdldfp::Decimal64 rhs)
{
    return DecimalImpUtil::greater(*lhs.data(), *rhs.data());
}

inline bool bdldfp::operator>(bdldfp::Decimal32 lhs, bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) > rhs;
}

inline bool bdldfp::operator>(bdldfp::Decimal64 lhs, bdldfp::Decimal32 rhs)
{
    return lhs > Decimal64(rhs);
}

                               // Greater Equal

inline bool bdldfp::operator>=(bdldfp::Decimal64 lhs, bdldfp::Decimal64 rhs)
{
    return DecimalImpUtil::greaterEqual(*lhs.data(), *rhs.data());
}

inline bool bdldfp::operator>=(bdldfp::Decimal32 lhs, bdldfp::Decimal64 rhs)
{
    return Decimal64(lhs) >= rhs;
}

inline bool bdldfp::operator>=(bdldfp::Decimal64 lhs, bdldfp::Decimal32 rhs)
{
    return lhs >= Decimal64(rhs);
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)  && \
    defined(BSLS_COMPILERFEATURES_SUPPORT_USER_DEFINED_LITERALS)
inline
bdldfp::Decimal64 bdldfp::DecimalLiterals::operator "" _d64(const char *str)
{
    return DecimalImpUtil::parse64(str);
}

inline
bdldfp::Decimal64 bdldfp::DecimalLiterals::operator "" _d64(
                                                  const char *str, bsl::size_t)
{
    return DecimalImpUtil::parse64(str);
}
#endif

// FREE OPERATORS

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 value)
{
    return value;
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 value)
{
    return Decimal128(DecimalImpUtil::negate(*value.data()));
}

inline
bdldfp::Decimal128 bdldfp::operator++(bdldfp::Decimal128& value, int)
{
    Decimal128 result = value;
    ++value;
    return result;
}

inline
bdldfp::Decimal128 bdldfp::operator--(bdldfp::Decimal128& value, int)
{
    Decimal128 result = value;
    --value;
    return result;
}

                                  // Addition

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(DecimalImpUtil::add(*lhs.data(), *rhs.data()));
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal32  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal32  rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal64  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal64  rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     int                rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     unsigned int       rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     long               rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     unsigned long      rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     long long          rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(bdldfp::Decimal128 lhs,
                                     unsigned long long rhs)
{
    return lhs + Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator+(int                lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator+(unsigned int       lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator+(long               lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator+(unsigned long      lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator+(long long          lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator+(unsigned long long lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) + rhs;
}

                                // Subtraction

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(DecimalImpUtil::subtract(*lhs.data(), *rhs.data()));
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal32  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal32  rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal64  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal64  rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     int                rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     unsigned int       rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     long               rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     unsigned long      rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     long long          rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(bdldfp::Decimal128 lhs,
                                     unsigned long long rhs)
{
    return lhs - Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator-(int                lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator-(unsigned int       lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator-(long               lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator-(unsigned long      lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator-(long long          lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator-(unsigned long long lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) - rhs;
}

                               // Multiplication

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(DecimalImpUtil::multiply(*lhs.data(), *rhs.data()));
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal32  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal32  rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal64  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal64  rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     int                rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     unsigned int       rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     long               rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     unsigned long      rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     long long          rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(bdldfp::Decimal128 lhs,
                                     unsigned long long rhs)
{
    return lhs * Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator*(int                lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator*(unsigned int       lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator*(long               lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator*(unsigned long      lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator*(long long          lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator*(unsigned long long lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) * rhs;
}

                                  // Division

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(DecimalImpUtil::divide(*lhs.data(), *rhs.data()));
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal32  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal32  rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal64  lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     bdldfp::Decimal64  rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     int                rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     unsigned int       rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     long               rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     unsigned long      rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     long long          rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(bdldfp::Decimal128 lhs,
                                     unsigned long long rhs)
{
    return lhs / Decimal128(rhs);
}

inline
bdldfp::Decimal128 bdldfp::operator/(int                lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator/(unsigned int       lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator/(long               lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator/(unsigned long      lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator/(long long          lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

inline
bdldfp::Decimal128 bdldfp::operator/(unsigned long long lhs,
                                     bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) / rhs;
}

                                  // Equality

inline
bool bdldfp::operator==(bdldfp::Decimal128 lhs, bdldfp::Decimal128 rhs)
{
    return DecimalImpUtil::equal(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator==(bdldfp::Decimal32 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) == rhs;
}

inline
bool bdldfp::operator==(bdldfp::Decimal128 lhs, bdldfp::Decimal32 rhs)
{
    return lhs == Decimal128(rhs);
}

inline
bool bdldfp::operator==(bdldfp::Decimal64 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) == rhs;
}

inline
bool bdldfp::operator==(bdldfp::Decimal128 lhs, bdldfp::Decimal64 rhs)
{
    return lhs == Decimal128(rhs);
}

                                 // Inequality

inline
bool bdldfp::operator!=(bdldfp::Decimal128 lhs, bdldfp::Decimal128 rhs)
{
    return DecimalImpUtil::notEqual(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator!=(bdldfp::Decimal32 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) != rhs;
}

inline
bool bdldfp::operator!=(bdldfp::Decimal128 lhs, bdldfp::Decimal32 rhs)
{
    return lhs != Decimal128(rhs);
}

inline
bool bdldfp::operator!=(bdldfp::Decimal64 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) != rhs;
}

inline
bool bdldfp::operator!=(bdldfp::Decimal128 lhs, bdldfp::Decimal64 rhs)
{
    return lhs != Decimal128(rhs);
}

                                 // Less Than

inline
bool bdldfp::operator<(bdldfp::Decimal128 lhs, bdldfp::Decimal128 rhs)
{
    return DecimalImpUtil::less(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator<(bdldfp::Decimal32 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) < rhs;
}

inline
bool bdldfp::operator<(bdldfp::Decimal128 lhs, bdldfp::Decimal32 rhs)
{
    return lhs < Decimal128(rhs);
}

inline
bool bdldfp::operator<(bdldfp::Decimal64 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) < rhs;
}

inline
bool bdldfp::operator<(bdldfp::Decimal128 lhs, bdldfp::Decimal64 rhs)
{
    return lhs < Decimal128(rhs);
}

                                 // Less Equal

inline
bool bdldfp::operator<=(bdldfp::Decimal128 lhs, bdldfp::Decimal128 rhs)
{
    return DecimalImpUtil::lessEqual(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator<=(bdldfp::Decimal32 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) <= rhs;
}

inline
bool bdldfp::operator<=(bdldfp::Decimal128 lhs, bdldfp::Decimal32 rhs)
{
    return lhs <= Decimal128(rhs);
}

inline
bool bdldfp::operator<=(bdldfp::Decimal64 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) <= rhs;
}

inline
bool bdldfp::operator<=(bdldfp::Decimal128 lhs, bdldfp::Decimal64 rhs)
{
    return lhs <= Decimal128(rhs);
}

                                  // Greater

inline
bool bdldfp::operator>(bdldfp::Decimal128 lhs, bdldfp::Decimal128 rhs)
{
    return DecimalImpUtil::greater(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator>(bdldfp::Decimal32 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) > rhs;
}

inline
bool bdldfp::operator>(bdldfp::Decimal128 lhs, bdldfp::Decimal32 rhs)
{
    return lhs > Decimal128(rhs);
}

inline
bool bdldfp::operator>(bdldfp::Decimal64 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) > rhs;
}

inline
bool bdldfp::operator>(bdldfp::Decimal128 lhs, bdldfp::Decimal64 rhs)
{
    return lhs > Decimal128(rhs);
}

                               // Greater Equal

inline
bool bdldfp::operator>=(bdldfp::Decimal128 lhs, bdldfp::Decimal128 rhs)
{
    return DecimalImpUtil::greaterEqual(*lhs.data(), *rhs.data());
}

inline
bool bdldfp::operator>=(bdldfp::Decimal32 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) >= rhs;
}

inline
bool bdldfp::operator>=(bdldfp::Decimal128 lhs, bdldfp::Decimal32 rhs)
{
    return lhs >= Decimal128(rhs);
}

inline
bool bdldfp::operator>=(bdldfp::Decimal64 lhs, bdldfp::Decimal128 rhs)
{
    return Decimal128(lhs) >= rhs;
}

inline
bool bdldfp::operator>=(bdldfp::Decimal128 lhs, bdldfp::Decimal64 rhs)
{
    return lhs >= Decimal128(rhs);
}

#if defined(BSLS_COMPILERFEATURES_SUPPORT_INLINE_NAMESPACE)  && \
    defined(BSLS_COMPILERFEATURES_SUPPORT_USER_DEFINED_LITERALS)
inline
bdldfp::Decimal128 bdldfp::DecimalLiterals::operator "" _d128(const char *str)
{
    return DecimalImpUtil::parse128(str);
}

inline
bdldfp::Decimal128 bdldfp::DecimalLiterals::operator "" _d128(
                                                  const char *str, bsl::size_t)
{
    return DecimalImpUtil::parse128(str);
}
#endif

// FREE FUNCTIONS
template <class HASHALG>
inline
void bdldfp::hashAppend(HASHALG& hashAlg, const bdldfp::Decimal32& object)
{
    using ::BloombergLP::bslh::hashAppend;

    bdldfp::Decimal32 normalizedObject = DecimalImpUtil::normalize(
                                                               object.value());
    hashAlg(&normalizedObject, sizeof(normalizedObject));
}

template <class HASHALG>
inline
void bdldfp::hashAppend(HASHALG& hashAlg, const bdldfp::Decimal64& object)
{
    using ::BloombergLP::bslh::hashAppend;

    bdldfp::Decimal64 normalizedObject = DecimalImpUtil::normalize(
                                                               object.value());

    hashAlg(&normalizedObject, sizeof(normalizedObject));
}

template <class HASHALG>
inline
void bdldfp::hashAppend(HASHALG& hashAlg, const bdldfp::Decimal128& object)
{
    using ::BloombergLP::bslh::hashAppend;

    bdldfp::Decimal128 normalizedObject = DecimalImpUtil::normalize(
                                                               object.value());

    hashAlg(&normalizedObject, sizeof(normalizedObject));
}

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