// bdldfp_decimalconvertutil.h -*-C++-*- #ifndef INCLUDED_BDLDFP_DECIMALCONVERTUTIL #define INCLUDED_BDLDFP_DECIMALCONVERTUTIL #include <bsls_ident.h> BSLS_IDENT("$Id$") //@PURPOSE: Provide decimal floating-point conversion functions. // //@CLASSES: // bdldfp::DecimalConvertUtil: Namespace for decimal FP conversion functions // //@SEE_ALSO: bdldfp_decimal, bdldfp_decimalplatform // //@DESCRIPTION: This component provides namespace, // 'bdldfp::DecimalConvertUtil', containing functions that are able to convert // between the native decimal types of the platform and various other possible // representations, such as binary floating-point, network encoding formats. // ///Encoding Formats ///---------------- // This utility contains functions to encode decimal values to and from three // different encoding formats: // //: o the IEEE decimal interchange format using decimal encoding for the //: significant (also known as the Densely Packed Decimal format, see IEEE //: 754 - 2008, section 3.5.2, for more details) //: //: o the multi-width encoding format, which is a custom format that can encode //: subsets of decimal values using a smaller number of bytes //: //: o the variable-width encoding format, which is a custom format that is //: similar to the multi-width encoding format with the main difference being //: that it self describes its own width // // 64-bit decimal values encoded by the IEEE decimal interchange format always // uses 8 bytes, which can be inefficient. The two custom encoding formats // provided by this to enable more space efficient encoding of values commonly // encountered by financial applications. // // In the full IEEE encoding, 50 bits are used for the trailing bits of the // mantissa, 13 bit is used for the combination field (exponent + special // states to indicate NaN and Inf values + leading bits of the mantissa), and 1 // bit is used for the significant. The basic idea for the custom encoding // formats is that the mantissa and exponent of many values (in typical // financial applications) can fit into fewer bits than those provided by the // full encoding. We can define a set of narrow formats to encode these // smaller values without loss of precision. For example, a ticker values less // than 100 dollars with a 2 decimal places of precision can be encoded using a // 2 bytes encoding, using no sign bit, 3 bits for the exponent, and 13 bits // for the mantissa. // ///IEEE Decimal Interchange Format ///- - - - - - - - - - - - - - - - // The IEEE decimal interchange format is defined by the IEEE standard. 64 bit // decimal values encoded by this format always uses 8 bytes. The // 'decimalFromNetwork' and 'decimalToNetwork' functions can be used encode to // and decode from this format. // ///Multi-Width Encoding Format ///- - - - - - - - - - - - - - // The multi-width encoding format uses a set of narrow encoding formats having // sizes smaller than that used by the for IEEE format. Each of the narrower // encoding format is used to encode a subset of values that can be represented // by the full format. The following configuration is used to encode 64-bit // decimal values: // //.. // |------|----------|----------|-----|----------|----------------| // | size | S (bits) | E (bits) | B | T (bits) | max signficand | // |------|----------|----------|-----|----------|----------------| // | 1* | 0 | 1 | -2 | 7 | 127 | // | 2 | 0 | 2 | -3 | 14 | 16383 | // | 3 | 0 | 3 | -6 | 21 | 2097151 | // | 4 | 1 | 5 | -16 | 26 | 67108863 | // | 5 | 1 | 5 | -16 | 34 | 17179869183 | // |------|-------------------------------------------------------| // | 8 | FULL IEEE INTERCHANGE FORMAT** | // |------|-------------------------------------------------------| // // S = sign, E = exponent, B = bias, T = significant // // * 1 byte encoding will be supported by the decoder but not the encoder. This // is done due to the relatively large performance impact of adding the 1 // byte encoding to the encoder (10%). Preserving the encoding size in the // decoder allows us to easily enable this encoding size at a later time. // // ** If the value to be encoded can not fit in the 5-byte encoding or is -Inf, // +Inf, or Nan, then the full 8-byte IEEE format will be used. //.. // // Since the multi-width encoding format consists of subformats having varying // widths, the size of the subformat used must be supplied long with the // encoding to the decode function. This is not required for either the IEEE // format or the variable-width encoding format. // // The 'decimal64ToMultiWidthEncoding' and 'decimal64FromMultiWidthEncoding' // can be used to encode to and decode from this format. Currently, only // 64-bit decimal values are supported by this encoding format. // ///Variable-Width Encoding Formats ///- - - - - - - - - - - - - - - - // The variable-width encoding format can encode decimal values using a // variable number of bytes, similar to the multi-width encoding format. The // difference is that the variable-width encoding format can self-describe its // own size using special state (typically, predicate bits), so the decode // function does not require the size of the encoding to work. The following // configuration is used to encode 64-bit decimal values: // //.. // |------|------------|---|---|-----|----|-----------------| // | size | P | S | E | B | T | max significant | // |------|------------|---|---|-----|----|-----------------| // | 2 | 0b0 | 0 | 2 | -2 | 13 | 8191 | // | 3 | 0b10 | 0 | 3 | -4 | 19 | 524287 | // | 4 | 0b11 | 1 | 5 | -16 | 24 | 16777215 | // |------|------------|------------------------------------| // | 9 | 0b11111111 | FULL IEEE FORMAT* | // |------|------------|------------------------------------| // // P = predicate (bit values) // S = sign (bits), E = exponent (bits), B = bias // T = significant (bits) // // * If the value to be encoded can not fit in the 4-byte encoding or is -Inf, // +Inf, or Nan, then the full 8-byte IEEE format will be used prefixed by a // 1 byte predicate having the value of 0xFF. //.. // // The 'decimal64ToVariableWidthEncoding' and // 'decimal64FromVariableWidthEncoding' can be used to encode to and decode // from this format. Currently, only 64-bit decimal values are supported by // this encoding format. // ///Conversion between Binary to Decimal ///------------------------------------ // The desire to convert numbers from binary to decimal format is fraught with // misunderstanding, and is often accompanied by ill-conceived attempts to // "correct rounding errors" and otherwise coerce results into aesthetically // pleasing forms. In the Bloomberg environment, there is the additional // complication of IBM/Perkin-Elmer/Interdata floating point. This is a // floating-point format that uses a base-16 rather than a base-2 underlying // representation, and the Bloomberg environment contains numbers that began as // decimals, were converted to IBM format, and then were converted from IBM // format to IEEE format. // // Generically, when a decimal is converted to floating-point (using, for // example, scanf from text, or 'DecimalConvertUtil::decimalToDouble'), the // result is the representable binary number nearest in value to that decimal. // If there are two such, the one whose least significant bit is 0 is generally // chosen. (This is also true for conversion of decimals to 32-bit // Perkin-Elmer format, but when the Perkin-Elmer float is then converted to // IEEE float, the resulting value is not the same as converting the decimal to // IEEE float directly, because the Perkin-Elmer format can lose up to three // bits of representation compared to the IEEE format.) Unless the decimal // value is exactly a multiple of a power of two (e.g., 3.4375 = 55 * 1/16), // the converted binary value cannot equal the decimal value, it can only be // close. This utility provides 'decimal{,32,64,128}To{Float,Double}' // functions to convert decimal floating-point numbers to their closest binary // floating-point values. // // When converting from decimal to binary, it is hoped that two different // decimal values (in the representable range of the target binary type) // convert to two different binary values. There is a maximum number of // significant digits for which this will be true. For example, all decimals // with 6 significant digits convert to distinct 'float' values, but 8589973000 // and 8589974000, with 7 significant digits, convert to the same 'float' // value. Similarly, all decimals with 15 significant digits convert to unique // 'double' values but 900719925474.0992 and 900719925474.0993, with 16 // significant digits, convert to the same 'double' value. Over restricted // ranges, the maximum may be higher - for example, every decimal value with 7 // or fewer significant digits between 1e-3 and 8.5e9 converts to a unique // 'float' value. // // Because binary floating-point values are generally not equal to their // decimal progenitors, "converting from binary to decimal" does not have a // single meaning, and programmers who seek such an operation therefore need to // know and specify the conversion they want. Common examples of conversions a // programmer might seek are listed below: // //: 1 Express the value as its nearest decimal value. //: //: o For this conversion, use the conversion constructors: //: o 'Decimal{32,64,128}(value)' //: //: 2 Express the value rounded to a given number of significant digits. (The //: significant digits of a decimal number are the digits with all leading //: and trailing 0s removed; e.g., 0.00103, 10.3 and 10300 each have 3 //: significant digits.) This conversion is the one that leads programmers //: to complain about "rounding error" (for example, .1f rounded to 9 digits //: is .100000001) but is the appropriate one to use when the programmer //: knows that the binary value was originally converted from a decimal value //: with that many significant digits. //: //: o For this conversion, use: //: o 'Decimal{32,64,128}From{Float,Double}(value, digits)' //: //: 3 Express the value using the minimum number of significant digits for the //: type of the binary such that converting the decimal value back to binary //: will yield the same value. (Note that 17 digits are needed for 'double' //: and 9 for 'float', so not all decimal types can hold such a result.) //: //: o For this conversion, use: //: o 'Decimal{64,128}FromFloat(value, 9)' or //: o 'Decimal128FromDouble(value, 17)' //: //: 4 Express the value using a number of decimal places that restores the //: original decimal value from which the binary value was converted, //: assuming that the original decimal value had sufficiently few significant //: digits so that no two values with that number of digits would convert to //: the same binary value. (That number is 15 for 'double' and 6 for 'float' //: in general but 7 over a limited range that spans '[1e-3 .. 8.5e9]'). //: //: o For this conversion, use: //: o 'Decimal{32,64,128}From{Float,Double}(value)' //: //: 5 Express the value as the shortest decimal number that converts back //: exactly to the binary value. For example. given the binary value //: 0x3DCCCCCD above, that corresponding shortest decimal value is //: (unsurprisingly) .1, while the next lower value 0x3DCCCCCC has the //: shortest decimal .099999994 and the next higher value 0x3DCCCCCE has the //: shortest decimal .010000001. This is the most visually appealing result, //: but can be expensive and slow to compute. //: //: o For this conversion, use: //: o 'Decimal{32,64,128}From{Float,Double}(value, -1)' //: //: 6 Express the value using a number of decimal places that restores the //: original decimal value assuming that it is a 'float' which originated as //: an IBM/Perkin-Elmer/Interdata 'float' value itself originally converted //: from a decimal value. //: //: o For this conversion, use: //: o 'Decimal{32,64,128}FromFloat(value, 6)' //: //: 7 Express the value exactly as a decimal. For example, the decimal //: value .1 converts to the 32-bit IEEE float value 0x3DCCCCCD, which has //: the exact value .100000001490116119384765625. This conversion is seldom //: useful, except perhaps for debugging, since the exact value may have over //: 1000 digits, and as well cannot be represented as a decimal //: floating-point type since those types do not have enough digits. //: //: o For this conversion, use 'sprintf' into a large-enough buffer: //: o 'char buf[2000]; double value; sprintf(buf, "%.1100f", value);' //: o The result will have trailing 0s, which may be trimmed. //: //: 8 Express the value rounded to a given number of decimal places. (The //: decimal places of a decimal number are the number of digits after the //: decimal point, with trailing 0s removed; .01, 10.01, and 1000.01 each //: have two decimal places.) This conversion can be problematic when the //: integer portion of the value is large, as there may not be enough //: precision remaining to deliver a meaningful number of decimal places. As //: seen above, for example, for numbers near one trillion, there is not //: enough precision in a 'double' for 4 decimal places. //: //: o For this conversion, use 'sprintf' into a large-enough buffer: //: o 'char buf[2000]; double value; sprintf(buf, "%.*f", places, value);' // ///Usage ///----- // This section shows the intended use of this component. // ///Example 1: Sending Decimals As Octets Using Network Format /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Suppose you have two communicating entities (programs) that talk to each // other using a binary (as opposed to text) protocol. In such protocol it is // important to establish a so-called network format, and convert to and from // that format in the protocol layer. The sender (suppose that it is an IBM // server that has just finished an expensive calculation involving millions // of numbers and needs to send the result to its client) will need to convert // the data to network format before sending: //.. // unsigned char msgbuffer[256]; // unsigned char *next = msgbuffer; // // BDEC::Decimal64 number(BDLDFP_DECIMAL_DD(1.234567890123456e-42)); // unsigned char expected[] = { // 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 }; // // next = bdldfp::DecimalConvertUtil::decimalToNetwork(next, number); // // assert(memcmp(msgbuffer, expected, sizeof(number)) == 0); //.. // The receiver/client shall then restore the number from network format: //.. // unsigned char msgbuffer[] ={ // 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 }; // unsigned char *next = msgbuffer; // // BDEC::Decimal64 number; // BDEC::Decimal64 expected(BDLDFP_DECIMAL_DD(1.234567890123456e-42)); // // next = bdldfp::DecimalConvertUtil::decimalFromNetwork(number, next); // // assert(number == expected); //.. // ///Example 2: Storing/Sending Decimals In Binary Floating-Point /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Suppose you have two communicating entities (programs) that talk to each // other using a legacy protocol that employs binary floating-point formats to // send/receive numbers. So your application layer will have to store the // decimal into a binary FP variable, ensure that it can be restored (in other // words that it has "fit" into the binary type) when sending, and restore the // decimal number (from the binary type) when receiving: //.. // const BDEC::Decimal64 number(BDLDFP_DECIMAL_DD(1.23456789012345e-42)); // // typedef bdldfp::DecimalConvertUtil Util; // double dbl = Util::decimalToDouble(number); // // if (Util::decimal64FromDouble(dbl) != number) { // // Do what is appropriate for the application // } //.. // Note that the above assert would probably be a lot more complicated if // statement in production code. It may actually be acceptable to put the // decimal onto the wire with certain amount of imprecision. // // The receiver would then restore the number using the appropriate // 'decimal64FromDouble' function: //.. // BDEC::Decimal64 restored = Util::decimal64FromDouble(dbl); // // assert(number == restored); //.. #include <bdlscm_version.h> #include <bdldfp_decimal.h> #include <bdldfp_decimalconvertutil_inteldfp.h> #include <bdldfp_decimalimputil.h> #include <bdldfp_decimalimputil_inteldfp.h> #include <bdldfp_decimalplatform.h> #include <bdldfp_decimalutil.h> #include <bdldfp_intelimpwrapper.h> #include <bsls_assert.h> #include <bsls_byteorder.h> #include <bsls_performancehint.h> #include <bsls_platform.h> #include <bsls_types.h> #include <bsl_cstring.h> #ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES #include <bsl_c_signal.h> // Formerly transitively included via decContext.h #endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES namespace BloombergLP { namespace bdldfp { // ======================== // class DecimalConvertUtil // ======================== struct DecimalConvertUtil { // This 'struct' provides a namespace for utility functions that convert // between the decimal floating-point types of 'bdldfp_decimal' and various // other formats. private: // PRIVATE TYPES #if defined(BDLDFP_DECIMALPLATFORM_INTELDFP) typedef DecimalConvertUtil_IntelDfp Imp; #else BDLDFP_DECIMALPLATFORM_COMPILER_ERROR; #endif // PRIVATE CLASS DATA // 'bid64' REPRESENTATION CONSTANTS static const int k_EXPONENT_SHIFT_SMALL64 = 53; // exponent position static const int k_EXPONENT_MASK64 = 0x3ff; // exponent mask bits static const unsigned long long k_SPECIAL_ENCODING_MASK64 = 0x6000000000000000ull; // special when non-zero static const unsigned long long k_SMALL_COEFF_MASK64 = 0x001fffffffffffffull; // mask for mantissa // PRIVATE CLASS METHODS static int decimal64ToUnpackedSpecial(bool *isNegative, int *biasedExponent, bsls::Types::Uint64 *mantissa, bdldfp::Decimal64 value); // If the specified 'value' is NaN, +infinity, -infinity, or its // unbiased exponent is 384, return a non-zero value and leave all // output parameters unmodified. Otherwise, partition the 'value' into // sign, biased exponent, and mantissa compartments, and load the // corresponding values into the specified 'isNegative', // 'biasedExponent', and 'mantissa'. Return 0. Note that a non-zero // value does not indicate that 'value' can not be partitioned, just // that it can not be partitioned by this function. Also note that the // bias for 'Decimal64' is 398. static bdldfp::Decimal64 decimal64FromUnpackedSpecial( bool isNegative, bsls::Types::Uint64 mantissa, int exponent); // Return a 'Decimal64' object that has the specified 'mantissa', // 'exponent', and a sign based on the specified 'isNegative'. The // behavior is undefined unless 'isNegative', 'mantissa', and the // biased exponent were originally obtained from // 'decimal64ToUnpackedSpecial'. Note that 'exponent' should be // unbiased, so 398 should be subtracted from the biased exponent // gotten from 'decimal64ToUnpackedSpecial'. static bdldfp::Decimal64 decimal64FromUnpackedSpecial(int mantissa, int exponent); // Return a 'Decimal64' object that has the specified 'mantissa', // 'exponent'. The behavior is undefined unless 'isNegative', // 'mantissa', and the biased exponent were originally obtained from // 'decimal64ToUnpackedSpecial'. Note that 'exponent' should be // unbiased, so 398 should be subtracted from the biased exponent // gotten from 'decimal64ToUnpackedSpecial'. public: // CLASS METHODS // decimalToDouble functions static double decimal32ToDouble (Decimal32 decimal); static double decimal64ToDouble (Decimal64 decimal); static double decimal128ToDouble(Decimal128 decimal); // [!DEPRECATED!] Use 'deciamalToDouble' instead. static double decimalToDouble (Decimal32 decimal); static double decimalToDouble (Decimal64 decimal); static double decimalToDouble (Decimal128 decimal); // Return a 'double' object having the value closest to the value of // the specified 'decimal' object following the conversion rules // defined by IEEE-754: // //: o If the 'decimal' object is a NaN, return a NaN. //: //: o Otherwise if 'decimal' is positive or negative infinity, return //: infinity of the same sign. //: //: o Otherwise if 'decimal' is positive or negative zero, return zero //: of the same sign. //: //: o Otherwise if 'decimal' object has an absolute value that is //: larger than 'std::numeric_limits<double>::max()', raise the //: "overflow" floating-point exception and return infinity of the //: same sign as 'decimal'. //: //: o Otherwise if 'decimal' has an absolute value that is smaller than //: 'std::numeric_limits<double>::min()', raise the "underflow" //: floating-point exception and return zero of the same sign as //: 'decimal'. //: //: o Otherwise if 'decimal' has a value that has more significant //: base-10 digits than 'std::numeric_limits<double>::digits10', //: raise the "inexact" floating-point exception, round that value //: according to the *binary* rounding direction setting of the //: floating-point environment, and return the result of that. //: //: o Otherwise if 'decimal' has a significand that cannot be exactly //: represented using binary floating-point, raise the "inexact" //: floating-point exception, round that value according to the //: *binary* rounding direction setting of the environment, and //: return the result of that. //: //: o Otherwise use the exact value of the 'other' object for the //: initialization if this object. // decimalToFloat functions static float decimal32ToFloat (Decimal32 decimal); static float decimal64ToFloat (Decimal64 decimal); static float decimal128ToFloat(Decimal128 decimal); // [!DEPRECATED!] Use 'deciamalToFloat' instead. static float decimalToFloat (Decimal32 decimal); static float decimalToFloat (Decimal64 decimal); static float decimalToFloat (Decimal128 decimal); // Return a 'float' object having the value closest to the value of the // specified 'decimal' object following the conversion rules defined // by IEEE-754: // //: o If the 'decimal' object is a NaN, return a NaN. //: //: o Otherwise if 'decimal' is positive or negative infinity, return //: infinity of the same sign. //: //: o Otherwise if 'decimal' is positive or negative zero, return zero //: of the same sign. //: //: o Otherwise if 'decimal' object has an absolute value that is //: larger than 'std::numeric_limits<long double>::max()', raise the //: "overflow" floating-point exception and return infinity of the //: same sign as 'decimal'. //: //: o Otherwise if 'decimal' has an absolute value that is smaller than //: 'std::numeric_limits<float>::min()', raise the "underflow" //: floating-point exception and return zero of the same sign as //: 'decimal'. //: //: o Otherwise if 'decimal' has a value that has more significant //: base-10 digits than 'std::numeric_limits<float>::digits10', //: raise the "inexact" floating-point exception, round that value //: according to the *binary* rounding direction setting of the //: floating-point environment, and return the result of that. //: //: o Otherwise if 'decimal' has a significand that cannot be exactly //: represented using binary floating-point, raise the "inexact" //: floating-point exception, round that value according to the //: *binary* rounding direction setting of the environment, and //: return the result of that. //: //: o Otherwise use the exact value of the 'other' object for the //: initialization if this object. // decimalFromDouble functions static Decimal32 decimal32FromDouble (double binary, int digits = 0); static Decimal32 decimal32FromFloat (float binary, int digits = 0); static Decimal64 decimal64FromDouble (double binary, int digits = 0); static Decimal64 decimal64FromFloat (float binary, int digits = 0); static Decimal128 decimal128FromDouble(double binary, int digits = 0); static Decimal128 decimal128FromFloat (float binary, int digits = 0); // Return a decimal floating-point number converted from the specified // 'binary'. // // If 'binary' is singular (+/-NaN, +/-Inf, or +/-0) or is not within // the representable range of the return type, return a corresponding // decimal singular value. // // Optionally specify 'digits' to indicate the number of significant // digits to produce in the returned value. The 'digits' parameter is // treated as follows: // // If 'digits' is larger than the number of digits in the destination // type, it will be reduced to that number of digits. // // If 'digits' is positive, the result is 'binary' rounded to that many // significant digits. // // If 'digits' is negative, the decimal value with the fewest // significant digits that converts back to 'binary' is returned if // possible, and otherwise the value closest to 'binary' is returned. // Note that this provides the most visually appealing result but is // the most expensive to compute. // // If 'digits' is not specified or 0, a default value will be used // (possibly depending on the value of 'binary') based on the premise // that 'binary' is a converted decimal value of no more significant // digits than is guaranteed to have a uniquely converted binary value // (15 for 'double', 6 for 'float' in general, and 7 for 'float' in the // range '[ .0009999995 .. 8589972000 ]'). Note that this is likely to // have the best performance for "business" numbers (i.e., numbers that // originate as decimal values in external market quote feeds). // // Note that the purpose of these functions is to restore a decimal // value that has been converted to a binary floating-point type. It // is more efficient to use conversion constructors when all that is // needed is the nearest decimal to the 'binary' value. // // Note that if 'binary' is a 'float' value that was converted from an // IBM/Perkin-Elmer/Interdata binary 'float' value itself converted // from a decimal value of no more than 6 significant digits, // specifying 6 for 'digits' will recover the original decimal value. // Not specifying 'digits' may result in a value having a spurious // seventh digit. // decimalToDPD functions static void decimal32ToDPD (unsigned char *buffer, Decimal32 decimal); static void decimal64ToDPD (unsigned char *buffer, Decimal64 decimal); static void decimal128ToDPD(unsigned char *buffer, Decimal128 decimal); static void decimalToDPD (unsigned char *buffer, Decimal32 decimal); static void decimalToDPD (unsigned char *buffer, Decimal64 decimal); static void decimalToDPD (unsigned char *buffer, Decimal128 decimal); // Populate the specified 'buffer' with the Densely Packed Decimal // (DPD) representation of the specified 'decimal' value. The DPD // representations of 'Decimal32', 'Decimal64', and 'Decimal128' // require 4, 8, and 16 bytes respectively. The behavior is undefined // unless 'buffer' points to a contiguous sequence of at least // 'sizeof(decimal)' bytes. Note that the DPD representation is // defined in section 3.5 of IEEE 754-2008. // decimalFromDPD functions static Decimal32 decimal32FromDPD (const unsigned char *buffer); static Decimal64 decimal64FromDPD (const unsigned char *buffer); static Decimal128 decimal128FromDPD(const unsigned char *buffer); // Return the native implementation representation of the value of the // same size base-10 floating-point value stored in Densely Packed // Decimal format at the specified 'buffer' address. The behavior is // undefined unless 'buffer' points to a memory area at least // 'sizeof(decimal)' in size containing a value in DPD format. static void decimal32FromDPD (Decimal32 *decimal, const unsigned char *buffer); static void decimal64FromDPD (Decimal64 *decimal, const unsigned char *buffer); static void decimal128FromDPD(Decimal128 *decimal, const unsigned char *buffer); static void decimalFromDPD (Decimal32 *decimal, const unsigned char *buffer); static void decimalFromDPD (Decimal64 *decimal, const unsigned char *buffer); static void decimalFromDPD (Decimal128 *decimal, const unsigned char *buffer); // Store, into the specified 'decimal', the native implementation // representation of the value of the same size base-10 floating point // value represented in Densely Packed Decimal format, at the specified // 'buffer' address. The behavior is undefined unless 'buffer' points // to a memory area at least 'sizeof(decimal)' in size containing a // value in DPD format. // decimalToBID functions static void decimal32ToBID (unsigned char *buffer, Decimal32 decimal); static void decimal64ToBID (unsigned char *buffer, Decimal64 decimal); static void decimal128ToBID(unsigned char *buffer, Decimal128 decimal); static void decimalToBID (unsigned char *buffer, Decimal32 decimal); static void decimalToBID (unsigned char *buffer, Decimal64 decimal); static void decimalToBID (unsigned char *buffer, Decimal128 decimal); // Populate the specified 'buffer' with the Binary Integer Decimal // (BID) representation of the specified 'decimal' value. The BID // representations of 'Decimal32', 'Decimal64', and 'Decimal128' // require 4, 8, and 16 bytes respectively. The behavior is undefined // unless 'buffer' points to a contiguous sequence of at least // 'sizeof(decimal)' bytes. Note that the BID representation is // defined in section 3.5 of IEEE 754-2008. // decimalFromBID functions static Decimal32 decimal32FromBID (const unsigned char *buffer); static Decimal64 decimal64FromBID (const unsigned char *buffer); static Decimal128 decimal128FromBID(const unsigned char *buffer); // Return the native implementation representation of the value of the // same size base-10 floating-point value stored in Binary Integer // Decimal format at the specified 'buffer' address. The behavior is // undefined unless 'buffer' points to a memory area at least // 'sizeof(decimal)' in size containing a value in BID format. static void decimal32FromBID (Decimal32 *decimal, const unsigned char *buffer); static void decimal64FromBID (Decimal64 *decimal, const unsigned char *buffer); static void decimal128FromBID(Decimal128 *decimal, const unsigned char *buffer); static void decimalFromBID (Decimal32 *decimal, const unsigned char *buffer); static void decimalFromBID (Decimal64 *decimal, const unsigned char *buffer); static void decimalFromBID (Decimal128 *decimal, const unsigned char *buffer); // Store, into the specified 'decimal', the native implementation // representation of the value of the same size base-10 floating point // value represented in Binary Integer Decimal format, at the specified // 'buffer' address. The behavior is undefined unless 'buffer' points // to a memory area at least 'sizeof(decimal)' in size containing a // value in BID format. // decimalToNetwork functions static unsigned char *decimal32ToNetwork (unsigned char *buffer, Decimal32 decimal); static unsigned char *decimal64ToNetwork (unsigned char *buffer, Decimal64 decimal); static unsigned char *decimal128ToNetwork(unsigned char *buffer, Decimal128 decimal); static unsigned char *decimalToNetwork (unsigned char *buffer, Decimal32 decimal); static unsigned char *decimalToNetwork (unsigned char *buffer, Decimal64 decimal); static unsigned char *decimalToNetwork (unsigned char *buffer, Decimal128 decimal); // Store the specified 'decimal', in network format, into the specified // 'buffer' and return the address one past the last byte written into // the 'buffer'. The network format is defined as big endian byte // order and densely packed base-10 significand encoding. This // corresponds to the way IBM hardware represents these numbers in // memory. The behavior is undefined unless 'buffer' points to a // memory area at least 'sizeof(decimal)' in size. Note that these // functions always return 'buffer + sizeof(decimal)' on the supported // 8-bits-byte architectures. // decimalFromNetwork functions static const unsigned char *decimal32FromNetwork( Decimal32 *decimal, const unsigned char *buffer); static const unsigned char *decimal64FromNetwork( Decimal64 *decimal, const unsigned char *buffer); static const unsigned char *decimal128FromNetwork( Decimal128 *decimal, const unsigned char *buffer); static const unsigned char *decimalFromNetwork( Decimal32 *decimal, const unsigned char *buffer); static const unsigned char *decimalFromNetwork( Decimal64 *decimal, const unsigned char *buffer); static const unsigned char *decimalFromNetwork( Decimal128 *decimal, const unsigned char *buffer); // Store into the specified 'decimal', the value of the same size // base-10 floating-point value stored in network format at the // specified 'buffer' address and return the address one past the last // byte read from 'buffer'. The network format is defined as big // endian byte order and densely packed base-10 significand encoding. // This corresponds to the way IBM hardware represents these numbers in // memory. The behavior is undefined unless 'buffer' points to a // memory area at least 'sizeof(decimal)' bytes. Note that these // functions always return 'buffer + sizeof(decimal)' on the supported // 8-bits-byte architectures. static bsls::Types::size_type decimal64ToMultiWidthEncoding( unsigned char *buffer, bdldfp::Decimal64 decimal); // Store the specified 'decimal', in the *multi-width encoding* format, // into the specified 'buffer' and return the number of bytes used by // the encoding. The behavior is undefined unless 'buffer' points to a // memory area with enough room to hold the encode value (which has a // maximum size of 8 bytes). static bsls::Types::size_type decimal64ToMultiWidthEncodingRaw( unsigned char *buffer, bdldfp::Decimal64 decimal); // If the specified 'decimal' can be encoded in 5 or fewer bytes of the // *multi-width encoding* format, then store 'decimal' into the // specified 'buffer' in that format, and return the number of bytes // written to 'buffer'. Otherwise, return 0. The behavior is // undefined unless 'buffer' points to a memory area having at least 5 // bytes. Note that this function does not supporting encoding values // requiring a full IEEE network encoding, which is supported by the // 'decimal64ToMultiWidthEncoding' function. static Decimal64 decimal64FromMultiWidthEncodingRaw( const unsigned char *buffer, bsls::Types::size_type size); // Decode a decimal value in the *multi-width encoding* format from the // specified 'buffer' having the specified 'size'. Return the decoded // value. The behavior is undefined unless 'buffer' has at least // 'size' bytes, 'size' is a valid encoding size in the // 'multi-width encoding' format, and 'size <= 5'. Note that this // function does not support decoding values requiring a full IEEE // network encoding, which is supported by the // 'decimal64FromMultiWidthEncoding' function. static bool isValidMultiWidthSize(bsls::Types::size_type size); // Return 'true' if the specified 'size' is a valid encoding size in // the *multi-width encoding* format, and 'false' otherwise. Note that // valid encoding sizes are 1, 2, 3, 4, 5 and 8 bytes. static Decimal64 decimal64FromMultiWidthEncoding( const unsigned char *buffer, bsls::Types::size_type size); // Decode a decimal value in the *multi-width encoding* format from the // specified 'buffer' having the specified 'size'. Return the decoded // value. The behavior is undefined unless 'buffer' has at least // 'size' bytes, and 'size' is a valid encoding size in the // 'multi-width encoding' format. static int decimal64FromMultiWidthEncodingIfValid( Decimal64 *decimal, const unsigned char *buffer, bsls::Types::size_type size); // Decode a decimal value in the *multi-width encoding* format from the // specified 'buffer' having the specified 'size' and store the result // into the specified 'decimal' parameter. Return 0 on success, and // non-zero value otherwise. The behavior is undefined unless 'buffer' // has at least 'size' bytes. Note that this function returns a // non-zero value and leaves 'decimal' unchanged if 'size' is not a // valid encoding size of the *multi-width encoding* format. static unsigned char *decimal64ToVariableWidthEncoding( unsigned char *buffer, bdldfp::Decimal64 decimal); // Store the specified 'decimal', in the *variable-width encoding* // format, into the specified 'buffer' and return the address one past // the last byte written into the 'buffer'. The behavior is undefined // unless 'buffer' points to a memory area with enough room to hold the // encoded value (which has a maximum size of 9 bytes). static const unsigned char *decimal64FromVariableWidthEncoding( bdldfp::Decimal64 *decimal, const unsigned char *buffer); // Store into the specified 'decimal', the value of 'Decimal64' value // stored in the *variable-width encoding* format at the specified // 'buffer' address. Return the address one past the last byte read // from 'buffer'. The behavior is undefined unless 'buffer' points to // a memory area holding a 'Decimal64' value encoded in the // *variable-width encoding* format. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // PRIVATE CLASS METHODS inline int DecimalConvertUtil::decimal64ToUnpackedSpecial( bool *isNegative, int *biasedExponent, bsls::Types::Uint64 *mantissa, bdldfp::Decimal64 value) { #ifdef BDLDFP_DECIMALPLATFORM_INTELDFP bsls::Types::Uint64 bidValue = value.data()->d_raw; #else bsls::Types::Uint64 bidValue = bid_dpd_to_bid64( static_cast<bsls::Types::Uint64>(*(value.data()))); #endif // This class method is based on inteldfp 'unpack_BID64' (bid_internal.h), // with a non-zero return if 'SPECIAL_ENCODING_MASK64' indicates a special // encoding; these are practically non-existent and no need to optimize. if (BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY( (bidValue & k_SPECIAL_ENCODING_MASK64) == k_SPECIAL_ENCODING_MASK64)) { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; // punt on special encodings return -1; // RETURN } *isNegative = (bidValue & 0x8000000000000000ull) ? 1 : 0; *biasedExponent = static_cast<int>( (bidValue >> k_EXPONENT_SHIFT_SMALL64) & k_EXPONENT_MASK64); *mantissa = bidValue & k_SMALL_COEFF_MASK64; return 0; } inline Decimal64 DecimalConvertUtil::decimal64FromUnpackedSpecial( bool isNegative, bsls::Types::Uint64 mantissa, int exponent) { #ifdef BDLDFP_DECIMALPLATFORM_INTELDFP bdldfp::Decimal64 result; result.data()->d_raw = (isNegative ? 0x8000000000000000ull : 0) | (static_cast<BID_UINT64>(exponent + 398) << k_EXPONENT_SHIFT_SMALL64) | mantissa; return result; #else if (isNegative) { return DecimalImpUtil::makeDecimalRaw64( -static_cast<long long>(mantissa), exponent); } else { return DecimalImpUtil::makeDecimalRaw64(mantissa, exponent); } #endif } inline Decimal64 DecimalConvertUtil::decimal64FromUnpackedSpecial(int mantissa, int exponent) { #ifdef BDLDFP_DECIMALPLATFORM_INTELDFP bdldfp::Decimal64 result; result.data()->d_raw = (static_cast<BID_UINT64>(exponent + 398) << k_EXPONENT_SHIFT_SMALL64) | mantissa; return result; #else return DecimalUtil::makeDecimalRaw64(mantissa, exponent); #endif } // CLASS METHODS inline bsls::Types::size_type DecimalConvertUtil::decimal64ToMultiWidthEncoding( unsigned char *buffer, bdldfp::Decimal64 decimal) { bsls::Types::size_type size = decimal64ToMultiWidthEncodingRaw(buffer, decimal); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(size != 0)) { return size; // RETURN } else { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; bsls::Types::Uint64 encoded; bsl::memcpy(reinterpret_cast<unsigned char *>(&encoded), decimal.data(), sizeof(encoded)); encoded = BSLS_BYTEORDER_HTONLL(encoded); bsl::memcpy(buffer, reinterpret_cast<unsigned char*>(&encoded), 8); return 8; // RETURN } } inline bsls::Types::size_type DecimalConvertUtil::decimal64ToMultiWidthEncodingRaw( unsigned char *buffer, bdldfp::Decimal64 decimal) { bool isNegative; int exponent; bsls::Types::Uint64 mantissa; // 'exponent' is biased --> biased exponent = exponent + 398 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(0 == decimal64ToUnpackedSpecial(&isNegative, &exponent, &mantissa, decimal))) { if (!isNegative) { if (395 <= exponent && exponent < 399) { if (mantissa < (1u << 14)) { unsigned short squished = static_cast<unsigned short>( mantissa | (exponent - 395) << 14); unsigned short squishedN = BSLS_BYTEORDER_HTONS(squished); bsl::memcpy(buffer, &squishedN, 2); return 2; // RETURN } } if (392 <= exponent && exponent < 400) { if (mantissa < (1u << 21)) { // On IBM (and Linux to a lesser extent), copying from a // word-aligned source is faster, so we shift an extra the // source by an extra 8 bits. unsigned int squished = static_cast<unsigned int>( (mantissa << 8) | (exponent - 392) << 29); unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished); bsl::memcpy(buffer, reinterpret_cast<unsigned char*>(&squishedN), 3); return 3; // RETURN } } } if (382 <= exponent && exponent < 414) { if (mantissa < (1u << 26)) { unsigned int squished = static_cast<unsigned int>( mantissa | (exponent - 382) << 26); if (isNegative) { squished |= 1u << 31; } unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished); bsl::memcpy(buffer, &squishedN, 4); return 4; // RETURN } if (mantissa < (1ull << 34)) { bsls::Types::Uint64 squished = static_cast<bsls::Types::Uint64>( (mantissa << 24) | (static_cast<bsls::Types::Uint64>(exponent - 382) << 58)); if (isNegative) { squished |= 1ull << 63; } bsls::Types::Uint64 squishedN = BSLS_BYTEORDER_HTONLL(squished); bsl::memcpy(buffer, reinterpret_cast<unsigned char*>(&squishedN), 5); return 5; // RETURN } } } return 0; } inline bool DecimalConvertUtil::isValidMultiWidthSize(bsls::Types::size_type size) { return (size > 0 && size <= 5) || size == 8; } inline Decimal64 DecimalConvertUtil::decimal64FromMultiWidthEncoding( const unsigned char *buffer, bsls::Types::size_type size) { BSLS_ASSERT(1 <= size); BSLS_ASSERT(size <= 5 || size == 8); if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(size < 6)) { return decimal64FromMultiWidthEncodingRaw(buffer, size); // RETURN } else { BSLS_PERFORMANCEHINT_UNLIKELY_HINT; bsls::Types::Uint64 encoded; bsl::memcpy(&encoded, buffer, 8); encoded = BSLS_BYTEORDER_NTOHLL(encoded); DecimalImpUtil::ValueType64 decimal; bsl::memcpy(&decimal, &encoded, sizeof(decimal)); return decimal; // RETURN } } inline int DecimalConvertUtil::decimal64FromMultiWidthEncodingIfValid( Decimal64 *decimal, const unsigned char *buffer, bsls::Types::size_type size) { int ret(0); if (isValidMultiWidthSize(size)) { *decimal = decimal64FromMultiWidthEncoding(buffer, size); } else { ret = 1; } return ret; } inline Decimal64 DecimalConvertUtil::decimal64FromMultiWidthEncodingRaw( const unsigned char *buffer, bsls::Types::size_type size) { BSLS_ASSERT(1 <= size); BSLS_ASSERT(size <= 5); switch(size) { case 2: { int exponent = (buffer[0] >> 6) - 3; int mantissa = static_cast<int>(((buffer[0] & 0x3F) << 8) | static_cast<int>(buffer[1])); return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN } break; case 3: { int exponent = (buffer[0] >> 5) - 6; int mantissa = static_cast<int>(((buffer[0] & 0x1F) << 16) | static_cast<int>(buffer[1]) << 8 | static_cast<int>(buffer[2])); return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN } break; case 4: { bool isNegative = buffer[0] >> 7; int exponent = ((buffer[0] & 0x7F) >> 2) - 16; int mantissa = static_cast<int>(((buffer[0] & 0x03) << 24) | static_cast<int>(buffer[1]) << 16 | static_cast<int>(buffer[2]) << 8 | static_cast<int>(buffer[3])); return decimal64FromUnpackedSpecial(isNegative, mantissa, exponent); // RETURN } break; case 1: { int exponent = (buffer[0] >> 7) - 2; int mantissa = static_cast<int>(buffer[0] & 0x7F); return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN } break; #ifdef BSLS_PLATFORM_CMP_IBM case 5: #else default: #endif { // Xlc optimizes better when 'case 5:' is used instead of 'default:', // and vice versa for gcc. bool isNegative = buffer[0] >> 7; int exponent = ((buffer[0] & 0x7F) >> 2) - 16; bsls::Types::Uint64 mantissa = static_cast<bsls::Types::Uint64>( static_cast<bsls::Types::Uint64>(buffer[0] & 0x03) << 32 | static_cast<bsls::Types::Uint64>(buffer[1]) << 24 | static_cast<bsls::Types::Uint64>(buffer[2]) << 16 | static_cast<bsls::Types::Uint64>(buffer[3]) << 8 | static_cast<bsls::Types::Uint64>(buffer[4])); return decimal64FromUnpackedSpecial(isNegative, mantissa, exponent); // RETURN } break; } #ifdef BSLS_PLATFORM_CMP_IBM // From here on, the function has undefined behavior. We will return a // default constructed value to suppress compiler warnings. return bdldfp::Decimal64(); #endif } inline unsigned char *DecimalConvertUtil::decimal64ToVariableWidthEncoding( unsigned char *buffer, bdldfp::Decimal64 decimal) { bool isNegative; int exponent; bsls::Types::Uint64 mantissa; // 'exponent' is biased --> biased exponent = exponent + 398 if (BSLS_PERFORMANCEHINT_PREDICT_LIKELY(0 == decimal64ToUnpackedSpecial(&isNegative, &exponent, &mantissa, decimal))) { if (!isNegative) { if (396 <= exponent && exponent < 400) { if (mantissa < (1u << 13)) { // The predicate disambiguation bit is implicitly 0. unsigned short squished = static_cast<unsigned short>( mantissa | (exponent - 396) << 13); unsigned short squishedN = BSLS_BYTEORDER_HTONS(squished); bsl::memcpy(buffer, &squishedN, 2); return buffer + 2; // RETURN } } if (394 <= exponent && exponent < 402) { if (mantissa < (1u << 19)) { // On IBM (and Linux to a lesser extent), copying from a // word-aligned source is faster, so we shift the source of // memcpy by an extra 8 bits. unsigned int squished = static_cast<unsigned int>( (mantissa << 8) | (exponent - 394) << 27); // The predicate bits should be 0b10. squished |= 1u << 31; unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished); bsl::memcpy(buffer, reinterpret_cast<unsigned char*>(&squishedN), 3); return buffer + 3; // RETURN } } } // If the value is negative, with exponent of 15 (biased exponent 413), // then the first byte will have a value of FF, which is the state used // to indicate that a full 9 byte representation should be used. if (382 <= exponent && (exponent < 413 || (!isNegative && exponent == 413))) { if (mantissa < (1u << 24)) { unsigned int squished = static_cast<unsigned int>( mantissa | (exponent - 382) << 24); if (isNegative) { squished |= 1u << 29; } // The predicate bits should be 11. squished |= 3u << 30; unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished); bsl::memcpy(buffer, &squishedN, 4); return buffer + 4; // RETURN } } } *buffer++ = 0xFF; bsls::Types::Uint64 encoded; bsl::memcpy(reinterpret_cast<unsigned char *>(&encoded), decimal.data(), sizeof(encoded)); encoded = BSLS_BYTEORDER_HTONLL(encoded); bsl::memcpy(buffer, reinterpret_cast<unsigned char*>(&encoded), 8); return buffer + 8; } inline const unsigned char *DecimalConvertUtil::decimal64FromVariableWidthEncoding( bdldfp::Decimal64 *decimal, const unsigned char *buffer) { if (!(*buffer & 0x80)) { // 2-byte encoding is used. int exponent = (buffer[0] >> 5) - 2; int mantissa = static_cast<int>(((buffer[0] & 0x1F) << 8) | static_cast<int>(buffer[1])); *decimal = decimal64FromUnpackedSpecial(mantissa, exponent); return buffer + 2; // RETURN } else if ((*buffer & 0xC0) == 0x80) { // 3-byte encoding is used. unsigned char eByte1 = buffer[0] & 0x3F; int exponent = (eByte1 >> 3) - 4; int mantissa = static_cast<int>(((eByte1 & 0x07) << 16) | static_cast<int>(buffer[1] << 8) | static_cast<int>(buffer[2])); *decimal = decimal64FromUnpackedSpecial(mantissa, exponent); return buffer + 3; // RETURN } else if (*buffer == 0xFF) { // Full 9-byte encoding is used. ++buffer; bsls::Types::Uint64 encoded; bsl::memcpy(&encoded, buffer, 8); encoded = BSLS_BYTEORDER_NTOHLL(encoded); bsl::memcpy(decimal, reinterpret_cast<unsigned char *>(&encoded), sizeof(*decimal)); return buffer + 8; // RETURN } else { // Here, the condition ((*buffer & 0xC0) == 0xC0) is true, and so the // 4-byte encoding is used. unsigned char eByte1 = buffer[0] & 0x3F; bool isNegative = eByte1 >> 5; int exponent = (eByte1 & 0x1F) - 16; int mantissa = static_cast<int>(static_cast<int>(buffer[1] << 16) | static_cast<int>(buffer[2] << 8) | static_cast<int>(buffer[3])); *decimal = decimal64FromUnpackedSpecial(isNegative, mantissa, exponent); return buffer + 4; // RETURN } } // decimalToDouble functions inline double DecimalConvertUtil::decimal32ToDouble(Decimal32 decimal) { return Imp::decimalToDouble(decimal); } inline double DecimalConvertUtil::decimal64ToDouble(Decimal64 decimal) { return Imp::decimalToDouble(decimal); } inline double DecimalConvertUtil::decimal128ToDouble(Decimal128 decimal) { return Imp::decimalToDouble(decimal); } inline double DecimalConvertUtil::decimalToDouble(Decimal32 decimal) { return Imp::decimalToDouble(decimal); } inline double DecimalConvertUtil::decimalToDouble(Decimal64 decimal) { return Imp::decimalToDouble(decimal); } inline double DecimalConvertUtil::decimalToDouble(Decimal128 decimal) { return Imp::decimalToDouble(decimal); } // decimalToFloat functions inline float DecimalConvertUtil::decimal32ToFloat(Decimal32 decimal) { return Imp::decimalToFloat(decimal); } inline float DecimalConvertUtil::decimal64ToFloat(Decimal64 decimal) { return Imp::decimalToFloat(decimal); } inline float DecimalConvertUtil::decimal128ToFloat(Decimal128 decimal) { return Imp::decimalToFloat(decimal); } inline float DecimalConvertUtil::decimalToFloat(Decimal32 decimal) { return Imp::decimalToFloat(decimal); } inline float DecimalConvertUtil::decimalToFloat(Decimal64 decimal) { return Imp::decimalToFloat(decimal); } inline float DecimalConvertUtil::decimalToFloat(Decimal128 decimal) { return Imp::decimalToFloat(decimal); } // decimalToDPD functions inline void DecimalConvertUtil::decimal32ToDPD(unsigned char *buffer, Decimal32 decimal) { Imp::decimalToDPD(buffer, decimal); } inline void DecimalConvertUtil::decimal64ToDPD(unsigned char *buffer, Decimal64 decimal) { Imp::decimalToDPD(buffer, decimal); } inline void DecimalConvertUtil::decimal128ToDPD(unsigned char *buffer, Decimal128 decimal) { Imp::decimalToDPD(buffer, decimal); } inline void DecimalConvertUtil::decimalToDPD(unsigned char *buffer, Decimal32 decimal) { Imp::decimalToDPD(buffer, decimal); } inline void DecimalConvertUtil::decimalToDPD(unsigned char *buffer, Decimal64 decimal) { Imp::decimalToDPD(buffer, decimal); } inline void DecimalConvertUtil::decimalToDPD(unsigned char *buffer, Decimal128 decimal) { Imp::decimalToDPD(buffer, decimal); } // decimalFromDPD functions inline Decimal32 DecimalConvertUtil::decimal32FromDPD(const unsigned char *buffer) { return Imp::decimal32FromDPD(buffer); } inline void DecimalConvertUtil::decimal32FromDPD(Decimal32 *decimal, const unsigned char *buffer) { *decimal = Imp::decimal32FromDPD(buffer); } inline Decimal64 DecimalConvertUtil::decimal64FromDPD(const unsigned char *buffer) { return Imp::decimal64FromDPD(buffer); } inline void DecimalConvertUtil::decimal64FromDPD(Decimal64 *decimal, const unsigned char *buffer) { *decimal = Imp::decimal64FromDPD(buffer); } inline Decimal128 DecimalConvertUtil::decimal128FromDPD(const unsigned char *buffer) { return Imp::decimal128FromDPD(buffer); } inline void DecimalConvertUtil::decimal128FromDPD(Decimal128 *decimal, const unsigned char *buffer) { *decimal = Imp::decimal128FromDPD(buffer); } inline void DecimalConvertUtil::decimalFromDPD(Decimal32 *decimal, const unsigned char *buffer) { Imp::decimalFromDPD(decimal, buffer); } inline void DecimalConvertUtil::decimalFromDPD(Decimal64 *decimal, const unsigned char *buffer) { Imp::decimalFromDPD(decimal, buffer); } inline void DecimalConvertUtil::decimalFromDPD(Decimal128 *decimal, const unsigned char *buffer) { Imp::decimalFromDPD(decimal, buffer); } // decimalToBID functions inline void DecimalConvertUtil::decimal32ToBID(unsigned char *buffer, Decimal32 decimal) { Imp::decimalToBID(buffer, decimal); } inline void DecimalConvertUtil::decimal64ToBID(unsigned char *buffer, Decimal64 decimal) { Imp::decimalToBID(buffer, decimal); } inline void DecimalConvertUtil::decimal128ToBID(unsigned char *buffer, Decimal128 decimal) { Imp::decimalToBID(buffer, decimal); } inline void DecimalConvertUtil::decimalToBID(unsigned char *buffer, Decimal32 decimal) { Imp::decimalToBID(buffer, decimal); } inline void DecimalConvertUtil::decimalToBID(unsigned char *buffer, Decimal64 decimal) { Imp::decimalToBID(buffer, decimal); } inline void DecimalConvertUtil::decimalToBID(unsigned char *buffer, Decimal128 decimal) { Imp::decimalToBID(buffer, decimal); } // decimalFromBID functions inline Decimal32 DecimalConvertUtil::decimal32FromBID(const unsigned char *buffer) { return Imp::decimal32FromBID(buffer); } inline void DecimalConvertUtil::decimal32FromBID(Decimal32 *decimal, const unsigned char *buffer) { *decimal = Imp::decimal32FromBID(buffer); } inline Decimal64 DecimalConvertUtil::decimal64FromBID(const unsigned char *buffer) { return Imp::decimal64FromBID(buffer); } inline void DecimalConvertUtil::decimal64FromBID(Decimal64 *decimal, const unsigned char *buffer) { *decimal = Imp::decimal64FromBID(buffer); } inline Decimal128 DecimalConvertUtil::decimal128FromBID(const unsigned char *buffer) { return Imp::decimal128FromBID(buffer); } inline void DecimalConvertUtil::decimal128FromBID(Decimal128 *decimal, const unsigned char *buffer) { *decimal = Imp::decimal128FromBID(buffer); } inline void DecimalConvertUtil::decimalFromBID(Decimal32 *decimal, const unsigned char *buffer) { Imp::decimalFromBID(decimal, buffer); } inline void DecimalConvertUtil::decimalFromBID(Decimal64 *decimal, const unsigned char *buffer) { Imp::decimalFromBID(decimal, buffer); } inline void DecimalConvertUtil::decimalFromBID(Decimal128 *decimal, const unsigned char *buffer) { Imp::decimalFromBID(decimal, buffer); } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2014 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------