BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bdldfp_decimalconvertutil.h
Go to the documentation of this file.
1/// @file bdldfp_decimalconvertutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdldfp_decimalconvertutil.h -*-C++-*-
8#ifndef INCLUDED_BDLDFP_DECIMALCONVERTUTIL
9#define INCLUDED_BDLDFP_DECIMALCONVERTUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id$")
13
14/// @defgroup bdldfp_decimalconvertutil bdldfp_decimalconvertutil
15/// @brief Provide decimal floating-point conversion functions.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdldfp
19/// @{
20/// @addtogroup bdldfp_decimalconvertutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdldfp_decimalconvertutil-purpose"> Purpose</a>
25/// * <a href="#bdldfp_decimalconvertutil-classes"> Classes </a>
26/// * <a href="#bdldfp_decimalconvertutil-description"> Description </a>
27/// * <a href="#bdldfp_decimalconvertutil-encoding-formats"> Encoding Formats </a>
28/// * <a href="#bdldfp_decimalconvertutil-ieee-decimal-interchange-format"> IEEE Decimal Interchange Format </a>
29/// * <a href="#bdldfp_decimalconvertutil-multi-width-encoding-format"> Multi-Width Encoding Format </a>
30/// * <a href="#bdldfp_decimalconvertutil-variable-width-encoding-formats"> Variable-Width Encoding Formats </a>
31/// * <a href="#bdldfp_decimalconvertutil-conversion-between-binary-to-decimal"> Conversion between Binary to Decimal </a>
32/// * <a href="#bdldfp_decimalconvertutil-usage"> Usage </a>
33/// * <a href="#bdldfp_decimalconvertutil-example-1-sending-decimals-as-octets-using-network-format"> Example 1: Sending Decimals As Octets Using Network Format </a>
34/// * <a href="#bdldfp_decimalconvertutil-example-2-storingsending-decimals-in-binary-floating-point"> Example 2: StoringSending Decimals In Binary Floating-Point </a>
35///
36/// # Purpose {#bdldfp_decimalconvertutil-purpose}
37/// Provide decimal floating-point conversion functions.
38///
39/// # Classes {#bdldfp_decimalconvertutil-classes}
40///
41/// - bdldfp::DecimalConvertUtil: Namespace for decimal FP conversion functions
42///
43/// @see bdldfp_decimal, bdldfp_decimalplatform
44///
45/// # Description {#bdldfp_decimalconvertutil-description}
46/// This component provides namespace,
47/// `bdldfp::DecimalConvertUtil`, containing functions that are able to convert
48/// between the native decimal types of the platform and various other possible
49/// representations, such as binary floating-point, network encoding formats.
50///
51/// ## Encoding Formats {#bdldfp_decimalconvertutil-encoding-formats}
52///
53///
54/// This utility contains functions to encode decimal values to and from three
55/// different encoding formats:
56///
57/// * the IEEE decimal interchange format using decimal encoding for the
58/// significant (also known as the Densely Packed Decimal format, see IEEE
59/// 754. - 2008, section 3.5.2, for more details)
60/// * the multi-width encoding format, which is a custom format that can encode
61/// subsets of decimal values using a smaller number of bytes
62/// * the variable-width encoding format, which is a custom format that is
63/// similar to the multi-width encoding format with the main difference being
64/// that it self describes its own width
65///
66/// 64-bit decimal values encoded by the IEEE decimal interchange format always
67/// uses 8 bytes, which can be inefficient. The two custom encoding formats
68/// provided by this to enable more space efficient encoding of values commonly
69/// encountered by financial applications.
70///
71/// In the full IEEE encoding, 50 bits are used for the trailing bits of the
72/// mantissa, 13 bit is used for the combination field (exponent + special
73/// states to indicate NaN and Inf values + leading bits of the mantissa), and 1
74/// bit is used for the significant. The basic idea for the custom encoding
75/// formats is that the mantissa and exponent of many values (in typical
76/// financial applications) can fit into fewer bits than those provided by the
77/// full encoding. We can define a set of narrow formats to encode these
78/// smaller values without loss of precision. For example, a ticker values less
79/// than 100 dollars with a 2 decimal places of precision can be encoded using a
80/// 2 bytes encoding, using no sign bit, 3 bits for the exponent, and 13 bits
81/// for the mantissa.
82///
83/// ### IEEE Decimal Interchange Format {#bdldfp_decimalconvertutil-ieee-decimal-interchange-format}
84///
85///
86/// The IEEE decimal interchange format is defined by the IEEE standard. 64 bit
87/// decimal values encoded by this format always uses 8 bytes. The
88/// `decimalFromNetwork` and `decimalToNetwork` functions can be used encode to
89/// and decode from this format.
90///
91/// ### Multi-Width Encoding Format {#bdldfp_decimalconvertutil-multi-width-encoding-format}
92///
93///
94/// The multi-width encoding format uses a set of narrow encoding formats having
95/// sizes smaller than that used by the for IEEE format. Each of the narrower
96/// encoding format is used to encode a subset of values that can be represented
97/// by the full format. The following configuration is used to encode 64-bit
98/// decimal values:
99///
100/// @code
101/// |------|----------|----------|-----|----------|----------------|
102/// | size | S (bits) | E (bits) | B | T (bits) | max signficand |
103/// |------|----------|----------|-----|----------|----------------|
104/// | 1* | 0 | 1 | -2 | 7 | 127 |
105/// | 2 | 0 | 2 | -3 | 14 | 16383 |
106/// | 3 | 0 | 3 | -6 | 21 | 2097151 |
107/// | 4 | 1 | 5 | -16 | 26 | 67108863 |
108/// | 5 | 1 | 5 | -16 | 34 | 17179869183 |
109/// |------|-------------------------------------------------------|
110/// | 8 | FULL IEEE INTERCHANGE FORMAT** |
111/// |------|-------------------------------------------------------|
112///
113/// S = sign, E = exponent, B = bias, T = significant
114///
115/// * 1 byte encoding will be supported by the decoder but not the encoder. This
116/// is done due to the relatively large performance impact of adding the 1
117/// byte encoding to the encoder (10%). Preserving the encoding size in the
118/// decoder allows us to easily enable this encoding size at a later time.
119///
120/// ** If the value to be encoded can not fit in the 5-byte encoding or is -Inf,
121/// +Inf, or Nan, then the full 8-byte IEEE format will be used.
122/// @endcode
123///
124/// Since the multi-width encoding format consists of subformats having varying
125/// widths, the size of the subformat used must be supplied long with the
126/// encoding to the decode function. This is not required for either the IEEE
127/// format or the variable-width encoding format.
128///
129/// The `decimal64ToMultiWidthEncoding` and `decimal64FromMultiWidthEncoding`
130/// can be used to encode to and decode from this format. Currently, only
131/// 64-bit decimal values are supported by this encoding format.
132///
133/// ### Variable-Width Encoding Formats {#bdldfp_decimalconvertutil-variable-width-encoding-formats}
134///
135///
136/// The variable-width encoding format can encode decimal values using a
137/// variable number of bytes, similar to the multi-width encoding format. The
138/// difference is that the variable-width encoding format can self-describe its
139/// own size using special state (typically, predicate bits), so the decode
140/// function does not require the size of the encoding to work. The following
141/// configuration is used to encode 64-bit decimal values:
142///
143/// @code
144/// |------|------------|---|---|-----|----|-----------------|
145/// | size | P | S | E | B | T | max significant |
146/// |------|------------|---|---|-----|----|-----------------|
147/// | 2 | 0b0 | 0 | 2 | -2 | 13 | 8191 |
148/// | 3 | 0b10 | 0 | 3 | -4 | 19 | 524287 |
149/// | 4 | 0b11 | 1 | 5 | -16 | 24 | 16777215 |
150/// |------|------------|------------------------------------|
151/// | 9 | 0b11111111 | FULL IEEE FORMAT* |
152/// |------|------------|------------------------------------|
153///
154/// P = predicate (bit values)
155/// S = sign (bits), E = exponent (bits), B = bias
156/// T = significant (bits)
157///
158/// * If the value to be encoded can not fit in the 4-byte encoding or is -Inf,
159/// +Inf, or Nan, then the full 8-byte IEEE format will be used prefixed by a
160/// 1 byte predicate having the value of 0xFF.
161/// @endcode
162///
163/// The `decimal64ToVariableWidthEncoding` and
164/// `decimal64FromVariableWidthEncoding` can be used to encode to and decode
165/// from this format. Currently, only 64-bit decimal values are supported by
166/// this encoding format.
167///
168/// ## Conversion between Binary to Decimal {#bdldfp_decimalconvertutil-conversion-between-binary-to-decimal}
169///
170///
171/// The desire to convert numbers from binary to decimal format is fraught with
172/// misunderstanding, and is often accompanied by ill-conceived attempts to
173/// "correct rounding errors" and otherwise coerce results into aesthetically
174/// pleasing forms. In the Bloomberg environment, there is the additional
175/// complication of IBM/Perkin-Elmer/Interdata floating point. This is a
176/// floating-point format that uses a base-16 rather than a base-2 underlying
177/// representation, and the Bloomberg environment contains numbers that began as
178/// decimals, were converted to IBM format, and then were converted from IBM
179/// format to IEEE format.
180///
181/// Generically, when a decimal is converted to floating-point (using, for
182/// example, scanf from text, or `DecimalConvertUtil::decimalToDouble`), the
183/// result is the representable binary number nearest in value to that decimal.
184/// If there are two such, the one whose least significant bit is 0 is generally
185/// chosen. (This is also true for conversion of decimals to 32-bit
186/// Perkin-Elmer format, but when the Perkin-Elmer float is then converted to
187/// IEEE float, the resulting value is not the same as converting the decimal to
188/// IEEE float directly, because the Perkin-Elmer format can lose up to three
189/// bits of representation compared to the IEEE format.) Unless the decimal
190/// value is exactly a multiple of a power of two (e.g., 3.4375 = 55 * 1/16),
191/// the converted binary value cannot equal the decimal value, it can only be
192/// close. This utility provides `decimal{,32,64,128}To{Float,Double}`
193/// functions to convert decimal floating-point numbers to their closest binary
194/// floating-point values.
195///
196/// When converting from decimal to binary, it is hoped that two different
197/// decimal values (in the representable range of the target binary type)
198/// convert to two different binary values. There is a maximum number of
199/// significant digits for which this will be true. For example, all decimals
200/// with 6 significant digits convert to distinct `float` values, but 8589973000
201/// and 8589974000, with 7 significant digits, convert to the same `float`
202/// value. Similarly, all decimals with 15 significant digits convert to unique
203/// `double` values but 900719925474.0992 and 900719925474.0993, with 16
204/// significant digits, convert to the same `double` value. Over restricted
205/// ranges, the maximum may be higher - for example, every decimal value with 7
206/// or fewer significant digits between 1e-3 and 8.5e9 converts to a unique
207/// `float` value.
208///
209/// Because binary floating-point values are generally not equal to their
210/// decimal progenitors, "converting from binary to decimal" does not have a
211/// single meaning, and programmers who seek such an operation therefore need to
212/// know and specify the conversion they want. Common examples of conversions a
213/// programmer might seek are listed below:
214///
215/// 1. Express the value as its nearest decimal value.
216/// - For this conversion, use the conversion constructors:
217/// - `Decimal{32,64,128}(value)`
218/// 2. Express the value rounded to a given number of significant digits. (The
219/// significant digits of a decimal number are the digits with all leading
220/// and trailing 0s removed; e.g., 0.00103, 10.3 and 10300 each have 3
221/// significant digits.) This conversion is the one that leads programmers
222/// to complain about "rounding error" (for example, .1f rounded to 9 digits
223/// is .100000001) but is the appropriate one to use when the programmer
224/// knows that the binary value was originally converted from a decimal value
225/// with that many significant digits.
226/// - For this conversion, use:
227/// - `Decimal{32,64,128}From{Float,Double}(value, digits)`
228/// 3. Express the value using the minimum number of significant digits for the
229/// type of the binary such that converting the decimal value back to binary
230/// will yield the same value. (Note that 17 digits are needed for `double`
231/// and 9 for `float`, so not all decimal types can hold such a result.)
232/// - For this conversion, use:
233/// - `Decimal{64,128}FromFloat(value, 9)` or
234/// - `Decimal128FromDouble(value, 17)`
235/// 4. Express the value using a number of decimal places that restores the
236/// original decimal value from which the binary value was converted,
237/// assuming that the original decimal value had sufficiently few significant
238/// digits so that no two values with that number of digits would convert to
239/// the same binary value. (That number is 15 for `double` and 6 for `float`
240/// in general but 7 over a limited range that spans `[1e-3 .. 8.5e9]`).
241/// - For this conversion, use:
242/// - `Decimal{32,64,128}From{Float,Double}(value)`
243/// 5. Express the value as the shortest decimal number that converts back
244/// exactly to the binary value. For example. given the binary value
245/// 0x3DCCCCCD above, that corresponding shortest decimal value is
246/// (unsurprisingly) .1, while the next lower value 0x3DCCCCCC has the
247/// shortest decimal .099999994 and the next higher value 0x3DCCCCCE has the
248/// shortest decimal .010000001. This is the most visually appealing result,
249/// but can be expensive and slow to compute.
250///
251/// - For this conversion, use:
252/// - `Decimal{32,64,128}From{Float,Double}(value, -1)`
253/// 6. Express the value using a number of decimal places that restores the
254/// original decimal value assuming that it is a `float` which originated as
255/// an IBM/Perkin-Elmer/Interdata `float` value itself originally converted
256/// from a decimal value.
257/// - For this conversion, use:
258/// - `Decimal{32,64,128}FromFloat(value, 6)`
259/// 7. Express the value exactly as a decimal. For example, the decimal
260/// value .1 converts to the 32-bit IEEE float value 0x3DCCCCCD, which has
261/// the exact value .100000001490116119384765625. This conversion is seldom
262/// useful, except perhaps for debugging, since the exact value may have over
263/// 1000. digits, and as well cannot be represented as a decimal
264/// floating-point type since those types do not have enough digits.
265/// - For this conversion, use `sprintf` into a large-enough buffer:
266/// - `char buf[2000]; double value; sprintf(buf, "%.1100f", value);`
267/// - The result will have trailing 0s, which may be trimmed.
268/// 8. Express the value rounded to a given number of decimal places. (The
269/// decimal places of a decimal number are the number of digits after the
270/// decimal point, with trailing 0s removed; .01, 10.01, and 1000.01 each
271/// have two decimal places.) This conversion can be problematic when the
272/// integer portion of the value is large, as there may not be enough
273/// precision remaining to deliver a meaningful number of decimal places. As
274/// seen above, for example, for numbers near one trillion, there is not
275/// enough precision in a `double` for 4 decimal places.
276/// - For this conversion, use `sprintf` into a large-enough buffer:
277/// - `char buf[2000]; double value; sprintf(buf, "%.*f", places, value);`
278///
279/// ## Usage {#bdldfp_decimalconvertutil-usage}
280///
281///
282/// This section shows the intended use of this component.
283///
284/// ### Example 1: Sending Decimals As Octets Using Network Format {#bdldfp_decimalconvertutil-example-1-sending-decimals-as-octets-using-network-format}
285///
286///
287/// Suppose you have two communicating entities (programs) that talk to each
288/// other using a binary (as opposed to text) protocol. In such protocol it is
289/// important to establish a so-called network format, and convert to and from
290/// that format in the protocol layer. The sender (suppose that it is an IBM
291/// server that has just finished an expensive calculation involving millions
292/// of numbers and needs to send the result to its client) will need to convert
293/// the data to network format before sending:
294/// @code
295/// unsigned char msgbuffer[256];
296/// unsigned char *next = msgbuffer;
297///
298/// BDEC::Decimal64 number(BDLDFP_DECIMAL_DD(1.234567890123456e-42));
299/// unsigned char expected[] = {
300/// 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 };
301///
302/// next = bdldfp::DecimalConvertUtil::decimalToNetwork(next, number);
303///
304/// assert(memcmp(msgbuffer, expected, sizeof(number)) == 0);
305/// @endcode
306/// The receiver/client shall then restore the number from network format:
307/// @code
308/// unsigned char msgbuffer[] ={
309/// 0x25, 0x55, 0x34, 0xb9, 0xc1, 0xe2, 0x8e, 0x56 };
310/// unsigned char *next = msgbuffer;
311///
312/// BDEC::Decimal64 number;
313/// BDEC::Decimal64 expected(BDLDFP_DECIMAL_DD(1.234567890123456e-42));
314///
315/// next = bdldfp::DecimalConvertUtil::decimalFromNetwork(number, next);
316///
317/// assert(number == expected);
318/// @endcode
319///
320/// ### Example 2: StoringSending Decimals In Binary Floating-Point {#bdldfp_decimalconvertutil-example-2-storingsending-decimals-in-binary-floating-point}
321///
322///
323/// Suppose you have two communicating entities (programs) that talk to each
324/// other using a legacy protocol that employs binary floating-point formats to
325/// send/receive numbers. So your application layer will have to store the
326/// decimal into a binary FP variable, ensure that it can be restored (in other
327/// words that it has "fit" into the binary type) when sending, and restore the
328/// decimal number (from the binary type) when receiving:
329/// @code
330/// const BDEC::Decimal64 number(BDLDFP_DECIMAL_DD(1.23456789012345e-42));
331///
332/// typedef bdldfp::DecimalConvertUtil Util;
333/// double dbl = Util::decimalToDouble(number);
334///
335/// if (Util::decimal64FromDouble(dbl) != number) {
336/// // Do what is appropriate for the application
337/// }
338/// @endcode
339/// Note that the above assert would probably be a lot more complicated if
340/// statement in production code. It may actually be acceptable to put the
341/// decimal onto the wire with certain amount of imprecision.
342///
343/// The receiver would then restore the number using the appropriate
344/// `decimal64FromDouble` function:
345/// @code
346/// BDEC::Decimal64 restored = Util::decimal64FromDouble(dbl);
347///
348/// assert(number == restored);
349/// @endcode
350/// @}
351/** @} */
352/** @} */
353
354/** @addtogroup bdl
355 * @{
356 */
357/** @addtogroup bdldfp
358 * @{
359 */
360/** @addtogroup bdldfp_decimalconvertutil
361 * @{
362 */
363
364#include <bdlscm_version.h>
365
366#include <bdldfp_decimal.h>
371#include <bdldfp_decimalutil.h>
373
374#include <bsls_assert.h>
375#include <bsls_byteorder.h>
376#include <bsls_performancehint.h>
377#include <bsls_platform.h>
378#include <bsls_types.h>
379
380#include <bsl_cstring.h>
381
382#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
383#include <bsl_c_signal.h> // Formerly transitively included via decContext.h
384#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
385
386
387namespace bdldfp {
388 // ========================
389 // class DecimalConvertUtil
390 // ========================
391
392/// This `struct` provides a namespace for utility functions that convert
393/// between the decimal floating-point types of @ref bdldfp_decimal and various
394/// other formats.
395///
396/// See @ref bdldfp_decimalconvertutil
398
399 private:
400 // PRIVATE TYPES
401#if defined(BDLDFP_DECIMALPLATFORM_INTELDFP)
402 typedef DecimalConvertUtil_IntelDfp Imp;
403#else
404 BDLDFP_DECIMALPLATFORM_COMPILER_ERROR;
405#endif
406
407 // PRIVATE CLASS DATA
408
409 // 'bid64' REPRESENTATION CONSTANTS
410
411 static const int k_EXPONENT_SHIFT_SMALL64 = 53; // exponent position
412 static const int k_EXPONENT_MASK64 = 0x3ff; // exponent mask bits
413 static const unsigned long long k_SPECIAL_ENCODING_MASK64 =
414 0x6000000000000000ull; // special when non-zero
415 static const unsigned long long k_SMALL_COEFF_MASK64 =
416 0x001fffffffffffffull; // mask for mantissa
417
418 // PRIVATE CLASS METHODS
419
420 /// If the specified `value` is NaN, +infinity, -infinity, or its
421 /// unbiased exponent is 384, return a non-zero value and leave all
422 /// output parameters unmodified. Otherwise, partition the `value` into
423 /// sign, biased exponent, and mantissa compartments, and load the
424 /// corresponding values into the specified `isNegative`, `biasedExponent`, and `mantissa`. Return 0.
425 ///
426 /// \note Note that a non-zero
427 /// value does not indicate that `value` can not be partitioned, just
428 /// that it can not be partitioned by this function. Also note that the
429 /// bias for `Decimal64` is 398.
430 static int decimal64ToUnpackedSpecial(bool *isNegative,
431 int *biasedExponent,
432 bsls::Types::Uint64 *mantissa,
433 bdldfp::Decimal64 value);
434
435 /// Return a `Decimal64` object that has the specified `mantissa`,
436 /// `exponent`, and a sign based on the specified `isNegative`.
437 ///
438 /// \pre The behavior is undefined unless `isNegative`, `mantissa`, and the
439 /// biased exponent were originally obtained from `decimal64ToUnpackedSpecial`.
440 ///
441 /// \note Note that `exponent` should be
442 /// unbiased, so 398 should be subtracted from the biased exponent
443 /// gotten from `decimal64ToUnpackedSpecial`.
444 static bdldfp::Decimal64 decimal64FromUnpackedSpecial(
445 bool isNegative,
446 bsls::Types::Uint64 mantissa,
447 int exponent);
448
449
450 /// Return a `Decimal64` object that has the specified `mantissa`, `exponent`.
451 ///
452 /// \pre The behavior is undefined unless `isNegative`,
453 /// `mantissa`, and the biased exponent were originally obtained from `decimal64ToUnpackedSpecial`.
454 ///
455 /// \note Note that `exponent` should be
456 /// unbiased, so 398 should be subtracted from the biased exponent
457 /// gotten from `decimal64ToUnpackedSpecial`.
458 static bdldfp::Decimal64 decimal64FromUnpackedSpecial(int mantissa,
459 int exponent);
460
461 public:
462 // CLASS METHODS
463
464 // decimalToDouble functions
465
466 static double decimal32ToDouble (Decimal32 decimal);
467 static double decimal64ToDouble (Decimal64 decimal);
468
469 /// @deprecated Use @ref deciamalToDouble instead.
470 static double decimal128ToDouble(Decimal128 decimal);
471
472 /// Return a `double` object having the value closest to the value of
473 /// the specified `decimal` object following the conversion rules
474 /// defined by IEEE-754:
475 ///
476 /// * If the `decimal` object is a NaN, return a NaN.
477 /// * Otherwise if `decimal` is positive or negative infinity, return
478 /// infinity of the same sign.
479 /// * Otherwise if `decimal` is positive or negative zero, return zero
480 /// of the same sign.
481 /// * Otherwise if `decimal` object has an absolute value that is
482 /// larger than `std::numeric_limits<double>::max()`, raise the
483 /// "overflow" floating-point exception and return infinity of the
484 /// same sign as `decimal`.
485 /// * Otherwise if `decimal` has an absolute value that is smaller than
486 /// `std::numeric_limits<double>::min()`, raise the "underflow"
487 /// floating-point exception and return zero of the same sign as
488 /// `decimal`.
489 /// * Otherwise if `decimal` has a value that has more significant
490 /// base-10 digits than `std::numeric_limits<double>::digits10`,
491 /// raise the "inexact" floating-point exception, round that value
492 /// according to the *binary* rounding direction setting of the
493 /// floating-point environment, and return the result of that.
494 /// * Otherwise if `decimal` has a significand that cannot be exactly
495 /// represented using binary floating-point, raise the "inexact"
496 /// floating-point exception, round that value according to the
497 /// *binary* rounding direction setting of the environment, and
498 /// return the result of that.
499 /// * Otherwise use the exact value of the `other` object for the
500 /// initialization if this object.
501 static double decimalToDouble (Decimal32 decimal);
502 static double decimalToDouble (Decimal64 decimal);
503 static double decimalToDouble (Decimal128 decimal);
504
505 // decimalToFloat functions
506
507 static float decimal32ToFloat (Decimal32 decimal);
508 static float decimal64ToFloat (Decimal64 decimal);
509
510 /// @deprecated Use @ref deciamalToFloat instead.
511 static float decimal128ToFloat(Decimal128 decimal);
512
513 /// Return a `float` object having the value closest to the value of the
514 /// specified `decimal` object following the conversion rules defined
515 /// by IEEE-754:
516 ///
517 /// * If the `decimal` object is a NaN, return a NaN.
518 /// * Otherwise if `decimal` is positive or negative infinity, return
519 /// infinity of the same sign.
520 /// * Otherwise if `decimal` is positive or negative zero, return zero
521 /// of the same sign.
522 /// * Otherwise if `decimal` object has an absolute value that is
523 /// larger than `std::numeric_limits<long double>::max()`, raise the
524 /// "overflow" floating-point exception and return infinity of the
525 /// same sign as `decimal`.
526 /// * Otherwise if `decimal` has an absolute value that is smaller than
527 /// `std::numeric_limits<float>::min()`, raise the "underflow"
528 /// floating-point exception and return zero of the same sign as
529 /// `decimal`.
530 /// * Otherwise if `decimal` has a value that has more significant
531 /// base-10 digits than `std::numeric_limits<float>::digits10`,
532 /// raise the "inexact" floating-point exception, round that value
533 /// according to the *binary* rounding direction setting of the
534 /// floating-point environment, and return the result of that.
535 /// * Otherwise if `decimal` has a significand that cannot be exactly
536 /// represented using binary floating-point, raise the "inexact"
537 /// floating-point exception, round that value according to the
538 /// *binary* rounding direction setting of the environment, and
539 /// return the result of that.
540 /// * Otherwise use the exact value of the `other` object for the
541 /// initialization if this object.
542 static float decimalToFloat (Decimal32 decimal);
543 static float decimalToFloat (Decimal64 decimal);
544 static float decimalToFloat (Decimal128 decimal);
545
546 // decimalFromDouble functions
547
548 static Decimal32 decimal32FromDouble (double binary, int digits = 0);
549 static Decimal32 decimal32FromFloat (float binary, int digits = 0);
550 static Decimal64 decimal64FromDouble (double binary, int digits = 0);
551 static Decimal64 decimal64FromFloat (float binary, int digits = 0);
552 static Decimal128 decimal128FromDouble(double binary, int digits = 0);
553
554 /// Return a decimal floating-point number converted from the specified
555 /// `binary`.
556 ///
557 /// If `binary` is singular (+/-NaN, +/-Inf, or +/-0) or is not within
558 /// the representable range of the return type, return a corresponding
559 /// decimal singular value.
560 ///
561 /// Optionally specify `digits` to indicate the number of significant
562 /// digits to produce in the returned value. The `digits` parameter is
563 /// treated as follows:
564 ///
565 /// If `digits` is larger than the number of digits in the destination
566 /// type, it will be reduced to that number of digits.
567 ///
568 /// If `digits` is positive, the result is `binary` rounded to that many
569 /// significant digits.
570 ///
571 /// If `digits` is negative, the decimal value with the fewest
572 /// significant digits that converts back to `binary` is returned if
573 /// possible, and otherwise the value closest to `binary` is returned.
574 ///
575 /// \note Note that this provides the most visually appealing result but is
576 /// the most expensive to compute.
577 ///
578 /// If `digits` is not specified or 0, a default value will be used
579 /// (possibly depending on the value of `binary`) based on the premise
580 /// that `binary` is a converted decimal value of no more significant
581 /// digits than is guaranteed to have a uniquely converted binary value
582 /// (15 for `double`, 6 for `float` in general, and 7 for `float` in the range `[ .0009999995 .. 8589972000 ]`).
583 ///
584 /// \note Note that this is likely to
585 /// have the best performance for "business" numbers (i.e., numbers that
586 /// originate as decimal values in external market quote feeds).
587 ///
588 ///
589 /// \note Note that the purpose of these functions is to restore a decimal
590 /// value that has been converted to a binary floating-point type. It
591 /// is more efficient to use conversion constructors when all that is
592 /// needed is the nearest decimal to the `binary` value.
593 ///
594 ///
595 /// \note Note that if `binary` is a `float` value that was converted from an
596 /// IBM/Perkin-Elmer/Interdata binary `float` value itself converted
597 /// from a decimal value of no more than 6 significant digits,
598 /// specifying 6 for `digits` will recover the original decimal value.
599 /// Not specifying `digits` may result in a value having a spurious
600 /// seventh digit.
601 static Decimal128 decimal128FromFloat (float binary, int digits = 0);
602
603 // decimalToDPD functions
604
605 static void decimal32ToDPD (unsigned char *buffer,
606 Decimal32 decimal);
607 static void decimal64ToDPD (unsigned char *buffer,
608 Decimal64 decimal);
609 static void decimal128ToDPD(unsigned char *buffer,
610 Decimal128 decimal);
611
612 /// Populate the specified `buffer` with the Densely Packed Decimal
613 /// (DPD) representation of the specified `decimal` value. The DPD
614 /// representations of `Decimal32`, `Decimal64`, and `Decimal128`
615 /// require 4, 8, and 16 bytes respectively.
616 ///
617 /// \pre The behavior is undefined unless `buffer` points to a contiguous sequence of at least `sizeof(decimal)` bytes.
618 ///
619 /// \note Note that the DPD representation is
620 /// defined in section 3.5 of IEEE 754-2008.
621 static void decimalToDPD (unsigned char *buffer,
622 Decimal32 decimal);
623 static void decimalToDPD (unsigned char *buffer,
624 Decimal64 decimal);
625 static void decimalToDPD (unsigned char *buffer,
626 Decimal128 decimal);
627
628 // decimalFromDPD functions
629
630 static Decimal32 decimal32FromDPD (const unsigned char *buffer);
631 static Decimal64 decimal64FromDPD (const unsigned char *buffer);
632
633 /// Return the native implementation representation of the value of the
634 /// same size base-10 floating-point value stored in Densely Packed
635 /// Decimal format at the specified `buffer` address.
636 ///
637 /// \pre The behavior is undefined unless `buffer` points to a memory area at least
638 /// `sizeof(decimal)` in size containing a value in DPD format.
639 static Decimal128 decimal128FromDPD(const unsigned char *buffer);
640
641 static void decimal32FromDPD (Decimal32 *decimal,
642 const unsigned char *buffer);
643 static void decimal64FromDPD (Decimal64 *decimal,
644 const unsigned char *buffer);
645 static void decimal128FromDPD(Decimal128 *decimal,
646 const unsigned char *buffer);
647
648 /// Store, into the specified `decimal`, the native implementation
649 /// representation of the value of the same size base-10 floating point
650 /// value represented in Densely Packed Decimal format, at the specified `buffer` address.
651 ///
652 /// \pre The behavior is undefined unless `buffer` points
653 /// to a memory area at least `sizeof(decimal)` in size containing a
654 /// value in DPD format.
655 static void decimalFromDPD (Decimal32 *decimal,
656 const unsigned char *buffer);
657 static void decimalFromDPD (Decimal64 *decimal,
658 const unsigned char *buffer);
659 static void decimalFromDPD (Decimal128 *decimal,
660 const unsigned char *buffer);
661
662 // decimalToBID functions
663
664 static void decimal32ToBID (unsigned char *buffer,
665 Decimal32 decimal);
666 static void decimal64ToBID (unsigned char *buffer,
667 Decimal64 decimal);
668 static void decimal128ToBID(unsigned char *buffer,
669 Decimal128 decimal);
670
671 /// Populate the specified `buffer` with the Binary Integer Decimal
672 /// (BID) representation of the specified `decimal` value. The BID
673 /// representations of `Decimal32`, `Decimal64`, and `Decimal128`
674 /// require 4, 8, and 16 bytes respectively.
675 ///
676 /// \pre The behavior is undefined unless `buffer` points to a contiguous sequence of at least `sizeof(decimal)` bytes.
677 ///
678 /// \note Note that the BID representation is
679 /// defined in section 3.5 of IEEE 754-2008.
680 static void decimalToBID (unsigned char *buffer,
681 Decimal32 decimal);
682 static void decimalToBID (unsigned char *buffer,
683 Decimal64 decimal);
684 static void decimalToBID (unsigned char *buffer,
685 Decimal128 decimal);
686
687 // decimalFromBID functions
688
689 static Decimal32 decimal32FromBID (const unsigned char *buffer);
690 static Decimal64 decimal64FromBID (const unsigned char *buffer);
691
692 /// Return the native implementation representation of the value of the
693 /// same size base-10 floating-point value stored in Binary Integer
694 /// Decimal format at the specified `buffer` address.
695 ///
696 /// \pre The behavior is undefined unless `buffer` points to a memory area at least
697 /// `sizeof(decimal)` in size containing a value in BID format.
698 static Decimal128 decimal128FromBID(const unsigned char *buffer);
699
700 static void decimal32FromBID (Decimal32 *decimal,
701 const unsigned char *buffer);
702 static void decimal64FromBID (Decimal64 *decimal,
703 const unsigned char *buffer);
704 static void decimal128FromBID(Decimal128 *decimal,
705 const unsigned char *buffer);
706
707 /// Store, into the specified `decimal`, the native implementation
708 /// representation of the value of the same size base-10 floating point
709 /// value represented in Binary Integer Decimal format, at the specified `buffer` address.
710 ///
711 /// \pre The behavior is undefined unless `buffer` points
712 /// to a memory area at least `sizeof(decimal)` in size containing a
713 /// value in BID format.
714 static void decimalFromBID (Decimal32 *decimal,
715 const unsigned char *buffer);
716 static void decimalFromBID (Decimal64 *decimal,
717 const unsigned char *buffer);
718 static void decimalFromBID (Decimal128 *decimal,
719 const unsigned char *buffer);
720
721 // decimalToNetwork functions
722
723 static unsigned char *decimal32ToNetwork (unsigned char *buffer,
724 Decimal32 decimal);
725 static unsigned char *decimal64ToNetwork (unsigned char *buffer,
726 Decimal64 decimal);
727 static unsigned char *decimal128ToNetwork(unsigned char *buffer,
728 Decimal128 decimal);
729
730 /// Store the specified `decimal`, in network format, into the specified
731 /// `buffer` and return the address one past the last byte written into
732 /// the `buffer`. The network format is defined as big endian byte
733 /// order and densely packed base-10 significand encoding. This
734 /// corresponds to the way IBM hardware represents these numbers in memory.
735 ///
736 /// \pre The behavior is undefined unless `buffer` points to a memory area at least `sizeof(decimal)` in size.
737 ///
738 /// \note Note that these
739 /// functions always return `buffer + sizeof(decimal)` on the supported
740 /// 8-bits-byte architectures.
741 static unsigned char *decimalToNetwork (unsigned char *buffer,
742 Decimal32 decimal);
743 static unsigned char *decimalToNetwork (unsigned char *buffer,
744 Decimal64 decimal);
745 static unsigned char *decimalToNetwork (unsigned char *buffer,
746 Decimal128 decimal);
747
748 // decimalFromNetwork functions
749
750 static const unsigned char *decimal32FromNetwork(
751 Decimal32 *decimal,
752 const unsigned char *buffer);
753 static const unsigned char *decimal64FromNetwork(
754 Decimal64 *decimal,
755 const unsigned char *buffer);
756 static const unsigned char *decimal128FromNetwork(
757 Decimal128 *decimal,
758 const unsigned char *buffer);
759
760 /// Store into the specified `decimal`, the value of the same size
761 /// base-10 floating-point value stored in network format at the
762 /// specified `buffer` address and return the address one past the last
763 /// byte read from `buffer`. The network format is defined as big
764 /// endian byte order and densely packed base-10 significand encoding.
765 /// This corresponds to the way IBM hardware represents these numbers in memory.
766 ///
767 /// \pre The behavior is undefined unless `buffer` points to a memory area at least `sizeof(decimal)` bytes.
768 ///
769 /// \note Note that these
770 /// functions always return `buffer + sizeof(decimal)` on the supported
771 /// 8-bits-byte architectures.
772 static const unsigned char *decimalFromNetwork(
773 Decimal32 *decimal,
774 const unsigned char *buffer);
775 static const unsigned char *decimalFromNetwork(
776 Decimal64 *decimal,
777 const unsigned char *buffer);
778 static const unsigned char *decimalFromNetwork(
779 Decimal128 *decimal,
780 const unsigned char *buffer);
781
782 /// Store the specified `decimal`, in the *multi-width encoding* format,
783 /// into the specified `buffer` and return the number of bytes used by the encoding.
784 ///
785 /// \pre The behavior is undefined unless `buffer` points to a
786 /// memory area with enough room to hold the encode value (which has a
787 /// maximum size of 8 bytes).
789 unsigned char *buffer,
790 bdldfp::Decimal64 decimal);
791
792 /// If the specified `decimal` can be encoded in 5 or fewer bytes of the
793 /// *multi-width encoding* format, then store `decimal` into the
794 /// specified `buffer` in that format, and return the number of bytes
795 /// written to `buffer`. Otherwise, return 0.
796 ///
797 /// \pre The behavior is undefined unless `buffer` points to a memory area having at least 5 bytes.
798 ///
799 /// \note Note that this function does not supporting encoding values
800 /// requiring a full IEEE network encoding, which is supported by the
801 /// `decimal64ToMultiWidthEncoding` function.
803 unsigned char *buffer,
804 bdldfp::Decimal64 decimal);
805
806 /// Decode a decimal value in the *multi-width encoding* format from the
807 /// specified `buffer` having the specified `size`. Return the decoded value.
808 ///
809 /// \pre The behavior is undefined unless `buffer` has at least
810 /// `size` bytes, `size` is a valid encoding size in the `multi-width encoding` format, and `size <= 5`.
811 ///
812 /// \note Note that this
813 /// function does not support decoding values requiring a full IEEE
814 /// network encoding, which is supported by the
815 /// `decimal64FromMultiWidthEncoding` function.
817 const unsigned char *buffer,
819
820 /// Return `true` if the specified `size` is a valid encoding size in
821 /// the *multi-width encoding* format, and `false` otherwise.
822 ///
823 /// \note Note that valid encoding sizes are 1, 2, 3, 4, 5 and 8 bytes.
825
826 /// Decode a decimal value in the *multi-width encoding* format from the
827 /// specified `buffer` having the specified `size`. Return the decoded value.
828 ///
829 /// \pre The behavior is undefined unless `buffer` has at least
830 /// `size` bytes, and `size` is a valid encoding size in the
831 /// `multi-width encoding` format.
833 const unsigned char *buffer,
835
836 /// Decode a decimal value in the *multi-width encoding* format from the
837 /// specified `buffer` having the specified `size` and store the result
838 /// into the specified `decimal` parameter. Return 0 on success, and non-zero value otherwise.
839 ///
840 /// \pre The behavior is undefined unless `buffer` has at least `size` bytes.
841 ///
842 /// \note Note that this function returns a
843 /// non-zero value and leaves `decimal` unchanged if `size` is not a
844 /// valid encoding size of the *multi-width encoding* format.
846 Decimal64 *decimal,
847 const unsigned char *buffer,
849
850 /// Store the specified `decimal`, in the *variable-width encoding*
851 /// format, into the specified `buffer` and return the address one past
852 /// the last byte written into the `buffer`.
853 ///
854 /// \pre The behavior is undefined unless `buffer` points to a memory area with enough room to hold the
855 /// encoded value (which has a maximum size of 9 bytes).
856 static unsigned char *decimal64ToVariableWidthEncoding(
857 unsigned char *buffer,
858 bdldfp::Decimal64 decimal);
859
860 /// Store into the specified `decimal`, the value of `Decimal64` value
861 /// stored in the *variable-width encoding* format at the specified
862 /// `buffer` address. Return the address one past the last byte read from `buffer`.
863 ///
864 /// \pre The behavior is undefined unless `buffer` points to
865 /// a memory area holding a `Decimal64` value encoded in the
866 /// *variable-width encoding* format.
867 static const unsigned char *decimal64FromVariableWidthEncoding(
868 bdldfp::Decimal64 *decimal,
869 const unsigned char *buffer);
870};
871
872// ============================================================================
873// INLINE DEFINITIONS
874// ============================================================================
875
876
877// PRIVATE CLASS METHODS
878
879inline
880int DecimalConvertUtil::decimal64ToUnpackedSpecial(
881 bool *isNegative,
882 int *biasedExponent,
883 bsls::Types::Uint64 *mantissa,
884 bdldfp::Decimal64 value)
885{
886#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
887 bsls::Types::Uint64 bidValue = value.data()->d_raw;
888#else
889 bsls::Types::Uint64 bidValue = bid_dpd_to_bid64(
890 static_cast<bsls::Types::Uint64>(*(value.data())));
891#endif
892 // This class method is based on inteldfp 'unpack_BID64' (bid_internal.h),
893 // with a non-zero return if 'SPECIAL_ENCODING_MASK64' indicates a special
894 // encoding; these are practically non-existent and no need to optimize.
895
897 (bidValue & k_SPECIAL_ENCODING_MASK64) == k_SPECIAL_ENCODING_MASK64)) {
899 // punt on special encodings
900 return -1; // RETURN
901 }
902
903 *isNegative = (bidValue & 0x8000000000000000ull) ? 1 : 0;
904
905 *biasedExponent = static_cast<int>(
906 (bidValue >> k_EXPONENT_SHIFT_SMALL64) & k_EXPONENT_MASK64);
907
908 *mantissa = bidValue & k_SMALL_COEFF_MASK64;
909
910 return 0;
911}
912
913inline
914Decimal64 DecimalConvertUtil::decimal64FromUnpackedSpecial(
915 bool isNegative,
916 bsls::Types::Uint64 mantissa,
917 int exponent)
918{
919#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
920 bdldfp::Decimal64 result;
921 result.data()->d_raw = (isNegative ? 0x8000000000000000ull : 0) |
922 (static_cast<BID_UINT64>(exponent + 398)
923 << k_EXPONENT_SHIFT_SMALL64) |
924 mantissa;
925 return result;
926#else
927 if (isNegative) {
929 -static_cast<long long>(mantissa),
930 exponent);
931 } else {
932 return DecimalImpUtil::makeDecimalRaw64(mantissa, exponent);
933 }
934#endif
935}
936
937inline
938Decimal64 DecimalConvertUtil::decimal64FromUnpackedSpecial(int mantissa,
939 int exponent)
940{
941#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
942 bdldfp::Decimal64 result;
943 result.data()->d_raw = (static_cast<BID_UINT64>(exponent + 398)
944 << k_EXPONENT_SHIFT_SMALL64) |
945 mantissa;
946 return result;
947#else
948 return DecimalUtil::makeDecimalRaw64(mantissa, exponent);
949#endif
950}
951
952// CLASS METHODS
953inline
955 unsigned char *buffer,
956 bdldfp::Decimal64 decimal)
957{
958
960 decimal);
961
963 return size; // RETURN
964 }
965 else {
967 bsls::Types::Uint64 encoded;
968 bsl::memcpy(reinterpret_cast<unsigned char *>(&encoded),
969 decimal.data(),
970 sizeof(encoded));
971
972 encoded = BSLS_BYTEORDER_HTONLL(encoded);
973
974 bsl::memcpy(buffer,
975 reinterpret_cast<unsigned char*>(&encoded),
976 8);
977 return 8; // RETURN
978 }
979}
980
981inline
983 unsigned char *buffer,
984 bdldfp::Decimal64 decimal)
985{
986 bool isNegative;
987 int exponent;
988 bsls::Types::Uint64 mantissa;
989
990 // 'exponent' is biased --> biased exponent = exponent + 398
991
993 decimal64ToUnpackedSpecial(&isNegative,
994 &exponent,
995 &mantissa,
996 decimal))) {
997 if (!isNegative) {
998 if (395 <= exponent && exponent < 399) {
999 if (mantissa < (1u << 14)) {
1000 unsigned short squished = static_cast<unsigned short>(
1001 mantissa | (exponent - 395) << 14);
1002
1003 unsigned short squishedN = BSLS_BYTEORDER_HTONS(squished);
1004 bsl::memcpy(buffer, &squishedN, 2);
1005 return 2; // RETURN
1006 }
1007 }
1008 if (392 <= exponent && exponent < 400) {
1009 if (mantissa < (1u << 21)) {
1010 // On IBM (and Linux to a lesser extent), copying from a
1011 // word-aligned source is faster, so we shift an extra the
1012 // source by an extra 8 bits.
1013
1014 unsigned int squished = static_cast<unsigned int>(
1015 (mantissa << 8) | (exponent - 392) << 29);
1016 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
1017
1018 bsl::memcpy(buffer,
1019 reinterpret_cast<unsigned char*>(&squishedN),
1020 3);
1021 return 3; // RETURN
1022 }
1023 }
1024 }
1025
1026 if (382 <= exponent && exponent < 414) {
1027 if (mantissa < (1u << 26)) {
1028 unsigned int squished = static_cast<unsigned int>(
1029 mantissa | (exponent - 382) << 26);
1030 if (isNegative) {
1031 squished |= 1u << 31;
1032 }
1033 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
1034 bsl::memcpy(buffer, &squishedN, 4);
1035 return 4; // RETURN
1036 }
1037 if (mantissa < (1ull << 34)) {
1038 bsls::Types::Uint64 squished =
1039 static_cast<bsls::Types::Uint64>(
1040 (mantissa << 24) |
1041 (static_cast<bsls::Types::Uint64>(exponent - 382) << 58));
1042 if (isNegative) {
1043 squished |= 1ull << 63;
1044 }
1045 bsls::Types::Uint64 squishedN =
1046 BSLS_BYTEORDER_HTONLL(squished);
1047 bsl::memcpy(buffer,
1048 reinterpret_cast<unsigned char*>(&squishedN),
1049 5);
1050 return 5; // RETURN
1051 }
1052 }
1053 }
1054
1055 return 0;
1056}
1057
1058inline
1060{
1061 return (size > 0 && size <= 5) || size == 8;
1062}
1063
1064inline
1066 const unsigned char *buffer,
1068{
1069 BSLS_ASSERT(1 <= size);
1070 BSLS_ASSERT(size <= 5 || size == 8);
1071
1073 return decimal64FromMultiWidthEncodingRaw(buffer, size); // RETURN
1074 }
1075 else {
1077
1078 bsls::Types::Uint64 encoded;
1079 bsl::memcpy(&encoded, buffer, 8);
1080 encoded = BSLS_BYTEORDER_NTOHLL(encoded);
1081
1083 bsl::memcpy(&decimal, &encoded, sizeof(decimal));
1084
1085 return decimal; // RETURN
1086 }
1087}
1088
1089inline
1091 Decimal64 *decimal,
1092 const unsigned char *buffer,
1094{
1095 int ret(0);
1096
1097 if (isValidMultiWidthSize(size)) {
1098 *decimal = decimal64FromMultiWidthEncoding(buffer, size);
1099 }
1100 else {
1101 ret = 1;
1102 }
1103 return ret;
1104}
1105
1106inline
1108 const unsigned char *buffer,
1110{
1111 BSLS_ASSERT(1 <= size);
1112 BSLS_ASSERT(size <= 5);
1113
1114 switch(size) {
1115 case 2: {
1116 int exponent = (buffer[0] >> 6) - 3;
1117 int mantissa = static_cast<int>(((buffer[0] & 0x3F) << 8) |
1118 static_cast<int>(buffer[1]));
1119
1120 return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN
1121 } break;
1122 case 3: {
1123 int exponent = (buffer[0] >> 5) - 6;
1124 int mantissa = static_cast<int>(((buffer[0] & 0x1F) << 16) |
1125 static_cast<int>(buffer[1]) << 8 |
1126 static_cast<int>(buffer[2]));
1127 return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN
1128 } break;
1129 case 4: {
1130 bool isNegative = buffer[0] >> 7;
1131 int exponent = ((buffer[0] & 0x7F) >> 2) - 16;
1132 int mantissa = static_cast<int>(((buffer[0] & 0x03) << 24) |
1133 static_cast<int>(buffer[1]) << 16 |
1134 static_cast<int>(buffer[2]) << 8 |
1135 static_cast<int>(buffer[3]));
1136 return decimal64FromUnpackedSpecial(isNegative, mantissa, exponent);
1137 // RETURN
1138 } break;
1139 case 1: {
1140 int exponent = (buffer[0] >> 7) - 2;
1141 int mantissa = static_cast<int>(buffer[0] & 0x7F);
1142 return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN
1143 } break;
1144#ifdef BSLS_PLATFORM_CMP_IBM
1145 case 5:
1146#else
1147 default:
1148#endif
1149 {
1150 // Xlc optimizes better when 'case 5:' is used instead of 'default:',
1151 // and vice versa for gcc.
1152
1153 bool isNegative = buffer[0] >> 7;
1154 int exponent = ((buffer[0] & 0x7F) >> 2) - 16;
1155 bsls::Types::Uint64 mantissa = static_cast<bsls::Types::Uint64>(
1156 static_cast<bsls::Types::Uint64>(buffer[0] & 0x03) << 32 |
1157 static_cast<bsls::Types::Uint64>(buffer[1]) << 24 |
1158 static_cast<bsls::Types::Uint64>(buffer[2]) << 16 |
1159 static_cast<bsls::Types::Uint64>(buffer[3]) << 8 |
1160 static_cast<bsls::Types::Uint64>(buffer[4]));
1161 return decimal64FromUnpackedSpecial(isNegative, mantissa, exponent);
1162 // RETURN
1163 } break;
1164 }
1165
1166#ifdef BSLS_PLATFORM_CMP_IBM
1167 // From here on, the function has undefined behavior. We will return a
1168 // default constructed value to suppress compiler warnings.
1169 return bdldfp::Decimal64();
1170#endif
1171}
1172
1173inline
1175 unsigned char *buffer,
1176 bdldfp::Decimal64 decimal)
1177{
1178 bool isNegative;
1179 int exponent;
1180 bsls::Types::Uint64 mantissa;
1181
1182 // 'exponent' is biased --> biased exponent = exponent + 398
1183
1185 decimal64ToUnpackedSpecial(&isNegative,
1186 &exponent,
1187 &mantissa,
1188 decimal))) {
1189 if (!isNegative) {
1190 if (396 <= exponent && exponent < 400) {
1191 if (mantissa < (1u << 13)) {
1192
1193 // The predicate disambiguation bit is implicitly 0.
1194
1195 unsigned short squished = static_cast<unsigned short>(
1196 mantissa | (exponent - 396) << 13);
1197
1198 unsigned short squishedN = BSLS_BYTEORDER_HTONS(squished);
1199 bsl::memcpy(buffer, &squishedN, 2);
1200 return buffer + 2; // RETURN
1201 }
1202 }
1203
1204 if (394 <= exponent && exponent < 402) {
1205 if (mantissa < (1u << 19)) {
1206 // On IBM (and Linux to a lesser extent), copying from a
1207 // word-aligned source is faster, so we shift the source of
1208 // memcpy by an extra 8 bits.
1209
1210 unsigned int squished = static_cast<unsigned int>(
1211 (mantissa << 8) | (exponent - 394) << 27);
1212
1213 // The predicate bits should be 0b10.
1214
1215 squished |= 1u << 31;
1216
1217 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
1218
1219 bsl::memcpy(buffer,
1220 reinterpret_cast<unsigned char*>(&squishedN),
1221 3);
1222 return buffer + 3; // RETURN
1223 }
1224 }
1225 }
1226
1227 // If the value is negative, with exponent of 15 (biased exponent 413),
1228 // then the first byte will have a value of FF, which is the state used
1229 // to indicate that a full 9 byte representation should be used.
1230
1231 if (382 <= exponent &&
1232 (exponent < 413 || (!isNegative && exponent == 413))) {
1233 if (mantissa < (1u << 24)) {
1234 unsigned int squished = static_cast<unsigned int>(
1235 mantissa | (exponent - 382) << 24);
1236 if (isNegative) {
1237 squished |= 1u << 29;
1238 }
1239 // The predicate bits should be 11.
1240
1241 squished |= 3u << 30;
1242 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
1243 bsl::memcpy(buffer, &squishedN, 4);
1244 return buffer + 4; // RETURN
1245 }
1246 }
1247 }
1248
1249 *buffer++ = 0xFF;
1250
1251 bsls::Types::Uint64 encoded;
1252 bsl::memcpy(reinterpret_cast<unsigned char *>(&encoded),
1253 decimal.data(),
1254 sizeof(encoded));
1255
1256 encoded = BSLS_BYTEORDER_HTONLL(encoded);
1257
1258 bsl::memcpy(buffer, reinterpret_cast<unsigned char*>(&encoded), 8);
1259
1260 return buffer + 8;
1261}
1262
1263inline
1265 bdldfp::Decimal64 *decimal,
1266 const unsigned char *buffer)
1267{
1268 if (!(*buffer & 0x80)) {
1269
1270 // 2-byte encoding is used.
1271
1272 int exponent = (buffer[0] >> 5) - 2;
1273 int mantissa = static_cast<int>(((buffer[0] & 0x1F) << 8) |
1274 static_cast<int>(buffer[1]));
1275
1276 *decimal = decimal64FromUnpackedSpecial(mantissa, exponent);
1277 return buffer + 2; // RETURN
1278 }
1279 else if ((*buffer & 0xC0) == 0x80) {
1280
1281 // 3-byte encoding is used.
1282
1283 unsigned char eByte1 = buffer[0] & 0x3F;
1284
1285 int exponent = (eByte1 >> 3) - 4;
1286 int mantissa = static_cast<int>(((eByte1 & 0x07) << 16) |
1287 static_cast<int>(buffer[1] << 8) |
1288 static_cast<int>(buffer[2]));
1289 *decimal = decimal64FromUnpackedSpecial(mantissa, exponent);
1290 return buffer + 3; // RETURN
1291 }
1292 else if (*buffer == 0xFF) {
1293
1294 // Full 9-byte encoding is used.
1295 ++buffer;
1296
1297 bsls::Types::Uint64 encoded;
1298 bsl::memcpy(&encoded, buffer, 8);
1299 encoded = BSLS_BYTEORDER_NTOHLL(encoded);
1300
1301 bsl::memcpy(decimal,
1302 reinterpret_cast<unsigned char *>(&encoded),
1303 sizeof(*decimal));
1304
1305 return buffer + 8; // RETURN
1306 }
1307 else {
1308 // Here, the condition ((*buffer & 0xC0) == 0xC0) is true, and so the
1309 // 4-byte encoding is used.
1310
1311 unsigned char eByte1 = buffer[0] & 0x3F;
1312 bool isNegative = eByte1 >> 5;
1313 int exponent = (eByte1 & 0x1F) - 16;
1314 int mantissa =
1315 static_cast<int>(static_cast<int>(buffer[1] << 16) |
1316 static_cast<int>(buffer[2] << 8) |
1317 static_cast<int>(buffer[3]));
1318
1319 *decimal = decimal64FromUnpackedSpecial(isNegative,
1320 mantissa,
1321 exponent);
1322 return buffer + 4; // RETURN
1323 }
1324}
1325
1326 // decimalToDouble functions
1327
1328inline
1330{
1331 return Imp::decimalToDouble(decimal);
1332}
1333
1334inline
1336{
1337 return Imp::decimalToDouble(decimal);
1338}
1339
1340inline
1342{
1343 return Imp::decimalToDouble(decimal);
1344}
1345
1346inline
1348{
1349 return Imp::decimalToDouble(decimal);
1350}
1351
1352inline
1354{
1355 return Imp::decimalToDouble(decimal);
1356}
1357
1358inline
1360{
1361 return Imp::decimalToDouble(decimal);
1362}
1363
1364 // decimalToFloat functions
1365
1366inline
1368{
1369 return Imp::decimalToFloat(decimal);
1370}
1371
1372inline
1374{
1375 return Imp::decimalToFloat(decimal);
1376}
1377
1378inline
1380{
1381 return Imp::decimalToFloat(decimal);
1382}
1383
1384inline
1386{
1387 return Imp::decimalToFloat(decimal);
1388}
1389
1390inline
1392{
1393 return Imp::decimalToFloat(decimal);
1394}
1395
1396inline
1398{
1399 return Imp::decimalToFloat(decimal);
1400}
1401
1402
1403 // decimalToDPD functions
1404
1405inline
1406void DecimalConvertUtil::decimal32ToDPD(unsigned char *buffer,
1407 Decimal32 decimal)
1408{
1409 Imp::decimalToDPD(buffer, decimal);
1410}
1411
1412inline
1413void DecimalConvertUtil::decimal64ToDPD(unsigned char *buffer,
1414 Decimal64 decimal)
1415{
1416 Imp::decimalToDPD(buffer, decimal);
1417}
1418
1419inline
1420void DecimalConvertUtil::decimal128ToDPD(unsigned char *buffer,
1421 Decimal128 decimal)
1422{
1423 Imp::decimalToDPD(buffer, decimal);
1424}
1425
1426inline
1427void DecimalConvertUtil::decimalToDPD(unsigned char *buffer,
1428 Decimal32 decimal)
1429{
1430 Imp::decimalToDPD(buffer, decimal);
1431}
1432
1433inline
1434void DecimalConvertUtil::decimalToDPD(unsigned char *buffer,
1435 Decimal64 decimal)
1436{
1437 Imp::decimalToDPD(buffer, decimal);
1438}
1439
1440inline
1441void DecimalConvertUtil::decimalToDPD(unsigned char *buffer,
1442 Decimal128 decimal)
1443{
1444 Imp::decimalToDPD(buffer, decimal);
1445}
1446
1447 // decimalFromDPD functions
1448
1449inline
1451DecimalConvertUtil::decimal32FromDPD(const unsigned char *buffer)
1452{
1453 return Imp::decimal32FromDPD(buffer);
1454}
1455
1456inline
1457void
1459 const unsigned char *buffer)
1460{
1461 *decimal = Imp::decimal32FromDPD(buffer);
1462}
1463
1464inline
1466DecimalConvertUtil::decimal64FromDPD(const unsigned char *buffer)
1467{
1468 return Imp::decimal64FromDPD(buffer);
1469}
1470
1471inline
1472void
1474 const unsigned char *buffer)
1475{
1476 *decimal = Imp::decimal64FromDPD(buffer);
1477}
1478
1479inline
1481DecimalConvertUtil::decimal128FromDPD(const unsigned char *buffer)
1482{
1483 return Imp::decimal128FromDPD(buffer);
1484}
1485
1486inline
1487void
1489 const unsigned char *buffer)
1490{
1491 *decimal = Imp::decimal128FromDPD(buffer);
1492}
1493
1494inline
1495void
1497 const unsigned char *buffer)
1498{
1499 Imp::decimalFromDPD(decimal, buffer);
1500}
1501
1502inline
1503void
1505 const unsigned char *buffer)
1506{
1507 Imp::decimalFromDPD(decimal, buffer);
1508}
1509
1510inline
1511void
1513 const unsigned char *buffer)
1514{
1515 Imp::decimalFromDPD(decimal, buffer);
1516}
1517
1518
1519 // decimalToBID functions
1520
1521inline
1522void DecimalConvertUtil::decimal32ToBID(unsigned char *buffer,
1523 Decimal32 decimal)
1524{
1525 Imp::decimalToBID(buffer, decimal);
1526}
1527
1528inline
1529void DecimalConvertUtil::decimal64ToBID(unsigned char *buffer,
1530 Decimal64 decimal)
1531{
1532 Imp::decimalToBID(buffer, decimal);
1533}
1534
1535inline
1536void DecimalConvertUtil::decimal128ToBID(unsigned char *buffer,
1537 Decimal128 decimal)
1538{
1539 Imp::decimalToBID(buffer, decimal);
1540}
1541
1542inline
1543void DecimalConvertUtil::decimalToBID(unsigned char *buffer,
1544 Decimal32 decimal)
1545{
1546 Imp::decimalToBID(buffer, decimal);
1547}
1548
1549inline
1550void DecimalConvertUtil::decimalToBID(unsigned char *buffer,
1551 Decimal64 decimal)
1552{
1553 Imp::decimalToBID(buffer, decimal);
1554}
1555
1556inline
1557void DecimalConvertUtil::decimalToBID(unsigned char *buffer,
1558 Decimal128 decimal)
1559{
1560 Imp::decimalToBID(buffer, decimal);
1561}
1562
1563 // decimalFromBID functions
1564
1565inline
1567DecimalConvertUtil::decimal32FromBID(const unsigned char *buffer)
1568{
1569 return Imp::decimal32FromBID(buffer);
1570}
1571
1572inline
1573void
1575 const unsigned char *buffer)
1576{
1577 *decimal = Imp::decimal32FromBID(buffer);
1578}
1579
1580inline
1582DecimalConvertUtil::decimal64FromBID(const unsigned char *buffer)
1583{
1584 return Imp::decimal64FromBID(buffer);
1585}
1586
1587inline
1588void
1590 const unsigned char *buffer)
1591{
1592 *decimal = Imp::decimal64FromBID(buffer);
1593}
1594
1595inline
1597DecimalConvertUtil::decimal128FromBID(const unsigned char *buffer)
1598{
1599 return Imp::decimal128FromBID(buffer);
1600}
1601
1602inline
1603void
1605 const unsigned char *buffer)
1606{
1607 *decimal = Imp::decimal128FromBID(buffer);
1608}
1609
1610inline
1611void
1613 const unsigned char *buffer)
1614{
1615 Imp::decimalFromBID(decimal, buffer);
1616}
1617
1618inline
1619void
1621 const unsigned char *buffer)
1622{
1623 Imp::decimalFromBID(decimal, buffer);
1624}
1625
1626inline
1627void
1629 const unsigned char *buffer)
1630{
1631 Imp::decimalFromBID(decimal, buffer);
1632}
1633
1634} // close package namespace
1635
1636
1637#endif
1638
1639// ----------------------------------------------------------------------------
1640// Copyright 2014 Bloomberg Finance L.P.
1641//
1642// Licensed under the Apache License, Version 2.0 (the "License");
1643// you may not use this file except in compliance with the License.
1644// You may obtain a copy of the License at
1645//
1646// http://www.apache.org/licenses/LICENSE-2.0
1647//
1648// Unless required by applicable law or agreed to in writing, software
1649// distributed under the License is distributed on an "AS IS" BASIS,
1650// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1651// See the License for the specific language governing permissions and
1652// limitations under the License.
1653// ----------------------------- END-OF-FILE ----------------------------------
1654
1655/** @} */
1656/** @} */
1657/** @} */
Imp::ValueType64 ValueType64
Definition bdldfp_decimalimputil.h:250
static ValueType64 makeDecimalRaw64(unsigned long long int significand, int exponent)
Definition bdldfp_decimal.h:3101
Definition bdldfp_decimal.h:765
Definition bdldfp_decimal.h:1890
DecimalImpUtil::ValueType64 * data()
Return a modifiable pointer to the underlying implementation.
Definition bdldfp_decimal.h:6425
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_BYTEORDER_HTONS(x)
Definition bsls_byteorder.h:272
#define BSLS_BYTEORDER_HTONL(x)
Definition bsls_byteorder.h:274
#define BSLS_BYTEORDER_NTOHLL(x)
Definition bsls_byteorder.h:267
#define BSLS_BYTEORDER_HTONLL(x)
Definition bsls_byteorder.h:276
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_PERFORMANCEHINT_PREDICT_LIKELY(expr)
Definition bsls_performancehint.h:451
#define BSLS_PERFORMANCEHINT_UNLIKELY_HINT
Definition bsls_performancehint.h:484
#define BSLS_PERFORMANCEHINT_PREDICT_UNLIKELY(expr)
Definition bsls_performancehint.h:452
Definition bdldfp_decimal.h:747
Decimal_Type64 Decimal64
Definition bdldfp_decimal.h:750
Definition bdldfp_decimalconvertutil.h:397
static const unsigned char * decimal128FromNetwork(Decimal128 *decimal, const unsigned char *buffer)
static Decimal128 decimal128FromFloat(float binary, int digits=0)
static Decimal64 decimal64FromMultiWidthEncoding(const unsigned char *buffer, bsls::Types::size_type size)
Definition bdldfp_decimalconvertutil.h:1065
static float decimalToFloat(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1385
static const unsigned char * decimal64FromVariableWidthEncoding(bdldfp::Decimal64 *decimal, const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1264
static void decimalToDPD(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1427
static Decimal32 decimal32FromBID(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1567
static Decimal64 decimal64FromMultiWidthEncodingRaw(const unsigned char *buffer, bsls::Types::size_type size)
Definition bdldfp_decimalconvertutil.h:1107
static double decimalToDouble(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1347
static unsigned char * decimalToNetwork(unsigned char *buffer, Decimal64 decimal)
static bsls::Types::size_type decimal64ToMultiWidthEncodingRaw(unsigned char *buffer, bdldfp::Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:982
static void decimal64ToBID(unsigned char *buffer, Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1529
static void decimal128ToBID(unsigned char *buffer, Decimal128 decimal)
Definition bdldfp_decimalconvertutil.h:1536
static int decimal64FromMultiWidthEncodingIfValid(Decimal64 *decimal, const unsigned char *buffer, bsls::Types::size_type size)
Definition bdldfp_decimalconvertutil.h:1090
static void decimalFromBID(Decimal32 *decimal, const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1612
static Decimal32 decimal32FromDouble(double binary, int digits=0)
static unsigned char * decimalToNetwork(unsigned char *buffer, Decimal32 decimal)
static const unsigned char * decimal64FromNetwork(Decimal64 *decimal, const unsigned char *buffer)
static Decimal128 decimal128FromDouble(double binary, int digits=0)
static const unsigned char * decimal32FromNetwork(Decimal32 *decimal, const unsigned char *buffer)
static Decimal128 decimal128FromBID(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1597
static unsigned char * decimal32ToNetwork(unsigned char *buffer, Decimal32 decimal)
static Decimal64 decimal64FromFloat(float binary, int digits=0)
static bsls::Types::size_type decimal64ToMultiWidthEncoding(unsigned char *buffer, bdldfp::Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:954
static unsigned char * decimalToNetwork(unsigned char *buffer, Decimal128 decimal)
static void decimal64ToDPD(unsigned char *buffer, Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1413
static Decimal64 decimal64FromDouble(double binary, int digits=0)
static void decimal128ToDPD(unsigned char *buffer, Decimal128 decimal)
Definition bdldfp_decimalconvertutil.h:1420
static float decimal128ToFloat(Decimal128 decimal)
Definition bdldfp_decimalconvertutil.h:1379
static Decimal64 decimal64FromDPD(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1466
static void decimal32ToDPD(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1406
static double decimal32ToDouble(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1329
static const unsigned char * decimalFromNetwork(Decimal32 *decimal, const unsigned char *buffer)
static float decimal32ToFloat(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1367
static const unsigned char * decimalFromNetwork(Decimal128 *decimal, const unsigned char *buffer)
static double decimal64ToDouble(Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1335
static Decimal32 decimal32FromFloat(float binary, int digits=0)
static void decimalFromDPD(Decimal32 *decimal, const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1496
static unsigned char * decimal64ToNetwork(unsigned char *buffer, Decimal64 decimal)
static unsigned char * decimal64ToVariableWidthEncoding(unsigned char *buffer, bdldfp::Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1174
static unsigned char * decimal128ToNetwork(unsigned char *buffer, Decimal128 decimal)
static float decimal64ToFloat(Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1373
static Decimal64 decimal64FromBID(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1582
static Decimal128 decimal128FromDPD(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1481
static const unsigned char * decimalFromNetwork(Decimal64 *decimal, const unsigned char *buffer)
static void decimal32ToBID(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1522
static bool isValidMultiWidthSize(bsls::Types::size_type size)
Definition bdldfp_decimalconvertutil.h:1059
static Decimal32 decimal32FromDPD(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1451
static void decimalToBID(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1543
static double decimal128ToDouble(Decimal128 decimal)
Definition bdldfp_decimalconvertutil.h:1341
static Decimal64 makeDecimalRaw64(int significand, int exponent)
Definition bdldfp_decimalutil.h:856
std::size_t size_type
Definition bsls_types.h:126
unsigned long long Uint64
Definition bsls_types.h:139