=========================================================================== Libdfp The "Decimal Floating Point C Library" User's Guide for the GNU/Linux OS and GLIBC 2.10+ Contributed by IBM Corporation Copyright (C) 2010 - 2014 Free Software Foundation =========================================================================== NOTE:Eight space tabs are the optimum editor setting for reading this file. =========================================================================== Author(s) : Ryan S. Arnold Date Created: January 27, 2010 Last Changed: August 8, 2012 --------------------------------------------------------------------------- Table of Contents: 1. Introduction 1.1. ISO/IEC TR 24732 1.2. ISO/IEC DTR 24733 1.3. IEEE 754-2008 (DPD & BID Encodings) 1.4. Backends (libdecnumber & libbid) 2. Availability 3. Compliance With ISO/IEC TR 24732 3.1 __STDC_DEC_FP__ 3.2 __STDC_WANT_DEC_FP__ 3.3 GNU99 Compatibility 3.4 _Decimal[32|64|128] Data Types 3.4.1 _Decimal[32|64|128] Encoding 3.5 scanf Support 3.6 printf Support 3.5.1 printf "a,A" Conversion Specifier 4. Compliance With ISO/IEC DTR 24733 4.1 C++ decimal[32|64|128] Types Compatibility 4.2 C++ decimal[32|64|128] operator<< and operator>> Support 4.3 Printing decimal[32|64|128] Types and Precision 5. Dependencies 5.1 GNU/Linux OS 5.2 GLIBC Minimum Version 5.3 GCC With --enable-decimal-float Support 6. DFP Headers 7. Compile and Link 8. Unsupported/Non-Standard Additions 9. Known Limitations --------------------------------------------------------------------------- 1. Introduction The "Decimal Floating Point C Library" is an implementation of ISO/IEC Technical report "ISO/IEC TR 24732" which describes the C-Language library routines necessary to provide the C library runtime support for decimal floating point data types introduced in IEEE 754-2008, namely _Decimal32, _Decimal64, and _Decimal128. --------------------------------------------------------------------------- 1.1. ISO/IEC TR 24732 The decimal floating point extension to the C programming language is described in the ratified ISO/IEC Technical Report 24732. The latest description of ISO/IEC TR 24732 at the time of this writing can be found here: http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1312.pdf A rationale can be found here: http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1242.pdf And the last draft for new standard can be found at: http://www.open-std.org/JTC1/SC22/wg14/www/docs/n1775.pdf --------------------------------------------------------------------------- 1.2. ISO/IEC DTR 24733 The decimal floating point extension to the C++ programming language is described in ISO/IEC DRAFT Technical Report 24733. The latest description of ISO/IEC DTR 24733 at the time of this writing can be found here: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2849.pdf --------------------------------------------------------------------------- 1.3. IEEE754-2008 (DPD & BID Encodings) IEEE 754-2008 defines two different encodings for the decimal floating point data types. These are DPD and BID. DPD (Densely Packed Decimal) - IBM sponsored encoding (implemented in hardware). BID (Binary Integer Decimal) - Intel sponsored encoding. A simple explanation of the general overview of Decimal Floaing Point can be found at http://speleotrove.com/decimal/decbits.pdf The BID format encoding general explanation can be found at BID - Binary-Integer Decimal Encoding for Decimal Floating Point | Ping Tak Peter Tang http://m1.archiveorange.com/m/att/KGyKy/ArchiveOrange_Ps0PWkD0ZgCLBVQYnJEcnXblPpEa.pdf Both encodings can be investigated in the draft IEEE754r: http://754r.ucbtest.org/drafts/archive/2006-10-04.pdf --------------------------------------------------------------------------- 1.4. Backends (libdecnumber & libbid) Libdfp use of "libdecnumber" backend library for software emulation. And for the most part, a user of libdfp should not have to be concerned with the libdfp backend. The user's interface is that defined by ISO/IEC TR 24732, i.e. the Decimal Floating Point addition to the C Language specification. --------------------------------------------------------------------------- 2. Availability Libdfp attempts to provide an encoding agnostic API to users based upon the _Decimal32, _Decimal64, and _Decimal128 data-types and the proposed C-Language extension for Decimal Floating Point Types. --------------------------------------------------------------------------- 3. Compliance With ISO/IEC TR 24732 This section covers issues related to compliance with ISO/IEC TR 24732, the ratified ISO C DFP Technical Report. --------------------------------------------------------------------------- 3.1 __STDC_DEC_FP__ The draft standard ISO/IEC TR 24732 specifies the macro __STDC_DEC_FP__ as integer constant 200805L to indicate conformance to the technical report. This macro describes properties of the compiler and library that together satisfy the technical report. The intention is that user applications may check for conformance with the following: #ifdef __STDC_DEC_FP__ /* Select implementation conforming to the TR. */ #else /* Select non-conforming DFP emulation library. */ #endif Since __STDC_DEC_FP__ is a property fulfilled by both the compiler and library the compiler can't predefine this macro without know if the user is using libdfp. There is currently no mechanism for the compiler to determine this early in the translation unit. This will eventually be provided, once a mechanism is added into GLIBC and GCC for identifying stdc predefines as highlighted in this email: http://sourceware.org/ml/libc-alpha/2009-04/msg00005.html At that point libdfp will provide __STDC_DEC_FP__ for GLIBC versions greater than FOO and GCC versions greater than BAR. --------------------------------------------------------------------------- 3.2 __STDC_WANT_DEC_FP__ The standard ISO/IEC TR 24732 indicates that programs that wish to use Decimal Floating Point should define the following macro: __STDC_WANT_DEC_FP__ There is no set value for this macro. Simply passing -D__STDC_WANT_DEC_FP__ on compilation, or defining it in your program should suffice: #define __STDC_WANT_DEC_FP__ This macro is REQUIRED when including dfp/math.h dfp/fenv.h, etc to pick up the DFP function prototypes and data types defined in these headers. --------------------------------------------------------------------------- 3.3 GNU99 Compatibility GNU99 compatibility is required to pick up some DFP prototypes that are similar to the binary floating point prototypes guarded in by __USE_ISOC99 and others. It will define __USE_ISOC99. Use the following compilation flag: -std=gnu99 NOTE: -std=gnu99 IS NOT THE SAME AS __USE_ISOC99 though -std=gnu99 DOES DEFINE __USE_ISOC99! Additionally, simply using -std=c99 isn't enough! NOTE: If you forget to use -std=gnu99 you may notice that you will get very screwy results when you call dfp math functions. If the compiler can't find the prototypes (due to missing defines) it will attempt to create a default prototype which will have an incorrect return type. Compile with -Wall to pick up undefined prototype warnings. --------------------------------------------------------------------------- 3.4 _Decimal* Data Types The Decimal Floating Point data types are as follows: _Decimal32 _Decimal64 _Decimal128 The floating point suffix for DFP constants follows: 'DF' for _Decimal32, e.g. _Decimal32 d32 = 1.045DF; 'DD' for _Decimal64, e.g. _Decimal64 d64 = 1.4738273DD; 'DL' for _Decimal128, e.g. _Decimal128 d128 = 1.0823382394823945DL; NOTE: Assigning a naked constant to a DFP variable will actually be performing a binary to decimal conversion and, depending on the precision, can assign an incorrect number. Always use the decimal floating point suffix, e.g., _Decimal64 d64 = 1.0DD; The following will result in a binary float to decimal float conversion: _Decimal64 d64 = 1.0; --------------------------------------------------------------------------- 3.4.1 _Decimal[32|64|128] Encoding Consider the following _Decimal64 values and encodings (displayed in declet triples): /* Encoded as "+1,000,000,000,000,000e+285" */ _Decimal64 d64 = 1.000000000000000e300DD; /* Encoded as "+0,000,000,000,000,001e+300" */ _Decimal64 e64 = 1e300DD; These values are equivalent in comparison but there is inherently more precision in the first value and this should be preserved when the value is printed. As described in section 3.6.1, the a/A conversion specifier is used to direct printf to use the precision encoded in the actual value for the output string precision. --------------------------------------------------------------------------- 3.5 scanf Support Libdfp does not, and will not comply with the TR 24732 requirement for the addition of scanf in support of decimal floating point data types. The strtod[32|64|128] functions can be used for the same purpose without the implications of scanf. This is main due the fact GLIBC does not support scanf hooks as it does for printf. --------------------------------------------------------------------------- 3.6 printf Support Libdfp supports the addition of the printf format codes indicated by TR 24732. GLIBC proper owns the printf implementation. Libdfp utilizes the printf-hooks mechanism provided by GLIBC to register support of the DFP format codes. The fully functional printf-hooks mechanism was debuted in GLIBC 2.10. Libdfp has a library constructor which registers the Libdfp printf handlers with the libc. If the version of GLIBC that is loaded when your application is executed is too old (pre-2.10) and doesn't have the printf-hooks interface you will get an undefined reference error against GLIBC. When libdfp is loaded printf will recognize the following length modifiers: %H - for _Decimal32 %D - for _Decimal64 %DD - for _Decimal128 It will recognize the following conversion specifier 'spec' characters: e,E f,F g,G a,A (as debuted in ISO/IEC TR 24732) Therefore, any combination of DFP length modifiers and spec characters is supported. 3.6.1 printf "a,A" Conversion Specifier --------------------------------------------------------------------------- The ISO-C DFP specification adds "a/A" as a printf conversion specifier. This conversion specifier is unique in that when it is used the precision of the output string includes as many of the significant digits in the mantissa in the as possible unless there are fewer digits in the mantissa than in the specified precision. Following are some examples to demonstrate the use of the a/A conversion specifier. printf("Result: %.1HaDF\n", 6543.00DF); Result: 7E+3DF printf("Result: %.5HaDF\n", 6543.00DF); Result: 6543.0DF printf("Result: %.4HaDF\n", 6543.00DF); Result: 6543DF /* Example where the implicit number of digits is less than the * explicit precision. */ printf("Result: %.8HaDF\n", 6543.00DF); Result: 6543.00DF If your compiler is being pedantic you may get the following warning (due to -Wformat) when using the a/A conversion specifier with the H/D/DD length modifiers. warning: use of ‘H’ length modifier with ‘A’ type character [-Wformat] This is not a real problem. It simply hints at the issue described in section 3.1. When the compiler and library are able to define __STDC_DEC_FP__ then the compiler can detect that libdfp is available and that a/A conv specifier is a valid combination with the H/D?DD length modifiers. --------------------------------------------------------------------------- 4. Compliance With ISO/IEC DTR 24733 This section covers issues related to compliance with ISO/IEC DTR 24733, the ISO C++ DFP Draft Technical Report. 4.1 C++ decimal[32|64|128] Types Compatibility --------------------------------------------------------------------------- Your C++ compiler may not yet provide the ISO C DFP _Decimal[32|64|128] types. Per the C++ DFP specification: ISO/IEC JTC1 SC22 WG21 N2732 "Extension for the programming language C++ to support decimal floating point arithmetic", the header float.h shall include the following C-compatibility convenience typedefs: typedef std::decimal::decimal32 _Decimal32; typedef std::decimal::decimal64 _Decimal64; typedef std::decimal::decimal128 _Decimal128; This allows C++ programs, which use the native decimal32, decimal64, and decimal128 types to use the _Decimal32, _Decimal64, and_Decimal128 types. Your compiler may or may not yet have this defined in float.h. As a matter of convenience, libdfp has provided these headers in the libdfp headers directory include/dfp/float.h 4.2 C++ decimal[32|64|128] operator<< and operator>> Support --------------------------------------------------------------------------- Your C++ compiler may not provide operator<< and operator>> support for std::decimal::decimal[32|64|128] data types. Per the C++ DFP specification: ISO/IEC JTC1 SC22 WG21 N2732 "Extension for the programming language C++ to support decimal floating point arithmetic", the header shall provide the following operator overloads. namespace std { namespace decimal { template std::basic_istream & operator>>(std::basic_istream & is, decimal32 & d); template std::basic_istream & operator>>(std::basic_istream & is, decimal64 & d); template std::basic_istream & operator>>(std::basic_istream & is, decimal128 & d); template std::basic_ostream & operator<<(std::basic_ostream & os, decimal32 d); template std::basic_ostream & operator<<(std::basic_ostream & os, decimal64 d); template std::basic_ostream & operator<<(std::basic_ostream & os, decimal128 d); }} Per http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51486, since C++ decimal support is defined in a technical report and not ratified into the actual C++ standard the header shouldn't be located in the default headers include directory. As a result the header is located in the include/decimal directory. Therefore, in order to include the decimal header implicitly use the following in applications: #include 4.3 Printing decimal[32|64|128] Types and Precision --------------------------------------------------------------------------- Libdfp provides two mechanisms for printing decimal floating-point data types in string representation. These are via the C++ ostream operator "<<" for decimal[32|64|128] data types and the ISO C printf interface (described in section 3.6) for _Decimal[32|64|128] data types. The ISO C DFP Technical Report provides well described extensions to the printf interface for decimal floating-point types. Unfortunately, the DFP C++ Draft Technical Report simply describes the ostream operator that needs to be provided for string formatting but does not fully describe the procedure for printing full precision decimal types considering the fully encoded precision in decimal types. Please refer to section 3.4.1 for a discussion of the encoding. The base C++ specification describes ostream operator support for floating-point types as equivalent to corresponding ISO C printf conversion specifiers (as described in the following table): C++ ios_base::fmtflags | ISO C printf equivalent conv spec -----------------------------|----------------------------------------- | g ios::fixed | f ios::scientific | e ios::fixed | ios::scientific | a ios::upper | G/F/E/A ios::lower | g/f/e/a Since the DFP C++ Draft Technical Report makes no explicit provisions for format codes specific to decimal floating-point types the Libdfp implementation falls back on the equivalency to printf conversion specifiers described in this table. Under binary floating-point the a/A spec is used to print hexadecimal representation of floating point values, which is why no precision is allowed to convert (truncate and round) the output string representation. The C++ specification indicates that a/A is specified by passing ios::fixed | ios::scientific in the ios_base::fmtflags for the stream. When this combination of flags is specified the precision set in the ostream (whether the default or user specified) is not honored or used in the printing of the type. As described in section 3.5.1, the overridden a/A conversion specifier is the most desireable conversion specifier used with printf for decimal floating-point types since it preserves the encoded precision in the output string representation by default (when no explicit precision is specified). Since there is no interface specified in the DFP C or C++ specifications for querying the number of significant digits in a decimal floating-point value the user should most often use the a/A conversion specifier in order to preserve significant digits. The caveat, of course, is that since the C++ specification does not provide a way to programmatically determine whether the queried stream precision is the default of '6', or a value set by the user, nor does the C++ specification allow stream precision to be considered when printing the a/A style conversion, this ostream operator implementation can not pass the stream precision on to the printf function. Therefore, all use of (ios::fixed | ios::scientific) will result in full precision output and it will not honor the output precision specified in the stream. --------------------------------------------------------------------------- 5. Dependencies --------------------------------------------------------------------------- 5.1 GNU/Linux OS Libdfp is only enabled to work on the GNU/Linux OS. --------------------------------------------------------------------------- 5.2 GLIBC Minimum Version Libdfp version 1.0.0 relies upon a minimum GLIBC 2.10 for printf-hooks support. The libdfp configure stage will check the libc that it is linked against for the printf-hook support and will warn if it is not found. --------------------------------------------------------------------------- 5.3 GCC With --enable-decimal-float Support There's a dependency on a version of GCC which supports Decimal Floating Point. Use the following to determine if your compiler supports it: gcc -v 2>&1 | grep "\-\-enable\-decimal\-float" If decimal floating point support is not available in your compiler the libdfp configure stage will fail with a warning. --------------------------------------------------------------------------- 6. DFP Headers The following Libdfp headers extend the existing system headers. If the path to the Libdfp headers is included in the search path then these will be picked up prior to the system headers. dfp/fenv.h dfp/math.h dfp/stdlib.h dfp/wchar.h dfp/float.h dfp/decimal/decimal Each of these headers uses the GCC construct #include_next in order to pick up the system header as well, e.g., dfp/math.h will #include_next dfp/decimal/decimal will #include_next This mechanism allows Libdfp to add the Decimal interfaces required by the specification to the aforementioned headers. In order to pick up the Libdfp prototypes and classification macro overrides compile with the following: -I/pathto/include/dfp/ -D__STDC_WANT_DEC_FP__=1 Using -I instead of -isystem is suggested because -I indicates that the specified headers are picked up BEFORE the system headers, which is what we want. Then in the application source simply using the following include will pick up both /pathto/include/dfp/.h and /usr/include/.h: #include #include #include #include /* And for C++ programs */ #include #include Due to the use of #include_next in the DFP headers (in order to wrap the default system headers with DFP prototypes) the methodology of including "dfp/" in the include path, and then excluding -I/pathto/include/dfp/ is NOT supported. DO NOT DO THE FOLLOWING: #include #include #include #include #include #include --------------------------------------------------------------------------- 7. Compile and Link A compilation and link for a DFP program will look like the following: $(CC) -Wall test_dfp.c -o test_dfp -D__STDC_WANT_DEC_FP__ \ -std=gnu99 -ldfp --------------------------------------------------------------------------- 8. Unsupported/Non-Standard Additions Libdfp provides a non-standard method for output of the decoded Densely Packed Decimal representation using the decoded[32|64|128]() functions. The output format is: [sign][MSD],[decoded-declet-1], ...,[decoded-declet-n][E][+|-][decoded exponent] Examples: +0,000,000E+0 = decoded32(0DF) +0,000,000,000,001,000E-1 = decoded64(100.0DD) -0,000,000,000,000,000,000,000,000,039,654,003E-3 = decoded128(-39654.003DL) +9,876,543E+22 = decoded32(9.876543E+28DF) WARNING: Do NOT rely on these methods for user space code. They're only provided for toolchain development debug support. A header file providing the prototype for these functions is not provided by the Advance Toolchain to discourage you from using them. If you MUST use them define the following prototypes in your program: /* char * should ref a 14 byte char array, * +0,000,000E+0\0 */ extern char * decoded32 (_Decimal32, char*); /* char * should ref a 26 byte char array, * +0,000,000,000,000,000E+0\0 */ extern char * decoded64 (_Decimal64, char*); /* char * should ref a 50 byte char array, * +0,000,000,000,000,000,000,000,000,000,000,000E+0\0 */ extern char * decoded128 (_Decimal128, char*); --------------------------------------------------------------------------- 9. Known Limitations IEEE754r currently has an addendum awaiting vote whereby the default quantum for conversions involving zero will go to a zero exponent (e.g. 0 equals 0.0). The current IEEE754r specification dictates that the quantum shall go to the largest supported by the data type, e.g. _Decimal32 0.0E191; _Decimal64 0.0E767, _Decimal128 0.0E12287. Observation of the advance toolchain results will show that we don't follow any particular convention. This may change in the future. For the following examples notice the DPD encoding on both power6[x] and non-power6: _Decimal32 d32 = 0.0DF; _Decimal64 d64 = 0.0DD; _Decimal128 d128 = 0.0DL; (_Decimal128)0.0DF: [+0,000,000E+0] (_Decimal128)0.0DD: [+0,000,000,000,000,000E+0] (_Decimal128)0.0DL: [+0,000,000,000,000,000,000,000,000,000,000,000E+0] On power6[x] notice the representation of zero after an [int|long|long long] conversion to _Decimal[32|64|128] respectively: (_Decimal32)0DF = (int)0: [+0,000,000E+0] (_Decimal32)0.0DF = (float)0.000000: [+0,000,000E+0] (_Decimal64)0DD = (long)0: [+0,000,000,000,000,000E+0] (_Decimal64)0.0DD = (double)0.000000: [+0,000,000,000,000,000E+0] (_Decimal128)0DL = (long long)0: [+0,000,000,000,000,000,000,000,000,000,000,000E+0] (_Decimal128)0.0DL = (long double)0.000000: [+0,000,000,000,000,000,000,000,000,000,000,000E+0] Notice the difference with soft-dfp: (_Decimal32)0.0DF = (int)0: [+0,000,000E-1] (_Decimal32)0.0DF = (float)0.000000: [+0,000,000E+0] (_Decimal64)0.0DD = (long)0: [+0,000,000,000,000,000E-1] (_Decimal64)0.0DD = (double)0.000000: [+0,000,000,000,000,000E+0] (_Decimal128)0.0DL = (long long)0: [+0,000,000,000,000,000,000,000,000,000,000,000E-1] (_Decimal128)0.0DL = (long double)0.000000: [+0,000,000,000,000,000,000,000,000,000,000,000E+0] Namely the negative sign of the exponent with soft-dfp for int to _Decimal conversions.