BDE 4.14.0 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.
396
397 private:
398 // PRIVATE TYPES
399#if defined(BDLDFP_DECIMALPLATFORM_INTELDFP)
400 typedef DecimalConvertUtil_IntelDfp Imp;
401#else
402 BDLDFP_DECIMALPLATFORM_COMPILER_ERROR;
403#endif
404
405 // PRIVATE CLASS DATA
406
407 // 'bid64' REPRESENTATION CONSTANTS
408
409 static const int k_EXPONENT_SHIFT_SMALL64 = 53; // exponent position
410 static const int k_EXPONENT_MASK64 = 0x3ff; // exponent mask bits
411 static const unsigned long long k_SPECIAL_ENCODING_MASK64 =
412 0x6000000000000000ull; // special when non-zero
413 static const unsigned long long k_SMALL_COEFF_MASK64 =
414 0x001fffffffffffffull; // mask for mantissa
415
416 // PRIVATE CLASS METHODS
417
418 /// If the specified `value` is NaN, +infinity, -infinity, or its
419 /// unbiased exponent is 384, return a non-zero value and leave all
420 /// output parameters unmodified. Otherwise, partition the `value` into
421 /// sign, biased exponent, and mantissa compartments, and load the
422 /// corresponding values into the specified `isNegative`,
423 /// `biasedExponent`, and `mantissa`. Return 0. Note that a non-zero
424 /// value does not indicate that `value` can not be partitioned, just
425 /// that it can not be partitioned by this function. Also note that the
426 /// bias for `Decimal64` is 398.
427 static int decimal64ToUnpackedSpecial(bool *isNegative,
428 int *biasedExponent,
429 bsls::Types::Uint64 *mantissa,
430 bdldfp::Decimal64 value);
431
432 /// Return a `Decimal64` object that has the specified `mantissa`,
433 /// `exponent`, and a sign based on the specified `isNegative`. The
434 /// behavior is undefined unless `isNegative`, `mantissa`, and the
435 /// biased exponent were originally obtained from
436 /// `decimal64ToUnpackedSpecial`. Note that `exponent` should be
437 /// unbiased, so 398 should be subtracted from the biased exponent
438 /// gotten from `decimal64ToUnpackedSpecial`.
439 static bdldfp::Decimal64 decimal64FromUnpackedSpecial(
440 bool isNegative,
441 bsls::Types::Uint64 mantissa,
442 int exponent);
443
444
445 /// Return a `Decimal64` object that has the specified `mantissa`,
446 /// `exponent`. The behavior is undefined unless `isNegative`,
447 /// `mantissa`, and the biased exponent were originally obtained from
448 /// `decimal64ToUnpackedSpecial`. Note that `exponent` should be
449 /// unbiased, so 398 should be subtracted from the biased exponent
450 /// gotten from `decimal64ToUnpackedSpecial`.
451 static bdldfp::Decimal64 decimal64FromUnpackedSpecial(int mantissa,
452 int exponent);
453
454 public:
455 // CLASS METHODS
456
457 // decimalToDouble functions
458
459 static double decimal32ToDouble (Decimal32 decimal);
460 static double decimal64ToDouble (Decimal64 decimal);
461
462 /// [**DEPRECATED**] Use `deciamalToDouble` instead.
463 static double decimal128ToDouble(Decimal128 decimal);
464
465 /// Return a `double` object having the value closest to the value of
466 /// the specified `decimal` object following the conversion rules
467 /// defined by IEEE-754:
468 ///
469 static double decimalToDouble (Decimal32 decimal);
470 static double decimalToDouble (Decimal64 decimal);
471 /// * If the `decimal` object is a NaN, return a NaN.
472 /// * Otherwise if `decimal` is positive or negative infinity, return
473 /// infinity of the same sign.
474 /// * Otherwise if `decimal` is positive or negative zero, return zero
475 /// of the same sign.
476 /// * Otherwise if `decimal` object has an absolute value that is
477 /// larger than `std::numeric_limits<double>::max()`, raise the
478 /// "overflow" floating-point exception and return infinity of the
479 /// same sign as `decimal`.
480 /// * Otherwise if `decimal` has an absolute value that is smaller than
481 /// `std::numeric_limits<double>::min()`, raise the "underflow"
482 /// floating-point exception and return zero of the same sign as
483 /// `decimal`.
484 /// * Otherwise if `decimal` has a value that has more significant
485 /// base-10 digits than `std::numeric_limits<double>::digits10`,
486 /// raise the "inexact" floating-point exception, round that value
487 /// according to the *binary* rounding direction setting of the
488 /// floating-point environment, and return the result of that.
489 /// * Otherwise if `decimal` has a significand that cannot be exactly
490 /// represented using binary floating-point, raise the "inexact"
491 /// floating-point exception, round that value according to the
492 /// *binary* rounding direction setting of the environment, and
493 /// return the result of that.
494 /// * Otherwise use the exact value of the `other` object for the
495 /// initialization if this object.
496 static double decimalToDouble (Decimal128 decimal);
497
498 // decimalToFloat functions
499
500 static float decimal32ToFloat (Decimal32 decimal);
501 static float decimal64ToFloat (Decimal64 decimal);
502
503 /// [**DEPRECATED**] Use `deciamalToFloat` instead.
504 static float decimal128ToFloat(Decimal128 decimal);
505
506 /// Return a `float` object having the value closest to the value of the
507 /// specified `decimal` object following the conversion rules defined
508 /// by IEEE-754:
509 ///
510 static float decimalToFloat (Decimal32 decimal);
511 static float decimalToFloat (Decimal64 decimal);
512 /// * If the `decimal` object is a NaN, return a NaN.
513 /// * Otherwise if `decimal` is positive or negative infinity, return
514 /// infinity of the same sign.
515 /// * Otherwise if `decimal` is positive or negative zero, return zero
516 /// of the same sign.
517 /// * Otherwise if `decimal` object has an absolute value that is
518 /// larger than `std::numeric_limits<long double>::max()`, raise the
519 /// "overflow" floating-point exception and return infinity of the
520 /// same sign as `decimal`.
521 /// * Otherwise if `decimal` has an absolute value that is smaller than
522 /// `std::numeric_limits<float>::min()`, raise the "underflow"
523 /// floating-point exception and return zero of the same sign as
524 /// `decimal`.
525 /// * Otherwise if `decimal` has a value that has more significant
526 /// base-10 digits than `std::numeric_limits<float>::digits10`,
527 /// raise the "inexact" floating-point exception, round that value
528 /// according to the *binary* rounding direction setting of the
529 /// floating-point environment, and return the result of that.
530 /// * Otherwise if `decimal` has a significand that cannot be exactly
531 /// represented using binary floating-point, raise the "inexact"
532 /// floating-point exception, round that value according to the
533 /// *binary* rounding direction setting of the environment, and
534 /// return the result of that.
535 /// * Otherwise use the exact value of the `other` object for the
536 /// initialization if this object.
537 static float decimalToFloat (Decimal128 decimal);
538
539 // decimalFromDouble functions
540
541 static Decimal32 decimal32FromDouble (double binary, int digits = 0);
542 static Decimal32 decimal32FromFloat (float binary, int digits = 0);
543 static Decimal64 decimal64FromDouble (double binary, int digits = 0);
544 static Decimal64 decimal64FromFloat (float binary, int digits = 0);
545 static Decimal128 decimal128FromDouble(double binary, int digits = 0);
546
547 /// Return a decimal floating-point number converted from the specified
548 /// `binary`.
549 ///
550 /// If `binary` is singular (+/-NaN, +/-Inf, or +/-0) or is not within
551 /// the representable range of the return type, return a corresponding
552 /// decimal singular value.
553 ///
554 /// Optionally specify `digits` to indicate the number of significant
555 /// digits to produce in the returned value. The `digits` parameter is
556 /// treated as follows:
557 ///
558 /// If `digits` is larger than the number of digits in the destination
559 /// type, it will be reduced to that number of digits.
560 ///
561 /// If `digits` is positive, the result is `binary` rounded to that many
562 /// significant digits.
563 ///
564 /// If `digits` is negative, the decimal value with the fewest
565 /// significant digits that converts back to `binary` is returned if
566 /// possible, and otherwise the value closest to `binary` is returned.
567 /// Note that this provides the most visually appealing result but is
568 /// the most expensive to compute.
569 ///
570 /// If `digits` is not specified or 0, a default value will be used
571 /// (possibly depending on the value of `binary`) based on the premise
572 /// that `binary` is a converted decimal value of no more significant
573 /// digits than is guaranteed to have a uniquely converted binary value
574 /// (15 for `double`, 6 for `float` in general, and 7 for `float` in the
575 /// range `[ .0009999995 .. 8589972000 ]`). Note that this is likely to
576 /// have the best performance for "business" numbers (i.e., numbers that
577 /// originate as decimal values in external market quote feeds).
578 ///
579 /// Note that the purpose of these functions is to restore a decimal
580 /// value that has been converted to a binary floating-point type. It
581 /// is more efficient to use conversion constructors when all that is
582 /// needed is the nearest decimal to the `binary` value.
583 ///
584 /// Note that if `binary` is a `float` value that was converted from an
585 /// IBM/Perkin-Elmer/Interdata binary `float` value itself converted
586 /// from a decimal value of no more than 6 significant digits,
587 /// specifying 6 for `digits` will recover the original decimal value.
588 /// Not specifying `digits` may result in a value having a spurious
589 /// seventh digit.
590 static Decimal128 decimal128FromFloat (float binary, int digits = 0);
591
592 // decimalToDPD functions
593
594 static void decimal32ToDPD (unsigned char *buffer,
595 Decimal32 decimal);
596 static void decimal64ToDPD (unsigned char *buffer,
597 Decimal64 decimal);
598 static void decimal128ToDPD(unsigned char *buffer,
599 Decimal128 decimal);
600
601 static void decimalToDPD (unsigned char *buffer,
602 Decimal32 decimal);
603 static void decimalToDPD (unsigned char *buffer,
604 Decimal64 decimal);
605 /// Populate the specified `buffer` with the Densely Packed Decimal
606 /// (DPD) representation of the specified `decimal` value. The DPD
607 /// representations of `Decimal32`, `Decimal64`, and `Decimal128`
608 /// require 4, 8, and 16 bytes respectively. The behavior is undefined
609 /// unless `buffer` points to a contiguous sequence of at least
610 /// `sizeof(decimal)` bytes. Note that the DPD representation is
611 /// defined in section 3.5 of IEEE 754-2008.
612 static void decimalToDPD (unsigned char *buffer,
613 Decimal128 decimal);
614
615 // decimalFromDPD functions
616
617 static Decimal32 decimal32FromDPD (const unsigned char *buffer);
618 static Decimal64 decimal64FromDPD (const unsigned char *buffer);
619
620 static Decimal128 decimal128FromDPD(const unsigned char *buffer);
621
622 static void decimal32FromDPD (Decimal32 *decimal,
623 const unsigned char *buffer);
624 static void decimal64FromDPD (Decimal64 *decimal,
625 const unsigned char *buffer);
626 /// Return the native implementation representation of the value of the
627 /// same size base-10 floating-point value stored in Densely Packed
628 /// Decimal format at the specified `buffer` address. The behavior is
629 /// undefined unless `buffer` points to a memory area at least
630 /// `sizeof(decimal)` in size containing a value in DPD format.
631 static void decimal128FromDPD(Decimal128 *decimal,
632 const unsigned char *buffer);
633
634 static void decimalFromDPD (Decimal32 *decimal,
635 const unsigned char *buffer);
636 static void decimalFromDPD (Decimal64 *decimal,
637 const unsigned char *buffer);
638 /// Store, into the specified `decimal`, the native implementation
639 /// representation of the value of the same size base-10 floating point
640 /// value represented in Densely Packed Decimal format, at the specified
641 /// `buffer` address. The behavior is undefined unless `buffer` points
642 /// to a memory area at least `sizeof(decimal)` in size containing a
643 /// value in DPD format.
644 static void decimalFromDPD (Decimal128 *decimal,
645 const unsigned char *buffer);
646
647 // decimalToBID functions
648
649 static void decimal32ToBID (unsigned char *buffer,
650 Decimal32 decimal);
651 static void decimal64ToBID (unsigned char *buffer,
652 Decimal64 decimal);
653 static void decimal128ToBID(unsigned char *buffer,
654 Decimal128 decimal);
655
656 static void decimalToBID (unsigned char *buffer,
657 Decimal32 decimal);
658 static void decimalToBID (unsigned char *buffer,
659 Decimal64 decimal);
660 /// Populate the specified `buffer` with the Binary Integer Decimal
661 /// (BID) representation of the specified `decimal` value. The BID
662 /// representations of `Decimal32`, `Decimal64`, and `Decimal128`
663 /// require 4, 8, and 16 bytes respectively. The behavior is undefined
664 /// unless `buffer` points to a contiguous sequence of at least
665 /// `sizeof(decimal)` bytes. Note that the BID representation is
666 /// defined in section 3.5 of IEEE 754-2008.
667 static void decimalToBID (unsigned char *buffer,
668 Decimal128 decimal);
669
670 // decimalFromBID functions
671
672 static Decimal32 decimal32FromBID (const unsigned char *buffer);
673 static Decimal64 decimal64FromBID (const unsigned char *buffer);
674
675 static Decimal128 decimal128FromBID(const unsigned char *buffer);
676
677 static void decimal32FromBID (Decimal32 *decimal,
678 const unsigned char *buffer);
679 static void decimal64FromBID (Decimal64 *decimal,
680 const unsigned char *buffer);
681 /// Return the native implementation representation of the value of the
682 /// same size base-10 floating-point value stored in Binary Integer
683 /// Decimal format at the specified `buffer` address. The behavior is
684 /// undefined unless `buffer` points to a memory area at least
685 /// `sizeof(decimal)` in size containing a value in BID format.
686 static void decimal128FromBID(Decimal128 *decimal,
687 const unsigned char *buffer);
688
689 static void decimalFromBID (Decimal32 *decimal,
690 const unsigned char *buffer);
691 static void decimalFromBID (Decimal64 *decimal,
692 const unsigned char *buffer);
693 /// Store, into the specified `decimal`, the native implementation
694 /// representation of the value of the same size base-10 floating point
695 /// value represented in Binary Integer Decimal format, at the specified
696 /// `buffer` address. The behavior is undefined unless `buffer` points
697 /// to a memory area at least `sizeof(decimal)` in size containing a
698 /// value in BID format.
699 static void decimalFromBID (Decimal128 *decimal,
700 const unsigned char *buffer);
701
702 // decimalToNetwork functions
703
704 static unsigned char *decimal32ToNetwork (unsigned char *buffer,
705 Decimal32 decimal);
706 static unsigned char *decimal64ToNetwork (unsigned char *buffer,
707 Decimal64 decimal);
708 static unsigned char *decimal128ToNetwork(unsigned char *buffer,
709 Decimal128 decimal);
710
711 /// Store the specified `decimal`, in network format, into the specified
712 /// `buffer` and return the address one past the last byte written into
713 /// the `buffer`. The network format is defined as big endian byte
714 /// order and densely packed base-10 significand encoding. This
715 /// corresponds to the way IBM hardware represents these numbers in
716 /// memory. The behavior is undefined unless `buffer` points to a
717 /// memory area at least `sizeof(decimal)` in size. Note that these
718 /// functions always return `buffer + sizeof(decimal)` on the supported
719 /// 8-bits-byte architectures.
720 static unsigned char *decimalToNetwork (unsigned char *buffer,
721 Decimal32 decimal);
722 static unsigned char *decimalToNetwork (unsigned char *buffer,
723 Decimal64 decimal);
724 static unsigned char *decimalToNetwork (unsigned char *buffer,
725 Decimal128 decimal);
726
727 // decimalFromNetwork functions
728
729 static const unsigned char *decimal32FromNetwork(
730 Decimal32 *decimal,
731 const unsigned char *buffer);
732 static const unsigned char *decimal64FromNetwork(
733 Decimal64 *decimal,
734 const unsigned char *buffer);
735 static const unsigned char *decimal128FromNetwork(
736 Decimal128 *decimal,
737 const unsigned char *buffer);
738
739 /// Store into the specified `decimal`, the value of the same size
740 /// base-10 floating-point value stored in network format at the
741 /// specified `buffer` address and return the address one past the last
742 /// byte read from `buffer`. The network format is defined as big
743 /// endian byte order and densely packed base-10 significand encoding.
744 /// This corresponds to the way IBM hardware represents these numbers in
745 /// memory. The behavior is undefined unless `buffer` points to a
746 /// memory area at least `sizeof(decimal)` bytes. Note that these
747 /// functions always return `buffer + sizeof(decimal)` on the supported
748 /// 8-bits-byte architectures.
749 static const unsigned char *decimalFromNetwork(
750 Decimal32 *decimal,
751 const unsigned char *buffer);
752 static const unsigned char *decimalFromNetwork(
753 Decimal64 *decimal,
754 const unsigned char *buffer);
755 static const unsigned char *decimalFromNetwork(
756 Decimal128 *decimal,
757 const unsigned char *buffer);
758
759 /// Store the specified `decimal`, in the *multi-width encoding* format,
760 /// into the specified `buffer` and return the number of bytes used by
761 /// the encoding. The behavior is undefined unless `buffer` points to a
762 /// memory area with enough room to hold the encode value (which has a
763 /// maximum size of 8 bytes).
765 unsigned char *buffer,
766 bdldfp::Decimal64 decimal);
767
768 /// If the specified `decimal` can be encoded in 5 or fewer bytes of the
769 /// *multi-width encoding* format, then store `decimal` into the
770 /// specified `buffer` in that format, and return the number of bytes
771 /// written to `buffer`. Otherwise, return 0. The behavior is
772 /// undefined unless `buffer` points to a memory area having at least 5
773 /// bytes. Note that this function does not supporting encoding values
774 /// requiring a full IEEE network encoding, which is supported by the
775 /// `decimal64ToMultiWidthEncoding` function.
777 unsigned char *buffer,
778 bdldfp::Decimal64 decimal);
779
780 /// Decode a decimal value in the *multi-width encoding* format from the
781 /// specified `buffer` having the specified `size`. Return the decoded
782 /// value. The behavior is undefined unless `buffer` has at least
783 /// `size` bytes, `size` is a valid encoding size in the
784 /// `multi-width encoding` format, and `size <= 5`. Note that this
785 /// function does not support decoding values requiring a full IEEE
786 /// network encoding, which is supported by the
787 /// `decimal64FromMultiWidthEncoding` function.
789 const unsigned char *buffer,
791
792 /// Return `true` if the specified `size` is a valid encoding size in
793 /// the *multi-width encoding* format, and `false` otherwise. Note that
794 /// valid encoding sizes are 1, 2, 3, 4, 5 and 8 bytes.
796
797 /// Decode a decimal value in the *multi-width encoding* format from the
798 /// specified `buffer` having the specified `size`. Return the decoded
799 /// value. The behavior is undefined unless `buffer` has at least
800 /// `size` bytes, and `size` is a valid encoding size in the
801 /// `multi-width encoding` format.
803 const unsigned char *buffer,
805
806 /// Decode a decimal value in the *multi-width encoding* format from the
807 /// specified `buffer` having the specified `size` and store the result
808 /// into the specified `decimal` parameter. Return 0 on success, and
809 /// non-zero value otherwise. The behavior is undefined unless `buffer`
810 /// has at least `size` bytes. Note that this function returns a
811 /// non-zero value and leaves `decimal` unchanged if `size` is not a
812 /// valid encoding size of the *multi-width encoding* format.
814 Decimal64 *decimal,
815 const unsigned char *buffer,
817
818 /// Store the specified `decimal`, in the *variable-width encoding*
819 /// format, into the specified `buffer` and return the address one past
820 /// the last byte written into the `buffer`. The behavior is undefined
821 /// unless `buffer` points to a memory area with enough room to hold the
822 /// encoded value (which has a maximum size of 9 bytes).
823 static unsigned char *decimal64ToVariableWidthEncoding(
824 unsigned char *buffer,
825 bdldfp::Decimal64 decimal);
826
827 /// Store into the specified `decimal`, the value of `Decimal64` value
828 /// stored in the *variable-width encoding* format at the specified
829 /// `buffer` address. Return the address one past the last byte read
830 /// from `buffer`. The behavior is undefined unless `buffer` points to
831 /// a memory area holding a `Decimal64` value encoded in the
832 /// *variable-width encoding* format.
833 static const unsigned char *decimal64FromVariableWidthEncoding(
834 bdldfp::Decimal64 *decimal,
835 const unsigned char *buffer);
836};
837
838// ============================================================================
839// INLINE DEFINITIONS
840// ============================================================================
841
842
843// PRIVATE CLASS METHODS
844
845inline
846int DecimalConvertUtil::decimal64ToUnpackedSpecial(
847 bool *isNegative,
848 int *biasedExponent,
849 bsls::Types::Uint64 *mantissa,
850 bdldfp::Decimal64 value)
851{
852#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
853 bsls::Types::Uint64 bidValue = value.data()->d_raw;
854#else
855 bsls::Types::Uint64 bidValue = bid_dpd_to_bid64(
856 static_cast<bsls::Types::Uint64>(*(value.data())));
857#endif
858 // This class method is based on inteldfp 'unpack_BID64' (bid_internal.h),
859 // with a non-zero return if 'SPECIAL_ENCODING_MASK64' indicates a special
860 // encoding; these are practically non-existent and no need to optimize.
861
863 (bidValue & k_SPECIAL_ENCODING_MASK64) == k_SPECIAL_ENCODING_MASK64)) {
865 // punt on special encodings
866 return -1; // RETURN
867 }
868
869 *isNegative = (bidValue & 0x8000000000000000ull) ? 1 : 0;
870
871 *biasedExponent = static_cast<int>(
872 (bidValue >> k_EXPONENT_SHIFT_SMALL64) & k_EXPONENT_MASK64);
873
874 *mantissa = bidValue & k_SMALL_COEFF_MASK64;
875
876 return 0;
877}
878
879inline
880Decimal64 DecimalConvertUtil::decimal64FromUnpackedSpecial(
881 bool isNegative,
882 bsls::Types::Uint64 mantissa,
883 int exponent)
884{
885#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
886 bdldfp::Decimal64 result;
887 result.data()->d_raw = (isNegative ? 0x8000000000000000ull : 0) |
888 (static_cast<BID_UINT64>(exponent + 398)
889 << k_EXPONENT_SHIFT_SMALL64) |
890 mantissa;
891 return result;
892#else
893 if (isNegative) {
895 -static_cast<long long>(mantissa),
896 exponent);
897 } else {
898 return DecimalImpUtil::makeDecimalRaw64(mantissa, exponent);
899 }
900#endif
901}
902
903inline
904Decimal64 DecimalConvertUtil::decimal64FromUnpackedSpecial(int mantissa,
905 int exponent)
906{
907#ifdef BDLDFP_DECIMALPLATFORM_INTELDFP
908 bdldfp::Decimal64 result;
909 result.data()->d_raw = (static_cast<BID_UINT64>(exponent + 398)
910 << k_EXPONENT_SHIFT_SMALL64) |
911 mantissa;
912 return result;
913#else
914 return DecimalUtil::makeDecimalRaw64(mantissa, exponent);
915#endif
916}
917
918// CLASS METHODS
919inline
921 unsigned char *buffer,
922 bdldfp::Decimal64 decimal)
923{
924
926 decimal);
927
929 return size; // RETURN
930 }
931 else {
933 bsls::Types::Uint64 encoded;
934 bsl::memcpy(reinterpret_cast<unsigned char *>(&encoded),
935 decimal.data(),
936 sizeof(encoded));
937
938 encoded = BSLS_BYTEORDER_HTONLL(encoded);
939
940 bsl::memcpy(buffer,
941 reinterpret_cast<unsigned char*>(&encoded),
942 8);
943 return 8; // RETURN
944 }
945}
946
947inline
949 unsigned char *buffer,
950 bdldfp::Decimal64 decimal)
951{
952 bool isNegative;
953 int exponent;
954 bsls::Types::Uint64 mantissa;
955
956 // 'exponent' is biased --> biased exponent = exponent + 398
957
959 decimal64ToUnpackedSpecial(&isNegative,
960 &exponent,
961 &mantissa,
962 decimal))) {
963 if (!isNegative) {
964 if (395 <= exponent && exponent < 399) {
965 if (mantissa < (1u << 14)) {
966 unsigned short squished = static_cast<unsigned short>(
967 mantissa | (exponent - 395) << 14);
968
969 unsigned short squishedN = BSLS_BYTEORDER_HTONS(squished);
970 bsl::memcpy(buffer, &squishedN, 2);
971 return 2; // RETURN
972 }
973 }
974 if (392 <= exponent && exponent < 400) {
975 if (mantissa < (1u << 21)) {
976 // On IBM (and Linux to a lesser extent), copying from a
977 // word-aligned source is faster, so we shift an extra the
978 // source by an extra 8 bits.
979
980 unsigned int squished = static_cast<unsigned int>(
981 (mantissa << 8) | (exponent - 392) << 29);
982 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
983
984 bsl::memcpy(buffer,
985 reinterpret_cast<unsigned char*>(&squishedN),
986 3);
987 return 3; // RETURN
988 }
989 }
990 }
991
992 if (382 <= exponent && exponent < 414) {
993 if (mantissa < (1u << 26)) {
994 unsigned int squished = static_cast<unsigned int>(
995 mantissa | (exponent - 382) << 26);
996 if (isNegative) {
997 squished |= 1u << 31;
998 }
999 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
1000 bsl::memcpy(buffer, &squishedN, 4);
1001 return 4; // RETURN
1002 }
1003 if (mantissa < (1ull << 34)) {
1004 bsls::Types::Uint64 squished =
1005 static_cast<bsls::Types::Uint64>(
1006 (mantissa << 24) |
1007 (static_cast<bsls::Types::Uint64>(exponent - 382) << 58));
1008 if (isNegative) {
1009 squished |= 1ull << 63;
1010 }
1011 bsls::Types::Uint64 squishedN =
1012 BSLS_BYTEORDER_HTONLL(squished);
1013 bsl::memcpy(buffer,
1014 reinterpret_cast<unsigned char*>(&squishedN),
1015 5);
1016 return 5; // RETURN
1017 }
1018 }
1019 }
1020
1021 return 0;
1022}
1023
1024inline
1026{
1027 return (size > 0 && size <= 5) || size == 8;
1028}
1029
1030inline
1032 const unsigned char *buffer,
1034{
1035 BSLS_ASSERT(1 <= size);
1036 BSLS_ASSERT(size <= 5 || size == 8);
1037
1039 return decimal64FromMultiWidthEncodingRaw(buffer, size); // RETURN
1040 }
1041 else {
1043
1044 bsls::Types::Uint64 encoded;
1045 bsl::memcpy(&encoded, buffer, 8);
1046 encoded = BSLS_BYTEORDER_NTOHLL(encoded);
1047
1049 bsl::memcpy(&decimal, &encoded, sizeof(decimal));
1050
1051 return decimal; // RETURN
1052 }
1053}
1054
1055inline
1057 Decimal64 *decimal,
1058 const unsigned char *buffer,
1060{
1061 int ret(0);
1062
1063 if (isValidMultiWidthSize(size)) {
1064 *decimal = decimal64FromMultiWidthEncoding(buffer, size);
1065 }
1066 else {
1067 ret = 1;
1068 }
1069 return ret;
1070}
1071
1072inline
1074 const unsigned char *buffer,
1076{
1077 BSLS_ASSERT(1 <= size);
1078 BSLS_ASSERT(size <= 5);
1079
1080 switch(size) {
1081 case 2: {
1082 int exponent = (buffer[0] >> 6) - 3;
1083 int mantissa = static_cast<int>(((buffer[0] & 0x3F) << 8) |
1084 static_cast<int>(buffer[1]));
1085
1086 return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN
1087 } break;
1088 case 3: {
1089 int exponent = (buffer[0] >> 5) - 6;
1090 int mantissa = static_cast<int>(((buffer[0] & 0x1F) << 16) |
1091 static_cast<int>(buffer[1]) << 8 |
1092 static_cast<int>(buffer[2]));
1093 return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN
1094 } break;
1095 case 4: {
1096 bool isNegative = buffer[0] >> 7;
1097 int exponent = ((buffer[0] & 0x7F) >> 2) - 16;
1098 int mantissa = static_cast<int>(((buffer[0] & 0x03) << 24) |
1099 static_cast<int>(buffer[1]) << 16 |
1100 static_cast<int>(buffer[2]) << 8 |
1101 static_cast<int>(buffer[3]));
1102 return decimal64FromUnpackedSpecial(isNegative, mantissa, exponent);
1103 // RETURN
1104 } break;
1105 case 1: {
1106 int exponent = (buffer[0] >> 7) - 2;
1107 int mantissa = static_cast<int>(buffer[0] & 0x7F);
1108 return decimal64FromUnpackedSpecial(mantissa, exponent); // RETURN
1109 } break;
1110#ifdef BSLS_PLATFORM_CMP_IBM
1111 case 5:
1112#else
1113 default:
1114#endif
1115 {
1116 // Xlc optimizes better when 'case 5:' is used instead of 'default:',
1117 // and vice versa for gcc.
1118
1119 bool isNegative = buffer[0] >> 7;
1120 int exponent = ((buffer[0] & 0x7F) >> 2) - 16;
1121 bsls::Types::Uint64 mantissa = static_cast<bsls::Types::Uint64>(
1122 static_cast<bsls::Types::Uint64>(buffer[0] & 0x03) << 32 |
1123 static_cast<bsls::Types::Uint64>(buffer[1]) << 24 |
1124 static_cast<bsls::Types::Uint64>(buffer[2]) << 16 |
1125 static_cast<bsls::Types::Uint64>(buffer[3]) << 8 |
1126 static_cast<bsls::Types::Uint64>(buffer[4]));
1127 return decimal64FromUnpackedSpecial(isNegative, mantissa, exponent);
1128 // RETURN
1129 } break;
1130 }
1131
1132#ifdef BSLS_PLATFORM_CMP_IBM
1133 // From here on, the function has undefined behavior. We will return a
1134 // default constructed value to suppress compiler warnings.
1135 return bdldfp::Decimal64();
1136#endif
1137}
1138
1139inline
1141 unsigned char *buffer,
1142 bdldfp::Decimal64 decimal)
1143{
1144 bool isNegative;
1145 int exponent;
1146 bsls::Types::Uint64 mantissa;
1147
1148 // 'exponent' is biased --> biased exponent = exponent + 398
1149
1151 decimal64ToUnpackedSpecial(&isNegative,
1152 &exponent,
1153 &mantissa,
1154 decimal))) {
1155 if (!isNegative) {
1156 if (396 <= exponent && exponent < 400) {
1157 if (mantissa < (1u << 13)) {
1158
1159 // The predicate disambiguation bit is implicitly 0.
1160
1161 unsigned short squished = static_cast<unsigned short>(
1162 mantissa | (exponent - 396) << 13);
1163
1164 unsigned short squishedN = BSLS_BYTEORDER_HTONS(squished);
1165 bsl::memcpy(buffer, &squishedN, 2);
1166 return buffer + 2; // RETURN
1167 }
1168 }
1169
1170 if (394 <= exponent && exponent < 402) {
1171 if (mantissa < (1u << 19)) {
1172 // On IBM (and Linux to a lesser extent), copying from a
1173 // word-aligned source is faster, so we shift the source of
1174 // memcpy by an extra 8 bits.
1175
1176 unsigned int squished = static_cast<unsigned int>(
1177 (mantissa << 8) | (exponent - 394) << 27);
1178
1179 // The predicate bits should be 0b10.
1180
1181 squished |= 1u << 31;
1182
1183 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
1184
1185 bsl::memcpy(buffer,
1186 reinterpret_cast<unsigned char*>(&squishedN),
1187 3);
1188 return buffer + 3; // RETURN
1189 }
1190 }
1191 }
1192
1193 // If the value is negative, with exponent of 15 (biased exponent 413),
1194 // then the first byte will have a value of FF, which is the state used
1195 // to indicate that a full 9 byte representation should be used.
1196
1197 if (382 <= exponent &&
1198 (exponent < 413 || (!isNegative && exponent == 413))) {
1199 if (mantissa < (1u << 24)) {
1200 unsigned int squished = static_cast<unsigned int>(
1201 mantissa | (exponent - 382) << 24);
1202 if (isNegative) {
1203 squished |= 1u << 29;
1204 }
1205 // The predicate bits should be 11.
1206
1207 squished |= 3u << 30;
1208 unsigned int squishedN = BSLS_BYTEORDER_HTONL(squished);
1209 bsl::memcpy(buffer, &squishedN, 4);
1210 return buffer + 4; // RETURN
1211 }
1212 }
1213 }
1214
1215 *buffer++ = 0xFF;
1216
1217 bsls::Types::Uint64 encoded;
1218 bsl::memcpy(reinterpret_cast<unsigned char *>(&encoded),
1219 decimal.data(),
1220 sizeof(encoded));
1221
1222 encoded = BSLS_BYTEORDER_HTONLL(encoded);
1223
1224 bsl::memcpy(buffer, reinterpret_cast<unsigned char*>(&encoded), 8);
1225
1226 return buffer + 8;
1227}
1228
1229inline
1231 bdldfp::Decimal64 *decimal,
1232 const unsigned char *buffer)
1233{
1234 if (!(*buffer & 0x80)) {
1235
1236 // 2-byte encoding is used.
1237
1238 int exponent = (buffer[0] >> 5) - 2;
1239 int mantissa = static_cast<int>(((buffer[0] & 0x1F) << 8) |
1240 static_cast<int>(buffer[1]));
1241
1242 *decimal = decimal64FromUnpackedSpecial(mantissa, exponent);
1243 return buffer + 2; // RETURN
1244 }
1245 else if ((*buffer & 0xC0) == 0x80) {
1246
1247 // 3-byte encoding is used.
1248
1249 unsigned char eByte1 = buffer[0] & 0x3F;
1250
1251 int exponent = (eByte1 >> 3) - 4;
1252 int mantissa = static_cast<int>(((eByte1 & 0x07) << 16) |
1253 static_cast<int>(buffer[1] << 8) |
1254 static_cast<int>(buffer[2]));
1255 *decimal = decimal64FromUnpackedSpecial(mantissa, exponent);
1256 return buffer + 3; // RETURN
1257 }
1258 else if (*buffer == 0xFF) {
1259
1260 // Full 9-byte encoding is used.
1261 ++buffer;
1262
1263 bsls::Types::Uint64 encoded;
1264 bsl::memcpy(&encoded, buffer, 8);
1265 encoded = BSLS_BYTEORDER_NTOHLL(encoded);
1266
1267 bsl::memcpy(decimal,
1268 reinterpret_cast<unsigned char *>(&encoded),
1269 sizeof(*decimal));
1270
1271 return buffer + 8; // RETURN
1272 }
1273 else {
1274 // Here, the condition ((*buffer & 0xC0) == 0xC0) is true, and so the
1275 // 4-byte encoding is used.
1276
1277 unsigned char eByte1 = buffer[0] & 0x3F;
1278 bool isNegative = eByte1 >> 5;
1279 int exponent = (eByte1 & 0x1F) - 16;
1280 int mantissa =
1281 static_cast<int>(static_cast<int>(buffer[1] << 16) |
1282 static_cast<int>(buffer[2] << 8) |
1283 static_cast<int>(buffer[3]));
1284
1285 *decimal = decimal64FromUnpackedSpecial(isNegative,
1286 mantissa,
1287 exponent);
1288 return buffer + 4; // RETURN
1289 }
1290}
1291
1292 // decimalToDouble functions
1293
1294inline
1296{
1297 return Imp::decimalToDouble(decimal);
1298}
1299
1300inline
1302{
1303 return Imp::decimalToDouble(decimal);
1304}
1305
1306inline
1308{
1309 return Imp::decimalToDouble(decimal);
1310}
1311
1312inline
1314{
1315 return Imp::decimalToDouble(decimal);
1316}
1317
1318inline
1320{
1321 return Imp::decimalToDouble(decimal);
1322}
1323
1324inline
1326{
1327 return Imp::decimalToDouble(decimal);
1328}
1329
1330 // decimalToFloat functions
1331
1332inline
1334{
1335 return Imp::decimalToFloat(decimal);
1336}
1337
1338inline
1340{
1341 return Imp::decimalToFloat(decimal);
1342}
1343
1344inline
1346{
1347 return Imp::decimalToFloat(decimal);
1348}
1349
1350inline
1352{
1353 return Imp::decimalToFloat(decimal);
1354}
1355
1356inline
1358{
1359 return Imp::decimalToFloat(decimal);
1360}
1361
1362inline
1364{
1365 return Imp::decimalToFloat(decimal);
1366}
1367
1368
1369 // decimalToDPD functions
1370
1371inline
1372void DecimalConvertUtil::decimal32ToDPD(unsigned char *buffer,
1373 Decimal32 decimal)
1374{
1375 Imp::decimalToDPD(buffer, decimal);
1376}
1377
1378inline
1379void DecimalConvertUtil::decimal64ToDPD(unsigned char *buffer,
1380 Decimal64 decimal)
1381{
1382 Imp::decimalToDPD(buffer, decimal);
1383}
1384
1385inline
1386void DecimalConvertUtil::decimal128ToDPD(unsigned char *buffer,
1387 Decimal128 decimal)
1388{
1389 Imp::decimalToDPD(buffer, decimal);
1390}
1391
1392inline
1393void DecimalConvertUtil::decimalToDPD(unsigned char *buffer,
1394 Decimal32 decimal)
1395{
1396 Imp::decimalToDPD(buffer, decimal);
1397}
1398
1399inline
1400void DecimalConvertUtil::decimalToDPD(unsigned char *buffer,
1401 Decimal64 decimal)
1402{
1403 Imp::decimalToDPD(buffer, decimal);
1404}
1405
1406inline
1407void DecimalConvertUtil::decimalToDPD(unsigned char *buffer,
1408 Decimal128 decimal)
1409{
1410 Imp::decimalToDPD(buffer, decimal);
1411}
1412
1413 // decimalFromDPD functions
1414
1415inline
1417DecimalConvertUtil::decimal32FromDPD(const unsigned char *buffer)
1418{
1419 return Imp::decimal32FromDPD(buffer);
1420}
1421
1422inline
1423void
1425 const unsigned char *buffer)
1426{
1427 *decimal = Imp::decimal32FromDPD(buffer);
1428}
1429
1430inline
1432DecimalConvertUtil::decimal64FromDPD(const unsigned char *buffer)
1433{
1434 return Imp::decimal64FromDPD(buffer);
1435}
1436
1437inline
1438void
1440 const unsigned char *buffer)
1441{
1442 *decimal = Imp::decimal64FromDPD(buffer);
1443}
1444
1445inline
1447DecimalConvertUtil::decimal128FromDPD(const unsigned char *buffer)
1448{
1449 return Imp::decimal128FromDPD(buffer);
1450}
1451
1452inline
1453void
1455 const unsigned char *buffer)
1456{
1457 *decimal = Imp::decimal128FromDPD(buffer);
1458}
1459
1460inline
1461void
1463 const unsigned char *buffer)
1464{
1465 Imp::decimalFromDPD(decimal, buffer);
1466}
1467
1468inline
1469void
1471 const unsigned char *buffer)
1472{
1473 Imp::decimalFromDPD(decimal, buffer);
1474}
1475
1476inline
1477void
1479 const unsigned char *buffer)
1480{
1481 Imp::decimalFromDPD(decimal, buffer);
1482}
1483
1484
1485 // decimalToBID functions
1486
1487inline
1488void DecimalConvertUtil::decimal32ToBID(unsigned char *buffer,
1489 Decimal32 decimal)
1490{
1491 Imp::decimalToBID(buffer, decimal);
1492}
1493
1494inline
1495void DecimalConvertUtil::decimal64ToBID(unsigned char *buffer,
1496 Decimal64 decimal)
1497{
1498 Imp::decimalToBID(buffer, decimal);
1499}
1500
1501inline
1502void DecimalConvertUtil::decimal128ToBID(unsigned char *buffer,
1503 Decimal128 decimal)
1504{
1505 Imp::decimalToBID(buffer, decimal);
1506}
1507
1508inline
1509void DecimalConvertUtil::decimalToBID(unsigned char *buffer,
1510 Decimal32 decimal)
1511{
1512 Imp::decimalToBID(buffer, decimal);
1513}
1514
1515inline
1516void DecimalConvertUtil::decimalToBID(unsigned char *buffer,
1517 Decimal64 decimal)
1518{
1519 Imp::decimalToBID(buffer, decimal);
1520}
1521
1522inline
1523void DecimalConvertUtil::decimalToBID(unsigned char *buffer,
1524 Decimal128 decimal)
1525{
1526 Imp::decimalToBID(buffer, decimal);
1527}
1528
1529 // decimalFromBID functions
1530
1531inline
1533DecimalConvertUtil::decimal32FromBID(const unsigned char *buffer)
1534{
1535 return Imp::decimal32FromBID(buffer);
1536}
1537
1538inline
1539void
1541 const unsigned char *buffer)
1542{
1543 *decimal = Imp::decimal32FromBID(buffer);
1544}
1545
1546inline
1548DecimalConvertUtil::decimal64FromBID(const unsigned char *buffer)
1549{
1550 return Imp::decimal64FromBID(buffer);
1551}
1552
1553inline
1554void
1556 const unsigned char *buffer)
1557{
1558 *decimal = Imp::decimal64FromBID(buffer);
1559}
1560
1561inline
1563DecimalConvertUtil::decimal128FromBID(const unsigned char *buffer)
1564{
1565 return Imp::decimal128FromBID(buffer);
1566}
1567
1568inline
1569void
1571 const unsigned char *buffer)
1572{
1573 *decimal = Imp::decimal128FromBID(buffer);
1574}
1575
1576inline
1577void
1579 const unsigned char *buffer)
1580{
1581 Imp::decimalFromBID(decimal, buffer);
1582}
1583
1584inline
1585void
1587 const unsigned char *buffer)
1588{
1589 Imp::decimalFromBID(decimal, buffer);
1590}
1591
1592inline
1593void
1595 const unsigned char *buffer)
1596{
1597 Imp::decimalFromBID(decimal, buffer);
1598}
1599
1600} // close package namespace
1601
1602
1603#endif
1604
1605// ----------------------------------------------------------------------------
1606// Copyright 2014 Bloomberg Finance L.P.
1607//
1608// Licensed under the Apache License, Version 2.0 (the "License");
1609// you may not use this file except in compliance with the License.
1610// You may obtain a copy of the License at
1611//
1612// http://www.apache.org/licenses/LICENSE-2.0
1613//
1614// Unless required by applicable law or agreed to in writing, software
1615// distributed under the License is distributed on an "AS IS" BASIS,
1616// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1617// See the License for the specific language governing permissions and
1618// limitations under the License.
1619// ----------------------------- END-OF-FILE ----------------------------------
1620
1621/** @} */
1622/** @} */
1623/** @} */
Imp::ValueType64 ValueType64
Definition bdldfp_decimalimputil.h:250
static ValueType64 makeDecimalRaw64(unsigned long long int significand, int exponent)
Definition bdldfp_decimal.h:3023
Definition bdldfp_decimal.h:730
Definition bdldfp_decimal.h:1834
DecimalImpUtil::ValueType64 * data()
Return a modifiable pointer to the underlying implementation.
Definition bdldfp_decimal.h:6063
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#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)
Definition bsls_ident.h:195
#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:712
Decimal_Type64 Decimal64
Definition bdldfp_decimal.h:715
Definition bdldfp_decimalconvertutil.h:395
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:1031
static float decimalToFloat(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1351
static const unsigned char * decimal64FromVariableWidthEncoding(bdldfp::Decimal64 *decimal, const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1230
static void decimalToDPD(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1393
static Decimal32 decimal32FromBID(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1533
static Decimal64 decimal64FromMultiWidthEncodingRaw(const unsigned char *buffer, bsls::Types::size_type size)
Definition bdldfp_decimalconvertutil.h:1073
static double decimalToDouble(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1313
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:948
static void decimal64ToBID(unsigned char *buffer, Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1495
static void decimal128ToBID(unsigned char *buffer, Decimal128 decimal)
Definition bdldfp_decimalconvertutil.h:1502
static int decimal64FromMultiWidthEncodingIfValid(Decimal64 *decimal, const unsigned char *buffer, bsls::Types::size_type size)
Definition bdldfp_decimalconvertutil.h:1056
static void decimalFromBID(Decimal32 *decimal, const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1578
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:1563
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:920
static unsigned char * decimalToNetwork(unsigned char *buffer, Decimal128 decimal)
static void decimal64ToDPD(unsigned char *buffer, Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1379
static Decimal64 decimal64FromDouble(double binary, int digits=0)
static void decimal128ToDPD(unsigned char *buffer, Decimal128 decimal)
Definition bdldfp_decimalconvertutil.h:1386
static float decimal128ToFloat(Decimal128 decimal)
[DEPRECATED] Use deciamalToFloat instead.
Definition bdldfp_decimalconvertutil.h:1345
static Decimal64 decimal64FromDPD(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1432
static void decimal32ToDPD(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1372
static double decimal32ToDouble(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1295
static const unsigned char * decimalFromNetwork(Decimal32 *decimal, const unsigned char *buffer)
static float decimal32ToFloat(Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1333
static const unsigned char * decimalFromNetwork(Decimal128 *decimal, const unsigned char *buffer)
static double decimal64ToDouble(Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1301
static Decimal32 decimal32FromFloat(float binary, int digits=0)
static void decimalFromDPD(Decimal32 *decimal, const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1462
static unsigned char * decimal64ToNetwork(unsigned char *buffer, Decimal64 decimal)
static unsigned char * decimal64ToVariableWidthEncoding(unsigned char *buffer, bdldfp::Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1140
static unsigned char * decimal128ToNetwork(unsigned char *buffer, Decimal128 decimal)
static float decimal64ToFloat(Decimal64 decimal)
Definition bdldfp_decimalconvertutil.h:1339
static Decimal64 decimal64FromBID(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1548
static Decimal128 decimal128FromDPD(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1447
static const unsigned char * decimalFromNetwork(Decimal64 *decimal, const unsigned char *buffer)
static void decimal32ToBID(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1488
static bool isValidMultiWidthSize(bsls::Types::size_type size)
Definition bdldfp_decimalconvertutil.h:1025
static Decimal32 decimal32FromDPD(const unsigned char *buffer)
Definition bdldfp_decimalconvertutil.h:1417
static void decimalToBID(unsigned char *buffer, Decimal32 decimal)
Definition bdldfp_decimalconvertutil.h:1509
static double decimal128ToDouble(Decimal128 decimal)
[DEPRECATED] Use deciamalToDouble instead.
Definition bdldfp_decimalconvertutil.h:1307
static Decimal64 makeDecimalRaw64(int significand, int exponent)
Definition bdldfp_decimalutil.h:839
std::size_t size_type
Definition bsls_types.h:124
unsigned long long Uint64
Definition bsls_types.h:137