diff --git a/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_four_over_pi.c b/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_four_over_pi.c index d26acd6d62..219a4695ec 100644 --- a/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_four_over_pi.c +++ b/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_four_over_pi.c @@ -28,11 +28,12 @@ ******************************************************************************/ #include "dpml_private.h" +#include "bid_conf.h" #ifndef DEFINES - const unsigned __int64 __four_over_pi[] = { + BID_EXTERN_C const unsigned __int64 __four_over_pi[] = { 0x0000000000000000ull, 0x0000000000000000ull, 0x0028be60db939105ull, 0x4a7f09d5f47d4d37ull, 0x7036d8a5664f10e4ull, 0x107f9458eaf7aef1ull, diff --git a/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_pow_t_table.c b/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_pow_t_table.c index d93da26350..984c39b890 100644 --- a/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_pow_t_table.c +++ b/groups/bdl/bdl+inteldfp/LIBRARY/float128/dpml_pow_t_table.c @@ -43,7 +43,7 @@ #if !DEFINE_SYMBOLIC_CONSTANTS - const unsigned int TABLE_NAME[] = { + BID_EXTERN_C const unsigned int TABLE_NAME[] = { /* * Tj = 2^(j/2^POW2_K) and Rj = [2^(j/2^POW2_K) - Tj]/Tj. diff --git a/groups/bdl/bdl+inteldfp/LIBRARY/float128/sqrt_tab_t.c b/groups/bdl/bdl+inteldfp/LIBRARY/float128/sqrt_tab_t.c index 74376e73b1..fd98ba9976 100644 --- a/groups/bdl/bdl+inteldfp/LIBRARY/float128/sqrt_tab_t.c +++ b/groups/bdl/bdl+inteldfp/LIBRARY/float128/sqrt_tab_t.c @@ -28,6 +28,7 @@ ******************************************************************************/ #include "dpml_ux.h" +#include "bid_conf.h" #define NUM_FRAC_BITS 7 @@ -36,7 +37,7 @@ typedef struct { double c; } SQRT_COEF_STRUCT; -const SQRT_COEF_STRUCT D_SQRT_TABLE_NAME[(1<<(NUM_FRAC_BITS+1))] = { +BID_EXTERN_C const SQRT_COEF_STRUCT D_SQRT_TABLE_NAME[(1<<(NUM_FRAC_BITS+1))] = { /* diff --git a/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.cpp b/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.cpp new file mode 100644 index 0000000000..f04e3b2f76 --- /dev/null +++ b/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.cpp @@ -0,0 +1,21 @@ +// bdldfp_binaryintegraldecimalimputil.cpp -*-C++-*- +#include + +#include +BSLS_IDENT_RCSID(bdldfp_binaryintegraldecimalimputil_cpp,"$Id$ $CSID$") + +// ---------------------------------------------------------------------------- +// 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 ---------------------------------- diff --git a/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.h b/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.h new file mode 100644 index 0000000000..4a1e876858 --- /dev/null +++ b/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.h @@ -0,0 +1,82 @@ +// bdldfp_binaryintegraldecimalimputil.h -*-C++-*- +#ifndef INCLUDED_BDLDFP_BINARYINTEGRALDECIMALIMPUTIL +#define INCLUDED_BDLDFP_BINARYINTEGRALDECIMALIMPUTIL + +#ifndef INCLUDED_BSLS_IDENT +#include +#endif +BSLS_IDENT("$Id$") + +//@PURPOSE: Utilities for working with Binary Integral Decimal representation. +// +//@CLASSES: +// bdldfp::BinaryIntegralDecimalImpUtil: namespace for BID functions. +// +//@SEE_ALSO: bdldfp_decimal, bdldfp_decimalplatform, +// bdldfp_denselypackeddecimalimputil +// +//@DESCRIPTION: This component provides a namespace, +// 'bdldfp::BinaryIntegralDecimalImpUtil', that supplies the necessary types +// for storing a Binary Integral Decimal (BID) representation of a decimal +// floating point value. +// +///Usage +///----- +// This section shows the intended use of this component. +// +///Example 1: none +///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +#ifndef INCLUDED_BDLSCM_VERSION +#include +#endif + +#ifndef INCLUDED_BDLDFP_DECIMALPLATFORM +#include +#endif + +#ifndef INCLUDED_BDLDFP_UINT128 +#include +#endif + +#ifndef INCLUDED_DENSELYPACKEDDECIMALIMPUTIL +#include +#endif + +namespace BloombergLP { +namespace bdldfp { + + // ================================== + // class BinaryIntegralDecimalImpUtil + // ================================== + +struct BinaryIntegralDecimalImpUtil { + // This 'struct' provides a namespace for functions that provide common DPD + // formatted decimal floating point. + + // TYPES + struct StorageType32 { unsigned int d_raw; }; + struct StorageType64 { unsigned long long int d_raw; }; + struct StorageType128 { bdldfp::Uint128 d_raw; }; +}; + +} // 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 ---------------------------------- diff --git a/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.t.cpp b/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.t.cpp new file mode 100644 index 0000000000..0a4dd8f6d2 --- /dev/null +++ b/groups/bdl/bdldfp/bdldfp_binaryintegraldecimalimputil.t.cpp @@ -0,0 +1,26 @@ +// bdldfp_binaryintegraldecimalimputil.t.cpp -*-C++-*- +#include + +#include +BSLS_IDENT("$Id$") + +int main(int , char **) +{ + return -1; +} + +// ---------------------------------------------------------------------------- +// 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 ---------------------------------- diff --git a/groups/bdl/bdldfp/bdldfp_decimalconvertutil.cpp b/groups/bdl/bdldfp/bdldfp_decimalconvertutil.cpp index 5d05f743aa..b113e93392 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalconvertutil.cpp +++ b/groups/bdl/bdldfp/bdldfp_decimalconvertutil.cpp @@ -20,9 +20,7 @@ BSLS_IDENT_RCSID(bdldfp_decimalconvertutil_cpp,"$Id$ $CSID$") #include #include -#include #include // TODO TBD - remove this, it is just for debugging -#include namespace BloombergLP { namespace bdldfp { diff --git a/groups/bdl/bdldfp/bdldfp_decimalconvertutil.h b/groups/bdl/bdldfp/bdldfp_decimalconvertutil.h index bb9d1cafb0..72cca39c7a 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalconvertutil.h +++ b/groups/bdl/bdldfp/bdldfp_decimalconvertutil.h @@ -17,8 +17,122 @@ BSLS_IDENT("$Id$") //@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 format (big endian, -// DPD encoded decimals). +// 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 signficant | +// |------|----------|----------|-----|----------|----------------| +// | 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%). Perserving 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. // ///Usage ///----- @@ -95,6 +209,10 @@ BSLS_IDENT("$Id$") #include #endif +#ifndef INCLUDED_BDLDFP_DECIMALUTIL +#include +#endif + #ifndef INCLUDED_BDLDFP_DECIMALCONVERTUTIL_DECNUMBER #include #endif @@ -115,8 +233,23 @@ BSLS_IDENT("$Id$") #include #endif +#ifndef INCLUDED_BSLS_PERFORMANCEHINT +#include +#endif + +#ifndef INCLUDED_BSLS_PLATFORM +#include +#endif + namespace BloombergLP { namespace bdldfp { + +#define BDLDFP_DU_INTELDFP_EXPONENT_SHIFT_SMALL64 53 +#define BDLDFP_DU_INTELDFP_SPECIAL_ENCODING_MASK64 0x6000000000000000ull + +#define BDLDFP_DU_INTELDFP_EXPONENT_MASK64 0x3ff +#define BDLDFP_DU_INTELDFP_SMALL_COEFF_MASK64 0x001fffffffffffffull + // ======================== // class DecimalConvertUtil // ======================== @@ -137,6 +270,44 @@ struct DecimalConvertUtil { BSLMF_ASSERT(false); #endif + // 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 specified + // '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 @@ -299,6 +470,59 @@ struct DecimalConvertUtil { // *not* to create a decimal from the exact base-2 value. Use the // conversion constructors when you are not restoring a decimal. + // decimalToBinaryIntegral functions + + static void decimal32ToBinaryIntegral( unsigned char *buffer, + Decimal32 decimal); + static void decimal64ToBinaryIntegral( unsigned char *buffer, + Decimal64 decimal); + static void decimal128ToBinaryIntegral(unsigned char *buffer, + Decimal128 decimal); + static void decimalToBinaryIntegral( unsigned char *buffer, + Decimal32 decimal); + static void decimalToBinaryIntegral( unsigned char *buffer, + Decimal64 decimal); + static void decimalToBinaryIntegral( unsigned char *buffer, + Decimal128 decimal); + // Populate the specified 'buffer' with the Binary Integral 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. + + // decimalFromBinaryIntegral functions + + static Decimal32 decimal32FromBinaryIntegral( const unsigned char *buffer); + static Decimal64 decimal64FromBinaryIntegral( const unsigned char *buffer); + static Decimal128 decimal128FromBinaryIntegral(const unsigned char *buffer); + // Return the native implementation representation of the value of the + // same size base-10 floating-point value stored in Binary Integral + // 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 decimalFromBinaryIntegral( Decimal32 *decimal, + const unsigned char *buffer); + static void decimalFromBinaryIntegral( Decimal64 *decimal, + const unsigned char *buffer); + static void decimalFromBinaryIntegral( Decimal128 *decimal, + const unsigned char *buffer); + static void decimal32FromBinaryIntegral( Decimal32 *decimal, + const unsigned char *buffer); + static void decimal64FromBinaryIntegral( Decimal64 *decimal, + const unsigned char *buffer); + static void decimal128FromBinaryIntegral(Decimal128 *decimal, + const unsigned char *buffer); + // Store, into the specified 'decimal', the native implmentation + // representation of the value of the same size base-10 floating point + // value represented in Binary Integral 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. + + // decimalToDenselyPacked functions static void decimal32ToDenselyPacked( unsigned char *buffer, @@ -400,6 +624,66 @@ struct DecimalConvertUtil { // 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( + 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 Decimal64 decimal64FromMultiWidthEncoding( + 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 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 unsigned char *decimal64FromVariableWidthEncoding( + bdldfp::Decimal64 *decimal, + 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. }; // ============================================================================ @@ -407,6 +691,430 @@ struct DecimalConvertUtil { // ============================================================================ +// 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(*(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 & BDLDFP_DU_INTELDFP_SPECIAL_ENCODING_MASK64) == + BDLDFP_DU_INTELDFP_SPECIAL_ENCODING_MASK64)) { + BSLS_PERFORMANCEHINT_UNLIKELY_HINT; + // punt on special encodings + return -1; + } + + *isNegative = (bidValue & 0x8000000000000000ull) ? 1 : 0; + + *biasedExponent = static_cast( + (bidValue >> BDLDFP_DU_INTELDFP_EXPONENT_SHIFT_SMALL64) & + BDLDFP_DU_INTELDFP_EXPONENT_MASK64); + + *mantissa = bidValue & BDLDFP_DU_INTELDFP_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(exponent + 398) + << BDLDFP_DU_INTELDFP_EXPONENT_SHIFT_SMALL64) | + mantissa; + return result; +#else + if (isNegative) { + return DecimalImpUtil::makeDecimalRaw64( + -static_cast(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(exponent + 398) + << BDLDFP_DU_INTELDFP_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; + decimal64ToBinaryIntegral(reinterpret_cast(&encoded), + decimal); + + encoded = BSLS_BYTEORDER_HTONLL(encoded); + + bsl::memcpy(buffer, + reinterpret_cast(&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( + 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( + (mantissa << 8) | (exponent - 392) << 29); + unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished); + + bsl::memcpy(buffer, + reinterpret_cast(&squishedN), + 3); + return 3; // RETURN + } + } + } + + if (382 <= exponent && exponent < 414) { + if (mantissa < (1u << 26)) { + unsigned int squished = static_cast( + 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( + (mantissa << 24) | + (static_cast(exponent - 382) << 58)); + if (isNegative) { + squished |= 1ull << 63; + } + bsls::Types::Uint64 squishedN = + BSLS_BYTEORDER_HTONLL(squished); + bsl::memcpy(buffer, + reinterpret_cast(&squishedN), + 5); + return 5; // RETURN + } + } + } + + return 0; +} + +inline +Decimal64 DecimalConvertUtil::decimal64FromMultiWidthEncoding( + 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); + + return decimal64FromBinaryIntegral( + reinterpret_cast(&encoded)); + // RETURN + } +} + +inline +Decimal64 DecimalConvertUtil::decimal64FromMultiWidthEncodingRaw( + 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(((buffer[0] & 0x3F) << 8) | + static_cast(buffer[1])); + + return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN + } break; + case 3: { + int exponent = (buffer[0] >> 5) - 6; + int mantissa = static_cast(((buffer[0] & 0x1F) << 16) | + static_cast(buffer[1]) << 8 | + static_cast(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(((buffer[0] & 0x03) << 24) | + static_cast(buffer[1]) << 16 | + static_cast(buffer[2]) << 8 | + static_cast(buffer[3])); + return decimal64FromUnpackedSpecial(isNegative, mantissa, exponent); + // RETURN + } break; + case 1: { + int exponent = (buffer[0] >> 7) - 2; + int mantissa = static_cast(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( + static_cast(buffer[0] & 0x03) << 32 | + static_cast(buffer[1]) << 24 | + static_cast(buffer[2]) << 16 | + static_cast(buffer[3]) << 8 | + static_cast(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( + 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( + (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(&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( + 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; + decimal64ToBinaryIntegral(reinterpret_cast(&encoded), + decimal); + + encoded = BSLS_BYTEORDER_HTONLL(encoded); + + bsl::memcpy(buffer, reinterpret_cast(&encoded), 8); + + return buffer + 8; +} + +inline +unsigned char *DecimalConvertUtil::decimal64FromVariableWidthEncoding( + bdldfp::Decimal64 *decimal, + unsigned char *buffer) +{ + if (!(*buffer & 0x80)) { + + // 2-byte encoding is used. + + int exponent = (buffer[0] >> 5) - 2; + int mantissa = static_cast(((buffer[0] & 0x1F) << 8) | + static_cast(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(((eByte1 & 0x07) << 16) | + static_cast(buffer[1] << 8) | + static_cast(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); + + decimal64FromBinaryIntegral( + decimal, + reinterpret_cast(&encoded)); + + 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(static_cast(buffer[1] << 16) | + static_cast(buffer[2] << 8) | + static_cast(buffer[3])); + + *decimal = decimal64FromUnpackedSpecial(isNegative, + mantissa, + exponent); + return buffer + 4; // RETURN + } +} + // decimalToDouble functions inline @@ -483,6 +1191,181 @@ float DecimalConvertUtil::decimalToFloat(Decimal128 decimal) return Imp::decimalToFloat(decimal); } + // decimalToBinaryIntegral functions + +inline +void DecimalConvertUtil::decimal32ToBinaryIntegral(unsigned char *buffer, + Decimal32 decimal) +{ + BinaryIntegralDecimalImpUtil::StorageType32 result; + + result = DecimalImpUtil::convertToBinaryIntegral(*decimal.data()); + + memcpy(buffer, &result, sizeof(result)); +} + +inline +void DecimalConvertUtil::decimal64ToBinaryIntegral(unsigned char *buffer, + Decimal64 decimal) +{ + BinaryIntegralDecimalImpUtil::StorageType64 result; + + result = DecimalImpUtil::convertToBinaryIntegral(*decimal.data()); + + memcpy(buffer, &result, sizeof(result)); +} + +inline +void DecimalConvertUtil::decimal128ToBinaryIntegral(unsigned char *buffer, + Decimal128 decimal) +{ + BinaryIntegralDecimalImpUtil::StorageType128 result; + + result = DecimalImpUtil::convertToBinaryIntegral(*decimal.data()); + + memcpy(buffer, &result, sizeof(result)); +} + +inline +void DecimalConvertUtil::decimalToBinaryIntegral(unsigned char *buffer, + Decimal32 decimal) +{ + BinaryIntegralDecimalImpUtil::StorageType32 result; + + result = DecimalImpUtil::convertToBinaryIntegral(*decimal.data()); + + memcpy(buffer, &result, sizeof(result)); +} + +inline +void DecimalConvertUtil::decimalToBinaryIntegral(unsigned char *buffer, + Decimal64 decimal) +{ + BinaryIntegralDecimalImpUtil::StorageType64 result; + + result = DecimalImpUtil::convertToBinaryIntegral(*decimal.data()); + + memcpy(buffer, &result, sizeof(result)); +} + +inline +void DecimalConvertUtil::decimalToBinaryIntegral(unsigned char *buffer, + Decimal128 decimal) +{ + BinaryIntegralDecimalImpUtil::StorageType128 result; + + result = DecimalImpUtil::convertToBinaryIntegral(*decimal.data()); + + memcpy(buffer, &result, sizeof(result)); +} + + // decimalFromBinaryIntegral functions + +inline +Decimal32 +DecimalConvertUtil::decimal32FromBinaryIntegral(const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType32 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + return Decimal32(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +Decimal64 +DecimalConvertUtil::decimal64FromBinaryIntegral(const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType64 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + return Decimal64(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +Decimal128 +DecimalConvertUtil::decimal128FromBinaryIntegral(const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType128 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + return Decimal128(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +void +DecimalConvertUtil::decimalFromBinaryIntegral(Decimal32 *decimal, + const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType32 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + *decimal = Decimal32(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +void +DecimalConvertUtil::decimalFromBinaryIntegral(Decimal64 *decimal, + const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType64 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + *decimal = Decimal64(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +void +DecimalConvertUtil::decimalFromBinaryIntegral(Decimal128 *decimal, + const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType128 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + *decimal = Decimal128(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +void +DecimalConvertUtil::decimal32FromBinaryIntegral(Decimal32 *decimal, + const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType32 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + *decimal = Decimal32(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +void +DecimalConvertUtil::decimal64FromBinaryIntegral(Decimal64 *decimal, + const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType64 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + *decimal = Decimal64(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + +inline +void +DecimalConvertUtil::decimal128FromBinaryIntegral(Decimal128 *decimal, + const unsigned char *buffer) +{ + BinaryIntegralDecimalImpUtil::StorageType128 bid; + + memcpy(&bid, buffer, sizeof(bid)); + + *decimal = Decimal128(DecimalImpUtil::convertFromBinaryIntegral(bid)); +} + // decimalToDenselyPacked functions inline @@ -501,7 +1384,7 @@ void DecimalConvertUtil::decimal64ToDenselyPacked(unsigned char *buffer, inline void DecimalConvertUtil::decimal128ToDenselyPacked(unsigned char *buffer, - Decimal128 decimal) + Decimal128 decimal) { Imp::decimalToDenselyPacked(buffer, decimal); } @@ -527,7 +1410,6 @@ void DecimalConvertUtil::decimalToDenselyPacked(unsigned char *buffer, Imp::decimalToDenselyPacked(buffer, decimal); } - // decimalFromDenselyPacked functions inline @@ -599,7 +1481,6 @@ DecimalConvertUtil::decimal128FromDenselyPacked(Decimal128 *decimal, *decimal = Imp::decimal128FromDenselyPacked(buffer); } - } // close package namespace } // close enterprise namespace diff --git a/groups/bdl/bdldfp/bdldfp_decimalconvertutil.t.cpp b/groups/bdl/bdldfp/bdldfp_decimalconvertutil.t.cpp index 36eb1177d2..83be9be4e6 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalconvertutil.t.cpp +++ b/groups/bdl/bdldfp/bdldfp_decimalconvertutil.t.cpp @@ -2,29 +2,32 @@ #include +#include + +#include +#include + +#include + +#include +#include + #include +#include #include #include #include #include #include #include +#include #include -#include -#include - -#include - #include using namespace BloombergLP; -using bsl::cout; -using bsl::cerr; -using bsl::flush; -using bsl::endl; -using bsl::hex; -using bsl::atoi; +using namespace BloombergLP::bdldfp; +using namespace bsl; // ============================================================================ // TEST PLAN @@ -33,80 +36,69 @@ using bsl::atoi; // -------- // TBD: // ---------------------------------------------------------------------------- -// CREATORS -// -// MANIPULATORS -// -// ACCESSORS -// -// FREE OPERATORS -// -// TRAITS +// CLASS METHODS +// [ 3] Decimal64 decimal64FromMultiWidthEncoding(*buffer, size); +// [ 3] Decimal64 decimal64FromMultiWidthEncodingRaw(*buffer, size); +// [ 2] size_type decimal64ToMultiWidthEncoding(*buffer, decimal); +// [ 2] size_type decimal64ToMultiWidthEncodingRaw(*buffer, decimal); +// [ 4] unsigned char *decimal64FromVariableWidthEncoding(*decimal, *buffer); +// [ 4] unsigned char *decimal64ToVariableWidthEncoding(*buffer, value); // ---------------------------------------------------------------------------- // [ 1] BREATHING TEST -// [ 2] USAGE EXAMPLE +// [ 3] USAGE EXAMPLE // ---------------------------------------------------------------------------- -// ============================================================================ -// STANDARD BDE ASSERT TEST MACROS -// ---------------------------------------------------------------------------- +//============================================================================= +// STANDARD BDE ASSERT TEST MACRO +//----------------------------------------------------------------------------- + +namespace { -static int testStatus = 0; +int testStatus = 0; -static void aSsErT(int c, const char *s, int i) +void aSsErT(bool b, const char *s, int i) { - if (c) { + if (b) { cout << "Error " << __FILE__ << "(" << i << "): " << s << " (failed)" << endl; - if (testStatus >= 0 && testStatus <= 100) ++testStatus; + if (0 <= testStatus && testStatus <= 100) ++testStatus; } } -#define ASSERT(X) { aSsErT(!(X), #X, __LINE__); } -// ============================================================================ -// STANDARD BDE LOOP-ASSERT TEST MACROS -// ---------------------------------------------------------------------------- - -#define LOOP_ASSERT(I,X) { \ - if (!(X)) { cout << #I << ": " << I << "\n"; aSsErT(1, #X, __LINE__); }} - -#define LOOP2_ASSERT(I,J,X) { \ - if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " \ - << J << "\n"; aSsErT(1, #X, __LINE__); } } +} // close unnamed namespace -#define LOOP3_ASSERT(I,J,K,X) { \ - if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " << J << "\t" \ - << #K << ": " << K << "\n"; aSsErT(1, #X, __LINE__); } } - -#define LOOP4_ASSERT(I,J,K,L,X) { \ - if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " << J << "\t" << \ - #K << ": " << K << "\t" << #L << ": " << L << "\n"; \ - aSsErT(1, #X, __LINE__); } } - -#define LOOP5_ASSERT(I,J,K,L,M,X) { \ - if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " << J << "\t" << \ - #K << ": " << K << "\t" << #L << ": " << L << "\t" << \ - #M << ": " << M << "\n"; \ - aSsErT(1, #X, __LINE__); } } +//============================================================================= +// STANDARD BDE TEST DRIVER MACROS +//----------------------------------------------------------------------------- -#define LOOP6_ASSERT(I,J,K,L,M,N,X) { \ - if (!(X)) { cout << #I << ": " << I << "\t" << #J << ": " << J << "\t" << \ - #K << ": " << K << "\t" << #L << ": " << L << "\t" << \ - #M << ": " << M << "\t" << #N << ": " << N << "\n"; \ - aSsErT(1, #X, __LINE__); } } +#define ASSERT BDLS_TESTUTIL_ASSERT +#define LOOP_ASSERT BDLS_TESTUTIL_LOOP_ASSERT +#define LOOP0_ASSERT BDLS_TESTUTIL_LOOP0_ASSERT +#define LOOP1_ASSERT BDLS_TESTUTIL_LOOP1_ASSERT +#define LOOP2_ASSERT BDLS_TESTUTIL_LOOP2_ASSERT +#define LOOP3_ASSERT BDLS_TESTUTIL_LOOP3_ASSERT +#define LOOP4_ASSERT BDLS_TESTUTIL_LOOP4_ASSERT +#define LOOP5_ASSERT BDLS_TESTUTIL_LOOP5_ASSERT +#define LOOP6_ASSERT BDLS_TESTUTIL_LOOP6_ASSERT +#define ASSERTV BDLS_TESTUTIL_ASSERTV + +#define Q BDLS_TESTUTIL_Q // Quote identifier literally. +#define P BDLS_TESTUTIL_P // Print identifier and value. +#define P_ BDLS_TESTUTIL_P_ // P(X) without '\n'. +#define T_ BDLS_TESTUTIL_T_ // Print a tab (w/o newline). +#define L_ BDLS_TESTUTIL_L_ // current Line number // ============================================================================ -// SEMI-STANDARD TEST OUTPUT MACROS +// NEGATIVE-TEST MACRO ABBREVIATIONS // ---------------------------------------------------------------------------- -#define P(X) cout << #X " = " << (X) << endl; // Print identifier and value. -#define Q(X) cout << "<| " #X " |>" << endl; // Quote identifier literally. -#define P_(X) cout << #X " = " << (X) << ", " << flush; // 'P(X)' without '\n' -#define T_ cout << "\t" << flush; // Print tab w/o newline. -#define L_ __LINE__ // current Line number - -#define PX(X) cout << #X " = " << hex << (X) << endl; // Print id and hex value +#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR) +#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR) +#define ASSERT_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_PASS(EXPR) +#define ASSERT_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_FAIL(EXPR) +#define ASSERT_OPT_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_OPT_PASS(EXPR) +#define ASSERT_OPT_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_OPT_FAIL(EXPR) // ============================================================================ // GLOBAL TYPEDEFS/CONSTANTS FOR TESTING @@ -114,6 +106,8 @@ static void aSsErT(int c, const char *s, int i) namespace BDEC = BloombergLP::bdldfp; +typedef bdldfp::DecimalConvertUtil Util; + static bslma::Allocator *ia = bslma::Default::globalAllocator(); #define PARSEDECIMAL(p, nn) \ @@ -411,6 +405,35 @@ bool strictEqual(DECIMAL_TYPE lhs, DECIMAL_TYPE rhs) return memcmp(blhs, brhs, sizeof(DECIMAL_TYPE)) == 0; } +void bufferToStream(bsl::ostream &out, + unsigned char *buffer, + bsls::Types::size_type size) +{ + out << hex; + for (bsls::Types::size_type b = 0; b < size; ++b) { + out << setfill('0') << setw(2) + << static_cast(buffer[b]); + if (b != size - 1) { + out<< " "; + } + } + out << dec; +} + +unsigned char * decimal64ToBinaryIntegralNetwork(unsigned char *buffer, + Decimal64 decimal) +{ + bsls::Types::Uint64 encoded; + Util::decimal64ToBinaryIntegral( + reinterpret_cast(&encoded), + decimal); + + encoded = BSLS_BYTEORDER_HTONLL(encoded); + + bsl::memcpy(buffer, reinterpret_cast(&encoded), 8); + return buffer + 8; +} + //============================================================================= // MAIN PROGRAM //----------------------------------------------------------------------------- @@ -434,7 +457,7 @@ int main(int argc, char* argv[]) cout.precision(35); switch (test) { case 0: - case 2: { + case 5: { // -------------------------------------------------------------------- // USAGE EXAMPLE // Extracted from component header file. @@ -453,11 +476,11 @@ int main(int argc, char* argv[]) // -------------------------------------------------------------------- if (verbose) cout << endl - << "USAGE EXAMPLE" << endl - << "=============" << endl; + << "USAGE EXAMPLE" << endl + << "=============" << endl; if (veryVerbose) bsl::cout << "\nSending decimals as octets " - "using network format" << bsl::endl; + "using network format" << bsl::endl; // 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, @@ -471,7 +494,7 @@ int main(int argc, char* argv[]) unsigned char msgbuffer[256]; BDEC::Decimal64 number(BDLDFP_DECIMAL_DD(1.234567890123456e-42)); unsigned char expected[] = { - 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 }; + 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 }; unsigned char *next = msgbuffer; next = bdldfp::DecimalConvertUtil::decimalToNetwork(next, number); @@ -484,7 +507,7 @@ int main(int argc, char* argv[]) //.. { // "client" unsigned char msgbuffer[] ={ - 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 }; + 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 }; BDEC::Decimal64 number; BDEC::Decimal64 expected(BDLDFP_DECIMAL_DD(1.234567890123456e-42)); @@ -497,7 +520,7 @@ int main(int argc, char* argv[]) //.. if (veryVerbose) bsl::cout << "\nStoring/sending decimals in binary" - " floating-point" << bsl::endl; + " floating-point" << bsl::endl; // 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 @@ -508,7 +531,7 @@ int main(int argc, char* argv[]) //.. { const BDEC::Decimal64 number( - BDLDFP_DECIMAL_DD(1.23456789012345e-42)); + BDLDFP_DECIMAL_DD(1.23456789012345e-42)); double dbl = Util::decimalToDouble(number); @@ -524,9 +547,697 @@ int main(int argc, char* argv[]) ASSERT(number == restored); } //.. - } break; + } break; + case 4: { + // -------------------------------------------------------------------- + // VARIABLE-WIDTH ENCODE AND DECODE + // + // Concerns: + //: 1 'decimal64ToVariableWidthEncoding' correctly encodes values in + //: the supported formats. + //: + //: 2 Values are always encoded in the smallest supported + //: format. E.g. a values that fits in both 2 byte and 3 byte + //: encodings will be encoded using the 2 byte encoding. + //: + //: 3 'decimal64ToVariableWidthEncoding' does not overwrite any memory + //: outside of the range that it is supposed to. + //: + //: 4 'decimal64FromMultiWidthEncoding' can decode any value encoded + //: using 'decimal64ToVariableWidthEncoding'. + // + // Plan: + //: 1 Using the table-driven technique, specify a set of decimal + //: values, and their expected encoded values when using the + //: variable-width encoding format. Ensure that the set of values + //: include bondary values in all supported widths of the + //: encoder. Use 'decimal64ToVariableWidthEncoding' to encode each + //: decimal value in the set. Verify that the encoded values matches + //: the expected values. Additional, verify the encoded values can + //: be decoded back to the original decimal values using + //: 'decimal64FromVaribleWidthEncoding'. (C-1..3) + // + // Testing: + // unsigned char *decimal64FromVariableWidthEncoding(*decimal, *buffer); + // unsigned char *decimal64ToVariableWidthEncoding(*buffer, value); + // -------------------------------------------------------------------- + + if (verbose) cout << endl + << "VARIABLE-WIDTH ENCODE AND DECODE" << endl + << "================================" << endl; + + Decimal64 (*MDF)(long long, int) = &DecimalUtil::makeDecimal64; + + static const struct { + int d_line; + Decimal64 d_decodedValue; + const char d_encodedValue[128]; + } DATA[] = { + { L_, MDF( 0, 0 ), "40 00" }, + { L_, MDF( 1, -2 ), "00 01" }, + { L_, MDF( 1, -1 ), "20 01" }, + { L_, MDF( 1, 0 ), "40 01" }, + { L_, MDF( 1, 1 ), "60 01" }, + { L_, MDF( (1 << 13) - 1, 1 ), "7f ff" }, + + { L_, MDF( 0, 2 ), "b0 00 00" }, + { L_, MDF( 0, -3 ), "88 00 00" }, + { L_, MDF( -1, 3 ), "f3 00 00 01" }, + { L_, MDF( (1 << 13), 3 ), "b8 20 00" }, + + { L_, MDF( (1 << 13), 0 ), "a0 20 00" }, + { L_, MDF( (1 << 13), -4 ), "80 20 00" }, + { L_, MDF( (1 << 13) + 1, 3 ), "b8 20 01" }, + { L_, MDF( (1 << 19) - 1, 3 ), "bf ff ff" }, + + { L_, MDF( (1 << 13), 4 ), "d4 00 20 00" }, + { L_, MDF( (1 << 13), -5 ), "cb 00 20 00" }, + { L_, MDF( (1 << 19), 3 ), "d3 08 00 00" }, + { L_, MDF( -(1 << 19), 3 ), "f3 08 00 00" }, + { L_, MDF( (1 << 24) - 1, 15 ), "df ff ff ff" }, + { L_, MDF( (1 << 24) - 1, -16 ), "c0 ff ff ff" }, + { L_, MDF( -((1 << 24) - 1), 14 ), "fe ff ff ff" }, + { L_, MDF( -((1 << 24) - 1), -16 ), "e0 ff ff ff" }, + + // Encoded value == "" indicates that the full 9-bytes encoding + // format should be used. + + { L_, MDF( -((1 << 24) - 1), 15 ), "" }, + { L_, MDF( (1 << 24) - 1, 16 ), "" }, + { L_, MDF( 1 << 24, 0 ), "" }, + { L_, MDF( -(1 << 24), 0 ), "" }, + + { L_, bsl::numeric_limits::min(), "" }, + { L_, bsl::numeric_limits::max(), "" }, + { L_, bsl::numeric_limits::infinity(), "" }, + { L_, bsl::numeric_limits::quiet_NaN(), "" }, + }; + const int NUM_DATA = sizeof DATA / sizeof *DATA; + + for (int i = 0; i != NUM_DATA; ++i) { + const int LINE = DATA[i].d_line; + const Decimal64 DECODED_VALUE = DATA[i].d_decodedValue; + const char *ENCODED_VALUE = DATA[i].d_encodedValue; + + unsigned char encodedBuffer[12]; + + bsls::Types::size_type encodedSize = 0; + + if (ENCODED_VALUE[0]) { + istringstream encodedBufferString(ENCODED_VALUE); + int temp; + while (encodedBufferString >> hex >> temp) { + encodedBuffer[encodedSize] = + static_cast(temp); + ++encodedSize; + } + } + else { + encodedBuffer[0] = 0xFF; + unsigned char *nextAdr = decimal64ToBinaryIntegralNetwork( + encodedBuffer + 1, DECODED_VALUE); + encodedSize = nextAdr - encodedBuffer; + } + + if (veryVerbose) { + P_(LINE) P_(DECODED_VALUE) P_(encodedSize); + cout << "ENCODED_VALUE: "; + bufferToStream(cout, encodedBuffer, encodedSize); + cout << endl; + } + - case 1: { + unsigned char actualEncodedBufferOrig[16] = { + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF }; + unsigned char actualEncodedBuffer[16] = { + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF }; + const bsls::Types::size_type actualEncodedBufferOffset = 4; + bsls::Types::size_type actualEncodedSize; + + actualEncodedSize = Util::decimal64ToVariableWidthEncoding( + actualEncodedBuffer + actualEncodedBufferOffset, + DECODED_VALUE) + - (actualEncodedBuffer + actualEncodedBufferOffset); + + if (veryVerbose) { + P_(actualEncodedSize); + cout << "actualEncodeValue: "; + bufferToStream(cout, + actualEncodedBuffer + actualEncodedBufferOffset, + actualEncodedSize); + cout << endl; + } + + ASSERTV(LINE, encodedSize, actualEncodedSize, + encodedSize == actualEncodedSize); + ASSERTV(LINE, 0 == memcmp( + encodedBuffer, + actualEncodedBuffer + actualEncodedBufferOffset, + encodedSize)); + ASSERTV(LINE, 0 == memcmp(actualEncodedBuffer, + actualEncodedBufferOrig, + actualEncodedBufferOffset)); + ASSERTV(LINE, 0 == memcmp( + actualEncodedBuffer + actualEncodedBufferOffset + encodedSize, + actualEncodedBufferOrig + actualEncodedBufferOffset + encodedSize, + sizeof(actualEncodedBuffer) - encodedSize + - actualEncodedBufferOffset)); + + Decimal64 actualDecodedValue = MDF(123,123); // initialize to + // unused value + + unsigned char *actualRet = + Util::decimal64FromVariableWidthEncoding(&actualDecodedValue, + encodedBuffer); + + bsls::Types::size_type actualSize = actualRet - encodedBuffer; + + if (veryVerbose) { + P_(actualDecodedValue); P(actualSize); + } + + if (DecimalUtil::isNan(DECODED_VALUE)) { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DecimalUtil::isNan(actualDecodedValue)); + } + else { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DECODED_VALUE == actualDecodedValue); + } + } + } break; + case 3: { + // -------------------------------------------------------------------- + // MULTI-WIDTH DECODE + // + // Concerns: + //: 1 'decimal64FromMultiWidthEncoding' and + //: 'decimal64FromMultiWidthEncodingRaw' correctly decode values in + //: the supported formats. + //: + //: 2 QoI: Asserted precondition violations are detected when enabled. + // + // Plan: + //: 1 Using the table-driven technique, specify a set of decimal + //: values, and their encoded values. Ensure that the set contains + //: boundary values in all supported widths of the decoder. Use + //: 'decimal64FromMultiWidthEncoding' and + //: 'decimal64FromMultiWidthEncodingRaw' to decode the encoded + //: values. Verify that the decoded decimal values matches the + //: original values. (C-1) + //: + //: 2 Verify that, in appropriate build modes, defensive checks are + //: triggered for invalid attribute values, but not triggered for + //: adjacent valid ones (using the 'BSLS_ASSERTTEST_*' macros). + //: (C-2) + // + // Testing: + // Decimal64 decimal64FromMultiWidthEncoding(*buffer, size); + // Decimal64 decimal64FromMultiWidthEncodingRaw(*buffer, size); + // -------------------------------------------------------------------- + + if (verbose) cout << endl + << "MULTI-WIDTH DECODE" << endl + << "==================" << endl; + + Decimal64 (*MDF)(long long, int) = &DecimalUtil::makeDecimal64; + + static const struct { + int d_line; + Decimal64 d_decodedValue; + const char d_encodedValue[128]; + } DATA[] = { + { L_, MDF( 0, -2 ), "00" }, + { L_, MDF( 0, -1 ), "80" }, + { L_, MDF( 50, -2 ), "32" }, + { L_, MDF( 50, -1 ), "b2" }, + { L_, MDF( (1 << 7) - 1, -2 ), "7f" }, + { L_, MDF( (1 << 7) - 1, -1 ), "ff" }, + + { L_, MDF( 0, -1 ), "80 00" }, + { L_, MDF( 1, -3 ), "00 01" }, + { L_, MDF( 1, -2 ), "40 01" }, + { L_, MDF( 1, -1 ), "80 01" }, + { L_, MDF( 1, 0 ), "c0 01" }, + { L_, MDF( (1 << 14) - 1, 0 ), "ff ff" }, + + { L_, MDF( 0, 1 ), "e0 00 00" }, + { L_, MDF( 0, -4 ), "40 00 00" }, + { L_, MDF( -1, 1 ), "c4 00 00 01" }, + { L_, MDF( (1 << 14), 1 ), "e0 40 00" }, + + { L_, MDF( (1 << 14), -2 ), "80 40 00" }, + { L_, MDF( (1 << 14), -6 ), "00 40 00" }, + { L_, MDF( (1 << 14), 1 ), "e0 40 00" }, + { L_, MDF( (1 << 21) - 1, 1 ), "ff ff ff" }, + + { L_, MDF( (1 << 14), 2 ), "48 00 40 00" }, + { L_, MDF( (1 << 14), -7 ), "24 00 40 00" }, + { L_, MDF( (1 << 21), 2 ), "48 20 00 00" }, + + { L_, MDF( (1 << 21), 0 ), "40 20 00 00" }, + { L_, MDF( (1 << 21), -16 ), "00 20 00 00" }, + { L_, MDF( (1 << 21), 15 ), "7c 20 00 00" }, + { L_, MDF( -(1 << 21), 0 ), "c0 20 00 00" }, + { L_, MDF( -(1 << 21), -16 ), "80 20 00 00" }, + { L_, MDF( -(1 << 21), 15 ), "fc 20 00 00" }, + { L_, MDF( ((1ll << 26) - 1), 15 ), "7f ff ff ff" }, + { L_, MDF( -((1ll << 26) - 1), 15 ), "ff ff ff ff" }, + + { L_, MDF( (1ll << 26), 0 ), "40 04 00 00 00" }, + { L_, MDF( (1ll << 26), -16 ), "00 04 00 00 00" }, + { L_, MDF( (1ll << 26), 15 ), "7c 04 00 00 00" }, + { L_, MDF( -(1ll << 26), 0 ), "c0 04 00 00 00" }, + { L_, MDF( -(1ll << 26), -16 ), "80 04 00 00 00" }, + { L_, MDF( -(1ll << 26), 15 ), "fc 04 00 00 00" }, + { L_, MDF( ((1ll << 34) - 1), 15 ), "7f ff ff ff ff" }, + { L_, MDF( -((1ll << 34) - 1), 15 ), "ff ff ff ff ff" }, + + // Encoded value == "" indicates that the full 8-bytes DPD encoding + // format should be used. + + { L_, MDF( (1ll << 34), 15 ), "" }, + { L_, MDF( -(1ll << 34), 15 ), "" }, + { L_, MDF( 1, 16 ), "" }, + { L_, MDF( 1, -17 ), "" }, + { L_, MDF( 1, -398 ), "" }, + + { L_, bsl::numeric_limits::min(), "" }, + { L_, bsl::numeric_limits::max(), "" }, + { L_, bsl::numeric_limits::infinity(), "" }, + { L_, bsl::numeric_limits::quiet_NaN(), "" }, + + }; + const int NUM_DATA = sizeof DATA / sizeof *DATA; + + for (int i = 0; i != NUM_DATA; ++i) { + const int LINE = DATA[i].d_line; + const Decimal64 DECODED_VALUE = DATA[i].d_decodedValue; + const char *ENCODED_VALUE = DATA[i].d_encodedValue; + + unsigned char encodedBuffer[12]; + bsls::Types::size_type encodedSize = 0; + + const bool useFullEncodingFlag = !(ENCODED_VALUE[0]); + if (!useFullEncodingFlag) { + istringstream encodedBufferString(ENCODED_VALUE); + int temp; + while (encodedBufferString >> hex >> temp) { + encodedBuffer[encodedSize] = + static_cast(temp); + ++encodedSize; + } + } + else { + unsigned char *nextAdr = decimal64ToBinaryIntegralNetwork( + encodedBuffer, DECODED_VALUE); + encodedSize = nextAdr - encodedBuffer; + } + + if (veryVerbose) { + P_(LINE) P_(DECODED_VALUE) + cout << "ENCODED_VALUE: "; + bufferToStream(cout, encodedBuffer, encodedSize); + cout << endl; + } + + // Test 'decimal64FromMultiWidthEncoding'. + { + Decimal64 actualDecodedValue = + Util::decimal64FromMultiWidthEncoding(encodedBuffer, + encodedSize); + if (veryVerbose) { + P(actualDecodedValue); + } + + if (DecimalUtil::isNan(DECODED_VALUE)) { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DecimalUtil::isNan(actualDecodedValue)); + } + else { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DECODED_VALUE == actualDecodedValue); + } + } + + // Test 'decimal64FromMultiWidthEncodingRaw'. + if (!useFullEncodingFlag) { + Decimal64 actualDecodedValue = + Util::decimal64FromMultiWidthEncoding(encodedBuffer, + encodedSize); + if (veryVerbose) { + P(actualDecodedValue); + } + + if (DecimalUtil::isNan(DECODED_VALUE)) { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DecimalUtil::isNan(actualDecodedValue)); + } + else { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DECODED_VALUE == actualDecodedValue); + } + } + } + + // Negative Testing + { + bsls::AssertFailureHandlerGuard hG( + bsls::AssertTest::failTestDriver); + + unsigned char encodedBuffer[9] = { 0x77, 0xfc, 0xff, 0x3f, + 0xcf, 0xf3, 0xfc, 0xff, + 0xff }; + + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 0)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 1)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 2)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 3)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 4)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 5)); + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 6)); + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 7)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 8)); + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncoding(encodedBuffer, 9)); + + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 0)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 1)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 2)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 3)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 4)); + ASSERT_SAFE_PASS( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 5)); + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 6)); + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 7)); + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 8)); + ASSERT_SAFE_FAIL( + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, 9)); + } + } break; + case 2: { + // -------------------------------------------------------------------- + // MULTI-WIDTH ENCODE + // + // Concerns: + //: 1 'decimal64ToMultiWidthEncoding' and + //: 'decimal64ToMultiWidthEncodingRaw' correctly encode values in the + //: supported formats. + //: + //: 2 Values are always encoded in the smallest supported + //: format. E.g. a values that fits in both 2 byte and 3 byte + //: encodings will be encoded using the 2 byte encoding. + //: + //: 3 'decimal64ToMultiWidthEncoding' and + //: 'decimal64ToMultiWidthEncodingRaw' do not overwrite any memory + //: outside of the range that it is supposed to. + //: + //: 4 Any value encoded using 'decimal64ToMultiWidthEncoding' can be + //: decoded using the function 'decimal64FromMultiWidthEncoding'. + //: + //: 5 Any value encoded using 'decimal64ToMultiWidthEncodingRaw' can be + //: decoded using the function 'decimal64FromMultiWidthEncodingRaw'. + //: + //: 6 'decimal64ToMultiWidthEncodingRaw' returns 0 if the value to + //: encode requires the full IEEE format. + // + // Plan: + //: 1 Using the table-driven technique, specify a set of decimal + //: values, and their expected encoded values when using the + //: multi-width encoding format. Ensure that the set of values + //: include bondary values in all supported widths of the + //: encoder. Use 'decimal64ToMultiWidthEncoding' and + //: 'decimal64ToMultiWidthEncodingRaw' to encode each decimal value + //: in the set. Verify that the encoded values matches the expected + //: values. Additional, verify the encoded values can be decoded + //: back to the original decimal values using + //: 'decimal64FromMultiWidthEncoding' and + //: 'decimal64FromMultiWidthEncodingRaw'. (C-1..6) + // + // Testing: + // size_type decimal64ToMultiWidthEncoding(*buffer, decimal); + // size_type decimal64ToMultiWidthEncodingRaw(*buffer, decimal); + // -------------------------------------------------------------------- + + if (verbose) cout << endl + << "MULTI-WIDTH ENCODE" << endl + << "==================" << endl; + + Decimal64 (*MDF)(long long, int) = &DecimalUtil::makeDecimal64; + + static const struct { + int d_line; + Decimal64 d_decodedValue; + const char d_encodedValue[128]; + } DATA[] = { + { L_, MDF( 0, -1 ), "80 00" }, + { L_, MDF( 1, -3 ), "00 01" }, + { L_, MDF( 1, -2 ), "40 01" }, + { L_, MDF( 1, -1 ), "80 01" }, + { L_, MDF( 1, 0 ), "c0 01" }, + { L_, MDF( (1 << 14) - 1, 0 ), "ff ff" }, + + { L_, MDF( 0, 1 ), "e0 00 00" }, + { L_, MDF( 0, -4 ), "40 00 00" }, + { L_, MDF( -1, 1 ), "c4 00 00 01" }, + { L_, MDF( (1 << 14), 1 ), "e0 40 00" }, + + { L_, MDF( (1 << 14), -2 ), "80 40 00" }, + { L_, MDF( (1 << 14), -6 ), "00 40 00" }, + { L_, MDF( (1 << 14), 1 ), "e0 40 00" }, + { L_, MDF( (1 << 21) - 1, 1 ), "ff ff ff" }, + + { L_, MDF( (1 << 14), 2 ), "48 00 40 00" }, + { L_, MDF( (1 << 14), -7 ), "24 00 40 00" }, + { L_, MDF( (1 << 21), 2 ), "48 20 00 00" }, + + { L_, MDF( (1 << 21), 0 ), "40 20 00 00" }, + { L_, MDF( (1 << 21), -16 ), "00 20 00 00" }, + { L_, MDF( (1 << 21), 15 ), "7c 20 00 00" }, + { L_, MDF( -(1 << 21), 0 ), "c0 20 00 00" }, + { L_, MDF( -(1 << 21), -16 ), "80 20 00 00" }, + { L_, MDF( -(1 << 21), 15 ), "fc 20 00 00" }, + { L_, MDF( ((1ll << 26) - 1), 15 ), "7f ff ff ff" }, + { L_, MDF( -((1ll << 26) - 1), 15 ), "ff ff ff ff" }, + + { L_, MDF( (1ll << 26), 0 ), "40 04 00 00 00" }, + { L_, MDF( (1ll << 26), -16 ), "00 04 00 00 00" }, + { L_, MDF( (1ll << 26), 15 ), "7c 04 00 00 00" }, + { L_, MDF( -(1ll << 26), 0 ), "c0 04 00 00 00" }, + { L_, MDF( -(1ll << 26), -16 ), "80 04 00 00 00" }, + { L_, MDF( -(1ll << 26), 15 ), "fc 04 00 00 00" }, + { L_, MDF( ((1ll << 34) - 1), 15 ), "7f ff ff ff ff" }, + { L_, MDF( -((1ll << 34) - 1), 15 ), "ff ff ff ff ff" }, + + // Encoded value == "" indicates that the full 8-bytes DPD encoding + // format should be used. + + { L_, MDF( (1ll << 34), 15 ), "" }, + { L_, MDF( -(1ll << 34), 15 ), "" }, + { L_, MDF( 1, 16 ), "" }, + { L_, MDF( 1, -17 ), "" }, + { L_, MDF( 1, -398 ), "" }, + + { L_, bsl::numeric_limits::min(), "" }, + { L_, bsl::numeric_limits::max(), "" }, + { L_, bsl::numeric_limits::infinity(), "" }, + { L_, bsl::numeric_limits::quiet_NaN(), "" }, + + }; + const int NUM_DATA = sizeof DATA / sizeof *DATA; + + for (int i = 0; i != NUM_DATA; ++i) { + const int LINE = DATA[i].d_line; + const Decimal64 DECODED_VALUE = DATA[i].d_decodedValue; + const char *ENCODED_VALUE = DATA[i].d_encodedValue; + + unsigned char encodedBuffer[12]; + bsls::Types::size_type encodedSize = 0; + + const bool useFullEncodingFlag = !(ENCODED_VALUE[0]); + + if (!useFullEncodingFlag) { + istringstream encodedBufferString(ENCODED_VALUE); + int temp; + while (encodedBufferString >> hex >> temp) { + encodedBuffer[encodedSize] = + static_cast(temp); + ++encodedSize; + } + } + else { + unsigned char *nextAdr = decimal64ToBinaryIntegralNetwork( + encodedBuffer, DECODED_VALUE); + encodedSize = nextAdr - encodedBuffer; + } + + if (veryVerbose) { + P_(LINE) P_(DECODED_VALUE) + cout << "ENCODED_VALUE: "; + bufferToStream(cout, encodedBuffer, encodedSize); + cout << endl; + } + + // Test 'decimal64ToMultiWidthEncoding'. + + { + unsigned char actualEncodedBufferOrig[16] = { + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF }; + unsigned char actualEncodedBuffer[16] = { + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF }; + const bsls::Types::size_type actualEncodedBufferOffset = 4; + bsls::Types::size_type actualEncodedSize; + + actualEncodedSize = Util::decimal64ToMultiWidthEncoding( + actualEncodedBuffer + actualEncodedBufferOffset, + DECODED_VALUE); + + if (veryVerbose) { + P_(actualEncodedSize); + cout << "actualEncodeValue: "; + bufferToStream( + cout, + actualEncodedBuffer + actualEncodedBufferOffset, + actualEncodedSize); + cout << endl; + } + + ASSERTV(LINE, encodedSize, actualEncodedSize, + encodedSize == actualEncodedSize); + ASSERTV(LINE, 0 == memcmp( + encodedBuffer, + actualEncodedBuffer + actualEncodedBufferOffset, + encodedSize)); + ASSERTV(LINE, 0 == memcmp(actualEncodedBuffer, + actualEncodedBufferOrig, + actualEncodedBufferOffset)); + ASSERTV(LINE, 0 == memcmp( + actualEncodedBuffer + + actualEncodedBufferOffset + encodedSize, + actualEncodedBufferOrig + + actualEncodedBufferOffset + encodedSize, + sizeof(actualEncodedBuffer) - encodedSize + - actualEncodedBufferOffset)); + + Decimal64 actualDecodedValue = + Util::decimal64FromMultiWidthEncoding(encodedBuffer, + encodedSize); + if (veryVerbose) { + P(actualDecodedValue); + } + + if (DecimalUtil::isNan(DECODED_VALUE)) { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DecimalUtil::isNan(actualDecodedValue)); + } + else { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DECODED_VALUE == actualDecodedValue); + } + } + + // Test 'decimal64ToMultiWidthEncodingRaw'. + + if (useFullEncodingFlag) { + unsigned char buffer[16]; + bsls::Types::size_type ret = + Util::decimal64ToMultiWidthEncodingRaw(buffer, + DECODED_VALUE); + ASSERTV(LINE, ret, ret == 0); + } + else { + unsigned char actualEncodedBufferOrig[16] = { + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF }; + unsigned char actualEncodedBuffer[16] = { + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF, + 0xDE, 0xAD, 0xBE, 0xEF }; + const bsls::Types::size_type actualEncodedBufferOffset = 4; + bsls::Types::size_type actualEncodedSize; + + actualEncodedSize = Util::decimal64ToMultiWidthEncodingRaw( + actualEncodedBuffer + actualEncodedBufferOffset, + DECODED_VALUE); + + if (veryVerbose) { + P_(actualEncodedSize); + cout << "actualEncodeValue: "; + bufferToStream( + cout, + actualEncodedBuffer + actualEncodedBufferOffset, + actualEncodedSize); + cout << endl; + } + + ASSERTV(LINE, encodedSize, actualEncodedSize, + encodedSize == actualEncodedSize); + ASSERTV(LINE, 0 == memcmp( + encodedBuffer, + actualEncodedBuffer + actualEncodedBufferOffset, + encodedSize)); + ASSERTV(LINE, 0 == memcmp(actualEncodedBuffer, + actualEncodedBufferOrig, + actualEncodedBufferOffset)); + ASSERTV(LINE, 0 == memcmp( + actualEncodedBuffer + + actualEncodedBufferOffset + encodedSize, + actualEncodedBufferOrig + + actualEncodedBufferOffset + encodedSize, + sizeof(actualEncodedBuffer) - encodedSize + - actualEncodedBufferOffset)); + + Decimal64 actualDecodedValue = + Util::decimal64FromMultiWidthEncodingRaw(encodedBuffer, + encodedSize); + if (veryVerbose) { + P(actualDecodedValue); + } + + if (DecimalUtil::isNan(DECODED_VALUE)) { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DecimalUtil::isNan(actualDecodedValue)); + } + else { + ASSERTV(LINE, DECODED_VALUE, actualDecodedValue, + DECODED_VALUE == actualDecodedValue); + } + } + } + } break; + case 1: { // -------------------------------------------------------------------- // BREATHING TEST // @@ -1214,11 +1925,8 @@ int main(int argc, char* argv[]) else { if (veryVerbose) bsl::cout << "Skipped, no binary FP" << bsl::endl; } - - } break; - - - default: { + } break; + default: { cerr << "WARNING: CASE '" << test << "' NOT FOUND." << endl; testStatus = -1; } diff --git a/groups/bdl/bdldfp/bdldfp_decimalimputil.h b/groups/bdl/bdldfp/bdldfp_decimalimputil.h index b3998bb090..0dda7e3374 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalimputil.h +++ b/groups/bdl/bdldfp/bdldfp_decimalimputil.h @@ -890,6 +890,31 @@ class DecimalImpUtil { // the specified 'value' in Densely Packed Decimal (DPD) format. This // format is compatible with the IBM compiler's native type, and the // decNumber library. + + // Binary Integral Conversion Functions + + static ValueType32 convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType32 bid); + static ValueType64 convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType64 bid); + static ValueType128 convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType128 bid); + // Return a 'ValueTypeXX' representing the specified 'bid', which is + // currently in Binary Integral Decimal (BID) format. This format is + // compatible with the Intel DFP implementation type. + + static + BinaryIntegralDecimalImpUtil::StorageType32 convertToBinaryIntegral( + ValueType32 value); + static + BinaryIntegralDecimalImpUtil::StorageType64 convertToBinaryIntegral( + ValueType64 value); + static + BinaryIntegralDecimalImpUtil::StorageType128 convertToBinaryIntegral( + ValueType128 value); + // Return a 'BinaryIntegralDecimalImpUtil::StorageTypeXX' representing + // the specified 'value' in Binary Integral Decimal (BID) format. This + // format is compatible with the Intel DFP implementation type. }; // ============================================================================ @@ -1550,6 +1575,53 @@ DecimalImpUtil::convertToDenselyPacked(ValueType128 value) return Imp::convertToDenselyPacked(value); } + // Binary Integral Conversion Functions + +inline +DecimalImpUtil::ValueType32 +DecimalImpUtil::convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType32 bid) +{ + return Imp::convertFromBinaryIntegral(bid); +} + +inline +DecimalImpUtil::ValueType64 +DecimalImpUtil::convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType64 bid) +{ + return Imp::convertFromBinaryIntegral(bid); +} + +inline +DecimalImpUtil::ValueType128 +DecimalImpUtil::convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType128 bid) +{ + return Imp::convertFromBinaryIntegral(bid); +} + +inline +BinaryIntegralDecimalImpUtil::StorageType32 +DecimalImpUtil::convertToBinaryIntegral(ValueType32 value) +{ + return Imp::convertToBinaryIntegral(value); +} + +inline +BinaryIntegralDecimalImpUtil::StorageType64 +DecimalImpUtil::convertToBinaryIntegral(ValueType64 value) +{ + return Imp::convertToBinaryIntegral(value); +} + +inline +BinaryIntegralDecimalImpUtil::StorageType128 +DecimalImpUtil::convertToBinaryIntegral(ValueType128 value) +{ + return Imp::convertToBinaryIntegral(value); +} + } // close package namespace } // close enterprise namespace diff --git a/groups/bdl/bdldfp/bdldfp_decimalimputil.t.cpp b/groups/bdl/bdldfp/bdldfp_decimalimputil.t.cpp index 94fe2343f5..de9ed3e55f 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalimputil.t.cpp +++ b/groups/bdl/bdldfp/bdldfp_decimalimputil.t.cpp @@ -1,6 +1,9 @@ // bdldfp_decimalimputil.t.cpp -*-C++-*- #include +#include +BSLS_IDENT("$Id$") + #include #include diff --git a/groups/bdl/bdldfp/bdldfp_decimalimputil_decnumber.h b/groups/bdl/bdldfp/bdldfp_decimalimputil_decnumber.h index f07518b3f8..2956924e5a 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalimputil_decnumber.h +++ b/groups/bdl/bdldfp/bdldfp_decimalimputil_decnumber.h @@ -706,10 +706,40 @@ struct DecimalImpUtil_DecNumber { ValueType64 value); static DenselyPackedDecimalImpUtil::StorageType128 convertToDenselyPacked( ValueType128 value); - // Return a 'DenselyPackeDecimalImpUtil::StorageTypeXX' representing + // Return a 'DenselyPackedDecimalImpUtil::StorageTypeXX' representing // the specified 'value' in Densely Packed Decimal (DPD) format. This // format is compatible with the IBM compiler's native type, and the // decNumber library. + + // Binary Integral Conversion Functions + + // The 'decNumber' library does not currently support conversion to or from + // 'BID', so these functions are not provided. This will cause a + // compile-time failure for this implementation. A portable implementation + // of this algorithm is forthcoming. + + //static ValueType32 convertFromBinaryIntegral( + // BinaryIntegralDecimalImpUtil::StorageType32 bid); + //static ValueType64 convertFromBinaryIntegral( + // BinaryIntegralDecimalImpUtil::StorageType64 bid); + //static ValueType128 convertFromBinaryIntegral( + // BinaryIntegralDecimalImpUtil::StorageType128 bid); + // Return a 'ValueTypeXX' representing the specified 'bid', which is + // currently in Binary Integral Decimal (BID) format. This format is + // compatible with the Intel DFP implementation type. + + //static + //BinaryIntegralDecimalImpUtil::StorageType32 convertToBinaryIntegral( + // ValueType32 value); + //static + //BinaryIntegralDecimalImpUtil::StorageType64 convertToBinaryIntegral( + // ValueType64 value); + //static + //BinaryIntegralDecimalImpUtil::StorageType128 convertToBinaryIntegral( + // ValueType128 value); + // Return a 'BinaryIntegralDecimalImpUtil::StorageTypeXX' representing + // the specified 'value' in Binary Integral Decimal (BID) format. This + // format is compatible with the Intel DFP implementation type. }; // ============================================================================ diff --git a/groups/bdl/bdldfp/bdldfp_decimalimputil_ibmxlc.h b/groups/bdl/bdldfp/bdldfp_decimalimputil_ibmxlc.h index 700be64c04..fbb9d66fe8 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalimputil_ibmxlc.h +++ b/groups/bdl/bdldfp/bdldfp_decimalimputil_ibmxlc.h @@ -669,10 +669,40 @@ struct DecimalImpUtil_IbmXlc { ValueType64 value); static DenselyPackedDecimalImpUtil::StorageType128 convertToDenselyPacked( ValueType128 value); - // Return a 'DenselyPackeDecimalImpUtil::StorageTypeXX' representing + // Return a 'DenselyPackedDecimalImpUtil::StorageTypeXX' representing // the specified 'value' in Densely Packed Decimal (DPD) format. This // format is compatible with the IBM compiler's native type, and the // decNumber library. + + // Binary Integral Conversion Functions + + // The IBM XLC compiler's Decimal implementation does not currently support + // conversion to or from 'BID', so these functions are not provided. This + // will cause a compile-time failure for this implementation. A portable + // implementation of this algorithm is forthcoming. + + //static ValueType32 convertFromBinaryIntegral( + // BinaryIntegralDecimalImpUtil::StorageType32 bid); + //static ValueType64 convertFromBinaryIntegral( + // BinaryIntegralDecimalImpUtil::StorageType64 bid); + //static ValueType128 convertFromBinaryIntegral( + // BinaryIntegralDecimalImpUtil::StorageType128 bid); + // Return a 'ValueTypeXX' representing the specified 'bid', which is + // currently in Binary Integral Decimal (BID) format. This format is + // compatible with the Intel DFP implementation type. + + //static + //BinaryIntegralDecimalImpUtil::StorageType32 convertToBinaryIntegral( + // ValueType32 value); + //static + //BinaryIntegralDecimalImpUtil::StorageType64 convertToBinaryIntegral( + // ValueType64 value); + //static + //BinaryIntegralDecimalImpUtil::StorageType128 convertToBinaryIntegral( + // ValueType128 value); + // Return a 'BinaryIntegralDecimalImpUtil::StorageTypeXX' representing + // the specified 'value' in Binary Integral Decimal (BID) format. This + // format is compatible with the Intel DFP implementation type. }; // ============================================================================ diff --git a/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.h b/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.h index 6da79ce6b5..f991ffd58e 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.h +++ b/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.h @@ -38,6 +38,10 @@ BSLS_IDENT("$Id$") #include #endif +#ifndef INCLUDED_BDLDFP_BINARYINTEGRALDECIMALIMPUTIL +#include +#endif + #ifdef BDLDFP_DECIMALPLATFORM_INTELDFP #ifndef INCLUDED_BDLDFP_INTELIMPWRAPPER @@ -684,10 +688,35 @@ struct DecimalImpUtil_IntelDfp { ValueType64 value); static DenselyPackedDecimalImpUtil::StorageType128 convertToDenselyPacked( ValueType128 value); - // Return a 'DenselyPackeDecimalImpUtil::StorageTypeXX' representing + // Return a 'DenselyPackedDecimalImpUtil::StorageTypeXX' representing // the specified 'value' in Densely Packed Decimal (DPD) format. This // format is compatible with the IBM compiler's native type, and the // decNumber library. + + // Binary Integral Conversion Functions + + static ValueType32 convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType32 bid); + static ValueType64 convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType64 bid); + static ValueType128 convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType128 bid); + // Return a 'ValueTypeXX' representing the specified 'bid', which is + // currently in Binary Integral Decimal (BID) format. This format is + // compatible with the Intel DFP implementation type. + + static + BinaryIntegralDecimalImpUtil::StorageType32 convertToBinaryIntegral( + ValueType32 value); + static + BinaryIntegralDecimalImpUtil::StorageType64 convertToBinaryIntegral( + ValueType64 value); + static + BinaryIntegralDecimalImpUtil::StorageType128 convertToBinaryIntegral( + ValueType128 value); + // Return a 'BinaryIntegralDecimalImpUtil::StorageTypeXX' representing + // the specified 'value' in Binary Integral Decimal (BID) format. This + // format is compatible with the Intel DFP implementation type. }; // ============================================================================ @@ -1539,6 +1568,73 @@ DecimalImpUtil_IntelDfp::convertToDenselyPacked( return dpd; } + // Binary Integral Conversion Functions + +inline +DecimalImpUtil_IntelDfp::ValueType32 +DecimalImpUtil_IntelDfp::convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType32 bid) +{ + ValueType32 result; + memcpy(&result, &bid, sizeof(result)); + + return result; +} + +inline +DecimalImpUtil_IntelDfp::ValueType64 +DecimalImpUtil_IntelDfp::convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType64 bid) +{ + ValueType64 result; + memcpy(&result, &bid, sizeof(result)); + + return result; +} + +inline +DecimalImpUtil_IntelDfp::ValueType128 +DecimalImpUtil_IntelDfp::convertFromBinaryIntegral( + BinaryIntegralDecimalImpUtil::StorageType128 bid) +{ + ValueType128 result; + memcpy(&result, &bid, sizeof(result)); + + return result; +} + +inline +BinaryIntegralDecimalImpUtil::StorageType32 +DecimalImpUtil_IntelDfp::convertToBinaryIntegral( + DecimalImpUtil_IntelDfp::ValueType32 value) +{ + BinaryIntegralDecimalImpUtil::StorageType32 bid; + bsl::memcpy(&bid, &value, sizeof(bid)); + + return bid; +} + +inline +BinaryIntegralDecimalImpUtil::StorageType64 +DecimalImpUtil_IntelDfp::convertToBinaryIntegral( + DecimalImpUtil_IntelDfp::ValueType64 value) +{ + BinaryIntegralDecimalImpUtil::StorageType64 bid; + bsl::memcpy(&bid, &value, sizeof(bid)); + + return bid; +} + +inline +BinaryIntegralDecimalImpUtil::StorageType128 +DecimalImpUtil_IntelDfp::convertToBinaryIntegral( + DecimalImpUtil_IntelDfp::ValueType128 value) +{ + BinaryIntegralDecimalImpUtil::StorageType128 bid; + bsl::memcpy(&bid, &value, sizeof(bid)); + + return bid; +} } // close package namespace } // close enterprise namespace diff --git a/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.t.cpp b/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.t.cpp index c7ce765f56..9207489418 100644 --- a/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.t.cpp +++ b/groups/bdl/bdldfp/bdldfp_decimalimputil_inteldfp.t.cpp @@ -4,8 +4,82 @@ #include BSLS_IDENT("$Id$") +#include +#include +#include + +// ============================================================================ +// TEST PLAN +// ---------------------------------------------------------------------------- +// Overview +// -------- +// The Intel DFP implementation provides a BID representation of DFP. The code +// is written in C, but due to compiler-portability concerns, we have to +// compile it with a C++ compiler. This test driver is not blank, to address +// some C/C++ compatibility concerns. +// +// Global Concerns: +// +//: 1 The IntelDFP library defines some manifest constants that might cause +//: linker failures. +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +using namespace BloombergLP; +using bsl::cout; +using bsl::cerr; +using bsl::flush; +using bsl::endl; +using bsl::atoi; + +//============================================================================= +// STANDARD BDE ASSERT TEST MACRO +//----------------------------------------------------------------------------- + +namespace { + +int testStatus = 0; + +void aSsErT(bool b, const char *s, int i) +{ + if (b) { + cout << "Error " << __FILE__ << "(" << i << "): " << s + << " (failed)" << endl; + if (0 <= testStatus && testStatus <= 100) ++testStatus; + } +} + +} // close unnamed namespace + +//============================================================================= +// STANDARD BDE TEST DRIVER MACROS +//----------------------------------------------------------------------------- + +#define ASSERT BDLS_TESTUTIL_ASSERT + +extern "C" { +extern const unsigned long long int __four_over_pi[]; +} + +#define DEFINES +#include "library_float128_dpml_four_over_pi.cpp" +typedef struct { float a, b; double c; } SQRT_COEF_STRUCT; +extern "C" const SQRT_COEF_STRUCT __dpml_bid_sqrt_t_table[]; +#undef DEFINES + int main() { + { + const SQRT_COEF_STRUCT *p = &__dpml_bid_sqrt_t_table[0]; + ASSERT(p); + } + + { + const DIGIT_TYPE *p = &FOUR_OVER_PI_TABLE_NAME[0]; + ASSERT(p); + } + return -1; } diff --git a/groups/bdl/bdldfp/bdldfp_intelimpwrapper.h b/groups/bdl/bdldfp/bdldfp_intelimpwrapper.h index 2d03f7b8d1..9522ff0e1b 100644 --- a/groups/bdl/bdldfp/bdldfp_intelimpwrapper.h +++ b/groups/bdl/bdldfp/bdldfp_intelimpwrapper.h @@ -84,6 +84,11 @@ BSLS_IDENT("$Id$") # ifndef _WCHAR_T_DEFINED # define _WCHAR_T_DEFINED +# endif + +# ifdef BSLS_PLATFORM_CMP_GNU +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wconversion" # endif extern "C" { @@ -92,6 +97,10 @@ BSLS_IDENT("$Id$") # include } +# ifdef BSLS_PLATFORM_CMP_GNU +# pragma GCC diagnostic pop +# endif + // Intel #define's several symbols we don't want to leak out. # undef P7 diff --git a/groups/bdl/bdldfp/bdldfp_intelimpwrapper.t.cpp b/groups/bdl/bdldfp/bdldfp_intelimpwrapper.t.cpp index a0deb1c6bb..a228428023 100644 --- a/groups/bdl/bdldfp/bdldfp_intelimpwrapper.t.cpp +++ b/groups/bdl/bdldfp/bdldfp_intelimpwrapper.t.cpp @@ -126,7 +126,10 @@ int main(int argc, char* argv[]) int test = argc > 1 ? atoi(argv[1]) : 0; int verbose = argc > 2; int veryVerbose = argc > 3; - int veryveryVerbose = argc > 4; + int veryVeryVerbose = argc > 4; + + (void) veryVerbose; + (void) veryVeryVerbose; _IDEC_flags flags; @@ -245,6 +248,8 @@ int main(int argc, char* argv[]) BID_UINT64 doubleDecimalComputed; BID_UINT128 quadDecimalComputed; + (void) singleDecimal2; + doubleDecimalComputed = __bid64_add( doubleDecimal, doubleDecimal2, &flags); @@ -334,6 +339,7 @@ int main(int argc, char* argv[]) BID_UINT64 simpleDecimal; simpleDecimal = 42; + (void) simpleDecimal; } break; default: { cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl; diff --git a/groups/bdl/bdldfp/package/bdldfp.mem b/groups/bdl/bdldfp/package/bdldfp.mem index 712674aa66..63522cd76d 100644 --- a/groups/bdl/bdldfp/package/bdldfp.mem +++ b/groups/bdl/bdldfp/package/bdldfp.mem @@ -1,3 +1,4 @@ +bdldfp_binaryintegraldecimalimputil bdldfp_decimal bdldfp_decimalplatform bdldfp_decimalconvertutil