The DFPAL Library, version 2.20
© Copyright IBM Corporation, 2007. All rights reserved.

Decimal Floating Point Abstraction Layer (DFPAL)


User's guide

This document describes Decimal Floating Point Abstraction Layer (DFPAL) implementation. DFPAL is a module written in C programming language. DFPAL detects availability of operating system and hardware support for the decimal floating point at runtime. If such support is available, it automatically branches into the hardware path and utilizes hardware for the decimal floating point arithmetic. On other hand, if operating system or hardware does not support decimal floating point (on POWER5++ or other processor architecture, for example) DFPAL branches into the software path and uses the decNumber module. The decNumber arithmetic module is software implementation of the decimal floating point arithmetic.

Source code for DFPAL is available from International Components for Unicode (ICU) DFPAL package.

Contents:


Overview

Most processors support binary floating point in hardware. However, binary floating point is not suitable for financial or human-centric applications. An alternative to binary floating point is decimal floating point arithmetic. Unlike binary floating point arithmetic, the decimal floating point performs arithmetic in base 10 to provide better accuracy. Further details about decimal arithmetic can be found at General Decimal Arithmetic. The IBM POWER6 processor implements decimal floating point arithmetic in hardware. Programming language decimal floating point support is enabled by IBM XLC C/C++ compiler version 9 release.

It will not be possible for many software vendors to migrate their build environment to the new compiler version required to utilize hardware decimal floating point. Typically, the compiler migration is not a trivial task due to regression, incompatibility and other concerns, furthermore it requires significant amount of resources and efforts. Additionally, such application will not be compatible and portable across platforms or compilers who do not support the decimal floating point feature. An application compiled with POWER6 as a target platform will not function on pre-POWER6 architectures (e.g. POWER5 family of processors) due to newer decimal floating point instructions available only with the POWER6 processor.

Decimal Floating Point Abstraction Layer (DFPAL) addresses these issues. DFPAL allows applications to run virtually on any platform and still provides hardware acceleration on the POWER6 processor. DFPAL provides the following features:


DFPAL examples

Simple addition

      1 #include <stdio.h>          // printf() etc.
      2 #include <stdlib.h>         // malloc()/free()
      3 
      4 #include "dfpal.h"          // DFPAL API
      5 
      6 int main(int argc, char **argv)
      7 {
      8 decimal64 n1, n2, n3;       // 64-bit work numbers
      9 decimal128 N1, N2, N3;      // 128-bit work numbers
     10 char dfpstr[64];            // buffer for 'to string' conversion
     11 int initErr, initOSErr;     // DFPAL initialization error place-holder
     12 char *errStr=NULL;          // ...
     13 
     14   if (argc < 3) {
     15     printf("Please supply two numbers to add.\n");
     16     return(1);
     17   }
     18 
     19   // initialize and check error; free memory if unsuccessful
     20   if (dfpalInit((void *)malloc(dfpalMemSize())) != DFPAL_ERR_NO_ERROR) {
     21     dfpalGetError(&initErr, &initOSErr, &errStr);
     22     fprintf(stderr, "DFPAL Init error number:%d, error: %s\n",
     23       initErr, errStr);
     24     dfpalEnd(free);
     25     return(1);
     26   }
     27 
     28   // what version?
     29   printf("Version of DFPAL: %s\n", dfpalVersion());
     30 
     31   // Is it running in software or hardware?
     32   if (dfpalGetExeMode()!=PPCHW)
     33     printf("DFPAL is operating in software\n");
     34   else
     35     printf("DFPAL is operating in hardware\n");
     36 
     37   // convert input strings to decimal64 format
     38   n1=dec64FromString(argv[1]);
     39   n2=dec64FromString(argv[2]);
     40 
     41   // add
     42   n3 = dec64Add(n1,n2);
     43   printf("n1 + n2 = %s\n", dec64ToString(n3, dfpstr));
     44 
     45   // convert decimal64 to decimal128
     46   N1=dec128FromDecimal64(n1); // N1=(decimal128)n1
     47   N2=dec128FromDecimal64(n2); // N2=(decimal128)n2
     48   N3 = dec128Add(N1,N2);
     49   printf("N1 + N2 = %s\n", dec128ToString(N3, dfpstr));
     50 
     51   dfpalEnd(free);  // cleanup; free memory used by DFPAL
     52
     53   return(0);
     54 }


Line #: 4
     Include required header file dfpal.h.

Line #: 8-9
     Declare decimal floating point datatype work variables to hold 64-bit and 128-bit decimal floating point numbers. Application is required to use decimal64 and decimal128 names to avoid name collision with compiler native decimal floating point data type names.

Line #: 20
     Initialize DFPAL using dfpalInit(). This example uses memory allocated using malloc() facility. Application can use its own memory allocation routine.

Line #: 21
     Retrieve some information about the error.

Line #: 22-23
     Print error.

Line #: 24
     Call dfpalEnd() to cleanup and free memory.

Line #: 29
     Check DFPAL version.

Line #: 32-35
     Find out whether DFPAL is operating in hardware or software.

Line #: 38-39
     Convert input string to decimal64 format.

Line #: 42-43
     Perform add operation on decimal64 data type, print result using dec64ToString().

Line #: 46-47
     Typecast decimal64 values to decimal128 type (type conversion).

Line #: 48-49
     Perform add operation on decimal128 data types, print result using dec128ToString().

Line #: 51
     Call dfpalEnd() to cleanup and free memory.




Decimal floating point exception status

      1 #include <stdio.h>          // printf() etc.
      2 #include <stdlib.h>         // malloc()/free()
      3 
      4 #include "dfpal.h"          // DFPAL API
      5 
      6 #define PRINT_EXCEPTIONS(where, st) {                                      \
      7   printf(#where "\n");                                                     \
      8   printf("INVALID  OVERFLOW   UNDERFLOW  DIV_BY_ZERO  INEXACT\n");         \
      9   printf("   %1d        %1d           %1d           %1d          %1d\n",   \
     10     ((st)&DFPAL_FP_INVALID)?1:0, ((st)&DFPAL_FP_OVERFLOW)?1:0,             \
     11     ((st)&DFPAL_FP_UNDERFLOW)?1:0, ((st)&DFPAL_FP_DIV_BY_ZERO)?1:0,        \
     12     ((st)&DFPAL_FP_INEXACT)?1:0);                                          \
     13 }
     14 
     15 
     16 int main(int argc, char **argv)
     17 {
     18 decimal64 n1, n2, n3, n4;   // 64-bit work numbers
     19 decimal128 N1, N2, N3, N4;  // 128-bit work numbers
     20 char dfpstr[64];            // buffer for 'to string' conversion
     21 int initErr, initOSErr;     // DFPAL initialization error place-holder
     22 char *errStr=NULL;          // ...
     23 dfpalflag_t xstatus;
     24 
     25   // initialize and check error; free memory if unsuccessful
     26   if (dfpalInit((void *)malloc(dfpalMemSize())) != DFPAL_ERR_NO_ERROR) {
     27     dfpalGetError(&initErr, &initOSErr, &errStr);
     28     fprintf(stderr, "DFPAL Init error number:%d, error: %s\n",
     29       initErr, errStr);
     30     dfpalEnd(free);
     31     return(1);
     32   }
     33 
     34   dfpalClearStatusFlag(DFPAL_FP_ALL);
     35 
     36   // create some number to play with
     37   n1=dec64FromString("9E+200");
     38   n2=dec64FromString("9E-200");
     39   N1=dec128FromString("9E+3200");
     40   N2=dec128FromString("9E-3200");
     41   // did anything go wrong in string conversion?
     42   if ((xstatus=dfpalReadStatusFlag()) & DFPAL_FP_ALL)
     43     PRINT_EXCEPTIONS(String Conversion, xstatus);
     44 
     45   // multiplication: this should cause overflow and inexact
     46   n3=dec64Multiply(n1,n1);
     47   printf("n1 * n2 = %s\n", dec64ToString(n3, dfpstr));
     48   // overflow and inexact should be present
     49   if ((xstatus=dfpalReadStatusFlag()) & DFPAL_FP_ALL)
     50     PRINT_EXCEPTIONS(decimal64 multiply, xstatus);
     51 
     52   // division: this should cause divide by zero
     53   N3=dec128Divide(N1, dec128Zero());
     54   printf("N1 / 0 = %s\n", dec128ToString(N3, dfpstr));
     55   // overflow, inexact, divide by zero should be present
     56   if ((xstatus=dfpalReadStatusFlag()) & DFPAL_FP_ALL)
     57     PRINT_EXCEPTIONS(decimal64 multiply, xstatus);
     58 
     59   // division: this should cause underflow and inexact
     60   N3=dec128Divide(N2,N1);
     61   printf("N1 / N2 = %s\n", dec128ToString(N3, dfpstr));
     62   // overflow, inexact, underflow, divide by zero should be present
     63   if ((xstatus=dfpalReadStatusFlag()) & DFPAL_FP_ALL)
     64     PRINT_EXCEPTIONS(decimal128 divide, xstatus);
     65 
     66   // divide Inf/Inf: should cause invalid
     67   n3=dec64Divide(n3, n3);
     68   printf("Inf / Inf = %s\n", dec64ToString(n3, dfpstr));
     69   // overflow, inexact, underflow, divide by zero, invalid  should be present
     70   if ((xstatus=dfpalReadStatusFlag()) & DFPAL_FP_ALL)
     71     PRINT_EXCEPTIONS(decimal64 divide, xstatus);
     72 
     73   dfpalEnd(free);  // cleanup; free memory used by DFPAL
     74
     75   return(0);
     76 }


Line #: 6-13
     Define helper macro to print floating point exception. In reality, application typically takes some corrective action when floating point exception(s) are encountered.

Line #: 34
     Clear all floating point exception status at beginning.

Line #: 37-41
     Create some numbers from strings.

Line #: 42-43
     Check if string conversion caused any floating point exception. There should not be any.

Line #: 46-50
     Multiply operation to induce INEXACT and OVERFLOW floating point exceptions. Retrieve and print floating point exception flags.

Line #: 53-57
     Divide operation to induce DIVIDE_BY_ZERO floating point exception. Retrieve and print floating point exception flags. At this time, all three floating point exceptions occurred so far should appear in the output.

Line #: 60-64
     Divide operation to induce UNDERFLOW and INEXACT floating point exceptions. Retrieve and print floating point exception flags. At this time, all four floating point exceptions occurred so far should appear in the output.

Line #: 67-71
     Divide operation using Infinity value for both operands to induce INVALID floating point exception.


DFPAL source layout

DFPAL source code is organized into following files.

dfpal.c Main source file; the only C source file.
asmdfp.S POWER6 decimal floating point insturction assembly language code snippets for Linux on Power, for use with GCC compiler on Linux on Power.
dfpal.h DFPAL API specification header file. Applications are required to include this header file into their C source file(s).
dfpalct.h DFPAL context data structure. DFPAL context is persistent data to hold DFPAL runtime state (e.g. exception status, traps, rounding mode etc.). The context data is divided into two parts. A process-wide context (common to all threads) and thread-specific context. This header is not seen by the application.
dfpaltypes.h DFPAL specific data type definitions. This header is used to achieve portability.
ppcdfp.h POWER PC machine instructions for DFP arithmetic. Contains XLC #pragma mc_func macros for in-place instruction expansion. This header is not seen by the application.
asmdfp.h Function prototype decleration corresponding to asmdfp.S snippets. This header is not seen by the application.
dfpstub.h Stub code for POWER PC machine instructions. The stub is used when DFPAL is compiled with no hardware decimal floating point support (using DFPAL_NO_HW_DFP). This header is not seen by the application.
dfpalerr.h DFPAL error codes and error messages. The error codes and error messages are separated to assist national language support (NLS) message catalog.


How to compile DFPAL?

DFPAL is successfully compiled with a variety of compilers on multiple platforms. DFPAL portability is enabled by a combination of coding style and compile time switches. Build instructions (Makefile), for various environments, are included in the package. Follow instructions in the makefile carefully, especially on AIX (e.g. -qlongdouble flag must be used with XLC on AIX) and Linux on Power (e.g. -mlong-double-128 flag must be used with GCC on Linux on Power). DFPAL can be compiled as a standalone library or can be integrated into the application itself.

decNumber tuning

Beginning decNumber version 3.40, the DECENDIAN setting (in decNumberLocal.h) has been removed to improve performance; instead, you must set the DECLITEND parameter to 1 if compiling for a little-endian target (for example, AMD and Intel x86), or to 0 if compiling for a big-endian (IBM POWER processor) target.

The decNumber package included in the DFPAL package has DECLITEND value set to 0. Additionally, respective Makefiles set DECLITEND to appropriate value on compiler command line.

Compile time switches

DFPAL_THREAD_SAFE Activate thread local storage for DFPAL context. This switch must be specified on all platforms to enable multi-threading support. Non multi-threaded application may get marginal performance benefit by not defining this switch. Absence of this switch bypasses a thread local storage.
DFPAL_OS_AIX5L
DFPAL_OS_LOP
DFPAL_OS_WINDOWS
Specify target platform using one of these switches. Using DFPAL_OS_AIX5L implies detecting and activating hardware decimal floating point with AIX on POWER6. Such code will run on any level of supported AIX operating system with any supported POWER processor. On pre-POWER6 processors, DFPAL will utilize decNumber for the decimal floating point arithmetic.

Using DFPAL_OS_LOP implies detecting and activating hardware decimal floating point for Linux on Power platform, running on POWER6. Such code will run on any level of supported Linux on Power distribution, with any supported POWER processor. On pre-POWER6 processors, DFPAL will utilize decNumber for the decimal floating point arithmetic. Both IBM XLC and GCC compilers are supported.

Use DFPAL_OS_WINDOWS to compile on Microsoft Windows using Microsoft compiler. Windows has a different thread local storage model than POSIX (on Unix or Linux) thread local storage model.

DFPAL_USE_INTTYPES_H DFPAL_LOCAL_INTTYPES For C99 data types, some platform have inttypes.h, whereas others have stdint.h (e.g. AIX, Linux). Windows does not have either. Select appropriate switch for your platform. For Windows use DFPAL_LOCAL_INTTYPES switch. If your build environment does not work with any of these, create and edit a file with stdint.h name and define appropriate data types.
DFPAL_INTEGER64_LITERAL_LL DFPAL_INTEGER64_LITERAL_L DFPAL_INTEGER64_LITERAL_i64 Various platforms/compilers use different literal designator for 64-bit integers. Set any one of these switch accordingly. The default is LL and ULL for signed integer and unsigned integer, respectively. AIX/XLC do not require any switch from this list.

DFPAL_INTEGER64_LITERAL_i64 is for Windows platforms.

The easiest way to determine the literal designator for particular compiler/platform is to look at system header file limits.h.
DFPAL_NO_HW_DFP Use this switch if target platform/compiler does not support hardware DFP or #pragma mc_func directives for the hardware instruction inline expansion (e.g. using GCC compiler on AIX). DFPAL compiled with this switch will only use decNumber for the DFP arithmetic even if running on POWER6.
DFPAL_USE_DECFLOAT decFloat is new API, part of the decNumber package, which performs arithmetic directly on densely packed decimal (DPD) encoding. Use of decFloat eliminates DPD encoding to decNumber format conversion, and vice versa, enabling faster operation in software. Use of this switch has no impact on speed of hardware arithmetic operations. Use this switch to use decFloat instead of decNumber. More information about the decFloat is available at decNumber module.
DFPAL_STANDALONE_DLL
(only for Windows)
This switch is relevant to Windows platform only. DFPAL is using pthread_once() facility on Unix platforms with POSIX thread support. Windows does not have equivalent facility. Alternatively, DFPAL is using DllMain() facility on Windows platform. Compile with this switch if DFPAL is being compiled as standalone library (Dynamic Link Library or DLL). If DFPAL is integrated into some container module such as EXE or another DLL, use that container module's DllMain() equivalent facility. The container module's DllMain() equivalent facility must call dfpalInitProcessContext() for DLL_PROCESS_ATTACH event. No other actions are necessary for the remaining events.

A sample export symbol definition file dfpalsymexp.def is included for convenience.
DFPAL_USE_COMPILER_DFP In future when application build environment is migrated to XLC version 9, this switch allows compiler native decimal floating point usage, bypassing DFPAL. Applications can take advantage of the fastest decimal floating point arithmetic using compile native decimal floating (as compared to the compiler native decimal floating point, all arithmetic operations have function call overhead with DFPAL). To be able to use this switch, application must use decNN...() macros rather than decimalNN...() functions (decNN...() directly map to either decimalNN...() function call or equivalent compiler native decimal floating point operation).

AIX build instruction

On AIX, the XLC compiler is required to activate hardware decimal floating point. The following guidelines will ensure a successful compile process. A working sample Makefile is also included in the DFPAL package.

Following is sample XLC command line on AIX (assumes application does not use floating point exception traps; add -qflttrap flag to following command, otherwise).

xlc_r -c –q64 -O2 -DDFPAL_THREAD_SAFE -DDFPAL_OS_AIX5L -q64 -qlongdouble qflttrap -qlanglvl=stdc99 -I ../decNumber -I . dfpal.c

Linux on Power build instruction

On Linux on Power, either IBM XLC or GCC compiler can be used to activate and enable hardware decimal floating point support. The following guidelines will ensure a successful compile process. Working sample Makefiles (for use with IBM XLC and GCC) are also included in the DFPAL package.

Following is sample GCC command line on Linux on Power.

gcc -c -m64 -mlong-double-128 -O3 -DDFPAL_THREAD_SAFE -DDFPAL_OS_LOP -DDFPAL_INTEGER64_LITERAL_LL -I ../decNumber -I . dfpal.c

Unix build instruction

Following is an example of typical command line for other Unix platforms (assumes literal designator is L).

cc -c -DDFPAL_THREAD_SAFE -DDFPAL_NO_HW_DFP -DDFPAL_INTEGER64_LITERAL_L -I ../decNumber -I . dfpal.c

Windows build instructions

Following is typical command line using Microsoft compiler. A working sample Makefile is also included in the DFPAL package.

cl -c -DDFPAL_THREAD_SAFE -DDFPAL_NO_HW_DFP -DDFPAL_LOCAL_INTTYPES -DDFPAL_INTEGER64_LITERAL_i64 -DDFPAL_STANDALONE_DLL -I ../decNumber -I . dfpal.c


DFPAL management functions

DFPAL management API consists of routines required for DFPAL initialization, error handling, status checking, and termination.

char * dfpalVersion(void)

Return version number of DFPAL. This function can be called before dfpalInit().

uint32_t dfpalMemSize(void)

Returns amount of memory needed (in bytes) for thread specific context information. DFPAL purposefully does not allocate any dynamic memory to avoid interfering with any application specific memory management paradigm, e.g. certain application do not utilize standard malloc() for the application memory allocation. Instead, such applications have their own memory management layer based on shared memory, for example. This function shall be called before dfpalInit() to determine amount of memory needed by the DFPAL.

int32_t dfpalInit(void *context)

DFPAL must be initialized using dfpalInit() before any of its service is accessed. The input context is pointer to allocated memory. This function either returns DFPAL_ERR_NO_ERROR or an error code indicating error condition. List of possible errors and error codes can be found in dfpalerr.h. For multi-threaded application, each thread using DFPAL service must initialize using this service. Additionally, application is responsible for making sure that memory passed as an argument is thread safe.

The dfpalInit() reads environment variable DFPAL_EXE_MODE. Possible values for this environment variable are DNSW (force DFPAL to use decNumber software mode), PPCHW (force DFPAL to use PowerPC hardware mode; dfpalInit() will return error if no hardware support available), or AUTO (auto detect). Default value, in absence of the environment variable or undefined value, is AUTO.

dfpalCSFlag *dfpalGetFlagHandle(void)

Returns handle to global status flags, traps, and rounding mode control structure. The status flags, traps, and rounding mode are switched based on whether DFPAL is operating in hardware or software. This routine is useful when using DFPAL with runtime linking and loading using dlopen()/dlsym(). Applications not using runtime linking and loading do not have to use this.

void dfpalEnd(void (*memfree)(void *))

Frees memory used by DFPAL, passed down to DFPAL by the dfpalInit() call earlier. It takes a pointer to function performing memory de-allocation. Typically, memory de-allocation function is corresponding to one used to allocate memory for the dfpalInit().

enum dfpalExeMode dfpalGetExeMode(void)

Returns current mode of execution. Returns DNSW (decNumber Software) if DFPAL is using decNumber software implementation for the decimal floating point arithmetic. Returns PPCHW (Power PC Hardware) if DFPAL is using hardware decimal floating point arithmetic.

void dfpalResetContext(void) [deprecated]

Reset decNumber context structure. Avoid using this function.

int32_t dfpalGetError(int32_t *dfpalErr, int32_t *osErr, char **dfpalErrTxt)

Returns last DFPAL error code. Also, DFPAL error code, operating system error code (if any) and DFPAL descriptive error text, respectively, is placed into function input parameters.

void dfpalClearError(void)

Clear DFPAL error codes. Calling the dfpalGetError() after this function call will return “No error”.

int32_t dfpalErrorFlag(void)

Similar to dfpalGetError() but only returns DFPAL error code.

void dfpalInitProcessContext(void)

Note: this is Windows specific function. Unix platforms shall never use this.
Initialize a process context. The process context is shared by all threads in read-only mode. This function is automatically called by the dfpalInit() on Unix platforms. On Windows platform, if DFPAL is integrated into some other container module, use that container module’s DllMain() equivalent facility to call dfpalInitProcessContext() for DLL_PROCESS_ATTACH event. Refer to
How to compile DFPAL? for more details.


Floating point controls: rounding mode, exception and trap handling

These routines allow decimal floating point control, influencing decimal floating point arithmetic. The decimal floating point arithmetic unit (either decNumber or POWER6 processor) indicates exceptions conditions (overflow, underflow, divide by zero, invalid operation, inexact) by setting relevant status bits in the status field. The IEEE 754r (draft) standard requires following five exceptions, invalid operation, overflow, underflow, divide by zero, and inexact. For details about when these exception conditions arise refer to General Decimal Arithmetic Specification.

The following guidelines shall be observed with DFPAL.






Exception status flag management

The following routines allow accessing and altering decimal floating point exception status value. DFPAL provides the following exception status flags. An application must use following defines to access the exception flags. For details about when the exceptions are raised refer to General Decimal Arithmetic Specification.

void dfpalClearStatusFlag(dfpalflag_t mask)

Clear exception status flags specified by the mask parameter. A bit value of 1 in mask will clear that particular exception status flag. The exception status flags can be bitwise or’ed together indicating multiple status flag to be cleared. The exception status flag remains unchanged if the corresponding bit value is 0 in the mask.

void dfpalClearAllStatusFlag()

Clear all exception status flags. This function is equivalent to, but relatively faster than dfpalClearStatusFlag() function with DFPAL_FP_ALL argument.

void dfpalSetStatusFlag(dfpalflag_t mask)

Set exception status flags specified by the mask parameter. Bit value of 1 in the mask will set that flag, value of 0 will clear the flag.

dfpalflag_t dfpalReadStatusFlag(void)

Read current exception status flags. Return value of the function can be used in bitwise and operation to check presence of particular exception status.

dfpalflag_t dfpalSwapStatusFlag(dfpalflag_t mask)

This is combination of the dfpalSetStatusFlag() and the dfpalReadStatusFlag(). Read and return current exception status flags, set exception status flags specified by the mask parameter.

Exception trap management

The following routines allow accessing and altering decimal floating point trap control. DFPAL provides the following trap control flags. An application must use following defines to access the trap control flags. SIGFPE is raised when trap is enabled for that particular exception.

void dfpalEnableTrap(dfpaltrap_t mask)

Enable floating point trap for exception(s) specified by the mask parameter. Bit value of 1 will turn on trap for that particular exception. The traps can be bitwise or’ed together to indicate multiple traps to be enabled.

void dfpalEnableAllTrap(void)

Enable all five floating point exception traps.

void dfpalDisableTrap(dfpaltrap_t mask)

Disable floating point trap for exception(s) specified by the mask parameter. Bit value of 1 will turn off trap for that particular exception. The traps can be bitwise or’ed together to indicate multiple traps to be disabled.

void dfpalDisableAllTrap(void)

Disable all five floating point exception traps.

uint8_t dfpalAnyTrapEnabled(void)

Returns boolean value 1 if any trap is enabled, 0 otherwise.

uint8_t dfpalTrapEnabled(dfpaltrap_t mask)

Returns boolean value 1 if any of the trap(s) specified by the mask parameter is enabled, 0 otherwise.




Rounding mode control

The following routines allow controlling and accessing decimal floating point rounding mode. DFPAL provides the following rounding mode definitions. An application must use following defines to access the exception flags. For details about how rounding mode influence decimal floating point arithmetic refer to General Decimal Arithmetic.

dfpalrnd_t dfpalReadRoundingMode(void)

Return current rounding mode.

dfpalrnd_t dfpalSwapRoundingMode(dfpalrnd_t rndmode)

Return current rounding mode and set rounding mode specified by the rndmode parameter.

void dfpalSetRoundingMode(dfpalrnd_t rndmode)

Set rounding mode specified by the rndmode parameter.

uint8_t dfpalSetExponentClamp(uint8_t) [deprecated]

Set exponent clamp for decNumber context. Do not use this function.


Floating point operations

DFPAL supports 64-bit (precision=16 digits), and 128-bit (precision=34 digits) encoding formats. DFPAL also supports 32-bit (precision=7 digits) conversion routines to/from 64-bit encoding format. An application can emulate 32-bit encoding format arithmetic using the conversion routines coupled with 64-bit encoding format arithmetic. These encodings are referred as decimal32, decimal64, and decimal128. decimalNN is a general term referring to either decimal64 or decimal128 encoding formats.

Decimal floating point operations are classified into the following categories.

Programming Note

This guide refers to decimalNN...() routines. However, it is highly recommended that application program to decNN...() macros for easy migration to compiler native decimal floating point using the DFPAL_USE_COMPILER_DFP compile time switch. Refer to How to compile DFPAL? for more information. The decNN...() macros are listed in square brackets.

Not all the facilities listed below is a part of the current Extension for the programming language C to support decimal floating-point arithmetic working draft technical report by the ISO/IEC JTC1 SC22 WG14 committee. The proposal for extension is continuously evolving. Refer to the current draft of the proposal for extension. Adhering to the facilities listed in the proposal for extension may simplify migration to compiler native decimal floating point usage later.

Data type conversion

DFPAL provides conversion to and from decimal floating point format and many other programming language intrinsic data types such as integer and floating point formats.

char * dfpal_decimalNNToString(const decimalNN rhs, char *out) [decNNToString]

Convert input rhs from decimalNN to equivalent string representation, populate memory location pointed by the out parameter. Returns same memory location as out. Memory must be pre-allocated by application.

decimalNN dfpal_decimalNNFromString(const char *dfpstr) [decNNFromString]

Convert input dfpstr into decimalNN number. Exceptions are raised as discussed in General Decimal Arithmetic Specification.

double decimalNNToDouble(const decimalNN rhs) [decNNToDouble]

Convert input decimalNN value rhs to binary floating point double representation. There will be lost precision and/or slight inaccuracy converting between these representations. Input sNaN is converted to NaN, because double value of sNaN is not portable.

decimalNN decimalNNFromDouble(const double) [decNNFromDouble]

Convert binary floating point input double value to equivalent decimalNN format.

uint8_t * decimalNNToPackedBCD(decimalNN rhs, uint8_t *bcdOut, int32_t bcdOutLen, int32_t *scale) [decNNToPackedBCD]

Convert rhs in packed binary coded decimal (BCD) string. The bcdOutLen is length of the input array bcdOut. Then length must be at least 9 bytes (for decimal64) or 18 bytes (for decimal128), otherwise unchanged bcdOut is returned. The scale is output – scale of the rhs. The output array will be populated in right aligned order. That is, highest array index will hold least significant digit nibble and a sign nibble. Application must pre-allocated enough memory for the bcdOut, and clear the array content if necessary. Output sign is C (for +ve number) or D (for –ve number).

decimalNN decimalNNFromPackedBCD(uint8_t *bcdIn, int32_t bcdInLen, int32_t scale) [decNNFromPackedBCD]

Convert the input character array bcdIn into decimalNN number, return decimalNN. The bcdInLen is length of input array bcdIn. The length must be at least 9 bytes (for decimal64) or 18 bytes (for decimal128), or NaN is returned. The input scale is used to set exponent of the output number. The input bcdIn is assumed to be right aligned. That is, highest array index will hold least significant nibble and a sign nibble. Input sign nibble must be present, and it is assumed to be C (for +ve number) or D (for –ve number). When the input array in larger than 9 bytes (for decimal64) or 18 bytes (for decimal128), no more than 16 digits (for decimal64) or 34 digits (for decimal128) shall be present. Application can pre-process input array before passing it to the decimalNNFromPackedBCD() to ensure that above rules are observed. This rules are imposed to reconcile rounding effect between hardware and software implementations of the decimal floating point.

decimal32 decimal64ToDecimal32(const decimal64 rhs) [dec64ToDecimal32]

Convert decimal64 input rhs into decimal32 format. In case of lost precision INEXACT exception is raised. Note: this function is intended to be used for decimal32 arithmetic emulation. The INVALID exception is not raised on sNaN input to avoid any side effect.

decimal64 decimal64FromDecimal32(const decimal32 rhs) [dec64FromDecimal32]

Convert decimal32 input rhs into decimal64 format. No exceptions are possible. Note: this function is intended to be used for decimal32 arithmetic emulation. The INVALID exception is not raised on sNaN input to avoid any side effect.

General integer conversion rules

For conversion to integer, no INEXACT exception is raised even if there are lost digit(s). Conversion to integer is not performed with current rounding mode, rounding mode is always truncate. (Conversion to integer with desired rounding mode can be performed by using decimalNNToIntegralValue() function followed by either decimalNNToIntXX() or decimalNNToUintXX() conversion.).

For out of bound or Infinite input that cannot be represented in the destination format, an integer with largest magnitude in the direction of the sign with the same sign as source (input) is returned with INVALID exception raised. For example, converting decimalNN to 64-bit signed integer, an input of +Infinite (or say 1E+100) will return 9223372036854775807, -Infinite (or say -1E+100) will return -9223372036854775808, The INVALID exception is raised in either case.

For +/-sNaN or +/-NaN input smallest possible integer is returned, regardless of the source (input) sign. For example, converting decimalNN value +NaN to 64-bit signed integer, return value is -9223372036854775808 regardless of the input sign. The INVALID exception raised.

Negative source (input) is considered out of bound value for unsigned integer conversion, largest magnitude in the direction of the –ve sign is 0 for the unsigned integer. Similarly, smallest possible integer, which is 0 is returned for +/-NaN or +/-sNaN input with INVALID exception raised.

In case of conversion from integer to decimalNN, current rounding mode is used and INEXACT exception may be raised, especially when converting 64-bit integer to decimal64. Because maximum precision for decimal64 is 16 digits and integer may need up to 20 digits for exact representation. No other exceptions are possible.

int64_t decimalNNToInt64(const decimal64 rhs) [decNNToInt64]

Convert input rhs to equivalent 64-bit signed integer value. The general integer conversion rules apply. The output 64-bit signed integer is in range [-9223372036854775808, 9223372036854775807].

uint64_t decimalNNToUint64(const decimal64 rhs) [decNNToUint64]

Convert input rhs to equivalent 64-bit unsigned integer value. The general integer conversion rules apply. The output 64-bit unsigned integer is in range [0, 18446744073709551615].

int32_t decimalNNToInt32(const decimal64 rhs) [decNNToInt32]

Convert input rhs to equivalent 32-bit signed integer value. The general integer conversion rules apply. The output 32-bit signed integer is in range [-2147483648, 2147483647].

uint32_t decimalNNToUint32(const decimal64 rhs) [decNNToUint32]

Convert input rhs to equivalent 32-bit unsigned integer value. The general integer conversion rules apply. The output 32-bit unsigned integer is in range [0, 4294967295].

decimalNN decimalNNFromInt64(const int64_t rhs) [decNNFromInt64]

Convert 64-bit signed integer input rhs to equivalent decimalNN format. The general integer conversion rules apply.

decimalNN decimalNNFromUint64(const uint64_t rhs) [decNNFromUint64]

Convert 64-bit unsigned integer input rhs to equivalent decimalNN format. The general integer conversion rules apply.

decimalNN decimalNNFromInt32(const int32_t rhs) [decNNFromInt32]

Convert 32-bit signed integer input rhs to equivalent decimalNN format. The general integer conversion rules apply.

decimalNN decimalNNFromUint32(const uint32_t rhs) [decNNFromUint32]

Convert 32-bit unsigned integer input rhs to equivalent decimalNN format. The general integer conversion rules apply.




Utility functions

uint32_t decNNSign(const decimalNN rhs) [decNNsign]

Return sign of input rhs. Returns integer non-zero value (boolean 1) if rhs is –ve, 0 otherwise.

uint32_t decNNComb(const decimalNN rhs) [decNNComb]

Return combination field of rhs.

uint32_t decNNExpCon(const decimalNN rhs) [decNNExpCon]

Return exponent continuation filed of rhs.

uint8_t decimalNNIsInfinite(const decimalNN rhs) [decNNIsInfinite]

Returns boolean value 1 if rhs is +/-Infinite, 0 otherwise.

uint8_t decimalNNIsNaN (const decimalNN rhs) [decNNIsNaN]

Returns boolean value 1 if rhs is either +/-qNaN or +/-sNaN, 0 otherwise.

uint8_t decimalNNIsQNaN (const decimalNN rhs) [decNNIsQNaN]

Returns boolean value 1 if rhs is +/-qNaN, 0 otherwise.

uint8_t decimalNNIsSNaN (const decimalNN rhs) [decNNIsSNaN]

Returns boolean value 1 if rhs is +/-sNaN, 0 otherwise.

uint8_t decimalNNIsNegative (const decimalNN rhs) [decNNIsNegative]

Returns boolean value 1 if rhs is –ve number, 0 otherwise. This function is similar to the decNNSign().

uint8_t decimalNNIsZero (const decimalNN rhs) [decNNIsZero]

Returns boolean value 1 if rhs numeric value is +/-0, 0 otherwise.

decimal64 decimalNNTrim(const decimalNN rhs) [decNNTrim]

Remove insignificant trailing zeros from rhs. That is, if the number has any fractional trailing zeros they are removed by dividing the coefficient by the appropriate power of ten and adjusting the exponent accordingly.

decimal64 decimalNNZero(void) [decNNZero]

Returns decimalNN value 0 (no sign, coefficient=0, exponent=0), useful for initializing decimalNN to zero.

int32_t decimalNNGetDigits(const decimalNN rhs) [decNNGetDigits]

Return number of coefficient digits of rhs.

int32_t decimalNNGetExponent(const decimalNN rhs) [decNNGetExponent]

Return unbiased exponent of rhs.




Arithmetic operations

decimalNN decimalNNAbs(const decimalNN rhs) [decNNAbs]

The return value is absolute value of decimalNN input rhs.

decimalNN decimalNNAdd(const decimalNN lhs, const decimalNN rhs) [decNNAdd]

Add decimalNN inputs lsh and rhs, return result of the add operation.

decimalNN decimalNNCompare(const decimalNN lhs, const decimalNN rhs) [decNNCompare]

Compare decimalNN inputs lsh and rhs, return decmimalNN –1 if lsh is less than rhs, decimalNN 0 if lsh is equal to rhs, and decmimalNN +1 if lsh is greater than rhs.

int32_t decimalNNCompareLT(const decimalNN lhs, const decimalNN rhs) [decNNCompareLT]

This is a macro. Compare decimalNN inputs lsh and rhs, return boolean 1 if lsh is less than rhs. This macro is convenient, fast and it is recommended over the decimalNNCompare() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareLE(const decimalNN lhs, const decimalNN rhs) [decNNCompareLE]

This is a macro. Compare decimalNN inputs lsh and rhs, return boolean 1 if lsh is less than or equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompare() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareEQ(const decimalNN lhs, const decimalNN rhs) [decNNCompareEQ]

This is a macro. Compare decimalNN inputs lsh and rhs, return boolean 1 if lsh is equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompare() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareNE(const decimalNN lhs, const decimalNN rhs) [decNNCompareNE]

This is a macro. Compare decimalNN inputs lsh and rhs, return boolean 1 if lsh is not equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompare() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareGT(const decimalNN lhs, const decimalNN rhs) [decNNCompareGT]

This is a macro. Compare decimalNN inputs lsh and rhs, return boolean 1 if lsh is greater than rhs. This macro is convenient, fast and it is recommended over the decimalNNCompare() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareGE(const decimalNN lhs, const decimalNN rhs) [decNNCompareGE]

This is a macro. Compare decimalNN inputs lsh and rhs, return boolean 1 if lsh is greater than or equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompare() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNN decimalNNCompareTotal(const decimalNN lhs, const decimalNN rhs) [decNNCompareTotal]

Compare decimalNN inputs lsh and rhs, return decmimalNN –1 if lsh is less than rhs, decimalNN 0 if lsh is equal to rhs, and decmimalNN +1 if lsh is greater than rhs. Unlike, regular compare, compare Total compares numbers using abstract representation. Refer to Decimal Arithmetic Specification for more details.

int32_t decimalNNCompareTotalLT(const decimalNN lhs, const decimalNN rhs) [decNNCompareTotalLT]

This is a macro. Compare decimalNN inputs lsh and rhs using total order, return boolean 1 if lsh is less than rhs. This macro is convenient, fast and it is recommended over the decimalNNCompareTotal() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareTotalLE(const decimalNN lhs, const decimalNN rhs) [decNNCompareTotalLE]

This is a macro. Compare decimalNN inputs lsh and rhs using total order, return boolean 1 if lsh is less than or equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompareTotal() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareTotalEQ(const decimalNN lhs, const decimalNN rhs) [decNNCompareTotalEQ]

This is a macro. Compare decimalNN inputs lsh and rhs using total order, return boolean 1 if lsh is equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompareTotal() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareTotalNE(const decimalNN lhs, const decimalNN rhs) [decNNCompareTotalNE]

This is a macro. Compare decimalNN inputs lsh and rhs using total order, return boolean 1 if lsh is not equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompareTotal() for use in programming language conditional constructs such as if, for or while statement.

int32_t decimalNNCompareTotalGT(const decimalNN lhs, const decimalNN rhs) [decNNCompareTotalGT]

This is a macro. Compare decimalNN inputs lsh and rhs using total order, return boolean 1 if lsh is greater than rhs. This macro is convenient, fast and it is recommended over the decimalNNCompareTotal() for use in programming language conditional constructs such such as if, for or while statement.

int32_t decimalNNCompareTotalGE(const decimalNN lhs, const decimalNN rhs) [decNNCompareTotalGE]

This is a macro. Compare decimalNN inputs lsh and rhs using total order, return boolean 1 if lsh is greater than or equal to rhs. This macro is convenient, fast and it is recommended over the decimalNNCompareTotal() for use in programming language conditional constructs such such as if, for or while statement.

decimalNN decimalNNDivide(const decimalNN lhs, const decimalNN rhs) [decNNDivide]

Divide lsh with rhs, return result.

decimalNN decimalNNDivideInteger(const decimalNN lhs, const decimalNN rhs) [decNNDivideInteger]

Divide lsh with rhs, return integer part of the quotient.

decimalNN decimalNNExp(const decimalNN rhs) [decNNExp]

The return value is e raised to the power of rhs. Refer to decNumber module for more information.

decimalNN decimalNNLn(const decimalNN rhs) [decNNLn]

The return value is natural logarithm (logarithm in base e) of rhs. Refer to decNumber module for more information.

decimalNN decimalNNLog10(const decimalNN rhs) [decNNLog10]

The return value is logarithm in base ten of rhs. Refer to decNumber module for more information.

decimalNN decimalNNMax(const decimalNN lhs, const decimalNN rhs) [decNNMax]

The return value is numeric maximum of lsh and rhs. Note that regular numeric comparison operation is used.

decimalNN decimalNNMin(const decimalNN lhs, const decimalNN rhs) [decNNMin]

The return value is numeric minimum of lsh and rhs. Note that regular numeric comparison operation is used.

decimalNN decimalNNMinus(const decimalNN rhs) [decNNMinus]

The return value is negated value of rhs. This can be used as unary negate operation.

decimalNN decimalNNMultiply(const decimalNN lhs, const decimalNN rhs) [decNNMultiply]

Multiply decimalNN inputs lsh and rhs, return result of the multiply operation.

decimalNN decimalNNNormalize(const decimalNN rhs) [decNNNormalize]

Return a number which is numerically same as rhs, derived from the rhs by removing trailing zeros in the coefficient. Zeros removed by dividing the coefficient by the appropriate power of ten and adjusting the exponent accordingly.

decimalNN decimalNNPlus(const decimalNN rhs) [decNNPlus]

The return value is plus sign prefix to rhs. This function essentially no-op, provided for identity with the decimalNNMinus().

decimalNN decimalNNPower(const decimalNN lhs, const decimalNN rhs) [decNNPower]

The return value is the result of raising the lhs to the power of the rhs. Refer to decNumber module for more information.

decimalNN decimalNNPowerInt(const decimalNN lhs, const int32_t rhs) [decNNPowerInt]

Same as the decimalNNPower(), however the second argument rhs is integer. Useful for square, or cube of the lhs.

decimalNN decimalNNQuantize(const decimalNN lhs, const decimalNN rhs) [decNNQuantize]

This function is used to modify the lhs so that its exponent has a specific value, equal to that of the rhs. The decimalNNRescale() function may also be used for this purpose, but requires the exponent to be given as a decimal number.

decimalNN decimalNNRemainder(const decimalNN lhs, const decimalNN rhs) [decNNRemainder]

The return value is the remainder when lhs is divided by the rhs.

decimalNN decimalNNRemainderNear(const decimalNN lhs, const decimalNN rhs) [decNNRemainderNear]

The return value is the remainder when lhs is divided by the rhs, using the rules defined in IEEE 854. This follows the same definition as decimalNNRemainder(), except that the nearest integer (or the nearest even integer if the remainder is equidistant from two) is used for the quotient instead of the result from decimalNNDivideInteger().

For example, if lhs had the value 10 and rhs had the value 6 then the result would be -2 (instead of 4) because the nearest multiple of 6 is 12 (rather than 6).

decimalNN decimalNNRescale(const decimalNN lhs, const decimalNN rhs) [decNNRescale]

This function is used to rescale a number so that its exponent has a specific value, given by the rhs. It is similar to the decimalNNQuantize(), however, the second argument rhs specifies new exponent. The rhs must be a whole number (before any rounding); that is, any digits in the fractional part of the number must be zero. decimalNNQuantize() is faster and it is recommended over decimalNNRescale(). This function may be removed from the future release.

decimalNN decimalNNSameQuantum(const decimalNN lhs, const decimalNN rhs) [decNNSameQuantum]

The return value is decimalNN 1 if the lhs and rhs have equal exponent. Return 0, otherwise.

decimalNN decimalNNSquareRoot(const decimalNN rhs) [decNNSquareRoot]

The return value is square root of the rhs.

decimalNN decimalNNSubtract(const decimalNN lhs, const decimalNN rhs) [decNNSubtract]

Subtract decimalNN inputs lsh and rhs, return result of the subtract operation.

decimalNN decimalNNToIntegralValue(const decimalNN rhs) [decNNToIntegralValue]

The return value is rhs, with any fractional part removed if necessary using the current rounding mode. No exceptions flags, not even Inexact, are set (unless the operand is sNaN). Unlike decimalNNToInt...(), the result may have a positive exponent.

decimalNN decimalNNCeil(const decimalNN rhs) [decNNCeil]

The return value is ceiling value of the rhs. No exceptions, not even INEXACT, are raised (unless the operand is sNaN). The result may have a positive exponent.

decimalNN decimalNNFloor(const decimalNN rhs) [decNNFloor]

The return value is floor value of the rhs. No exceptions, not even INEXACT, are raised (unless the operand is sNaN). The result may have a positive exponent.


DFPAL Frequently Asked Questions



Q: Are there any success stories with DFPAL?
A: Yes. There are quite a few IBM and non-IBM enterprise class applications and middlewares are using DFPAL today.

Q: What version of decNumber is compatible with DFPAL?
A: DFPAL has been compiled and tested with variety of decNumber versions. It is highly recommended to use decNumber included in the DFPAL package. Please read release notes carefully, many DFPAL versions require some minimum decNumber version.

Q: Is there any special tuning needed for decNumber
A: Yes. Check decNumber release notes. Most of the decNumber defaults are sufficient for the DFPAL, such as DECDPUN and DECBUFFER. However, beginning decNumber version 3.40, the DECLITEND must be set 1, if the target platform is little-endian, or 0, if the target platform is big-endian. Refer to How to compile DFPAL? for more information.

Q: Does DFPAL allocate memory?
A: No. DFPAL does not allocate any memory to retain application memory management integrity. The memory needed by DFPAL is allocated by application on DFPAL's behalf, and passed to DFPAL using dfpalInit().

Q: But I see some memory allocation by decNumber.
A: With DECBUFFER unchanged from its default value, decNumber should not allocate any memory either. Additionally, consider using decFloat based arithmetic, which is much faster and does not allocate any memory. Refer to How to compile DFPAL? for more information.

Q: Is DFPAL thread safe?
A: Yes. However DFPAL must be built with DFPAL_THREAD_SAFE compile time switch. Refer to How to compile DFPAL? for more details.

Q: Are results (numeric value and exception status) the same between hardware and software mode of DFPAL?
A: The results are the same (with very few exceptions).

Q: Can I force DFPAL to use a particular execution method?
A: Yes. Set environment variable DFPAL_EXE_MODE to either DNSW (decNumber software) or PPCHW (PowerPC hardware) to force DFPAL to use particular execution mode. The DNSW mode will work on all cases, however DFPAL initialization will fail when using PPCHW on architecture where it is not possible. Refer to DFPAL management functions for more information.

Q: How does DFPAL performance compare to say binary floating point and compiler native decimal floating point?
A: Performance depends on many factors, and many time it is not even possible to compare due to inherent differences. However, our internal performance exercise revealed following consistent order (fastest to slowest): binary floating point, compiler native decimal floating point, DFPAL hardware, DFPAL software.

Q: Is there Linux on POWER hardware decimal floating point acceleration using DFPAL?
A: Yes. Linux on POWER support is similar to AIX. You can use either IBM XLC or GCC compiler on Linux on Power. Refer to How to compile DFPAL? for more information

Q: Can I integrate DFPAL into my application code?
A: Yes. DFPAL has been designed to compiler as standalone library or integrated into application code.

Q: If I use DFPAL now, then in future how can I migrate my application to use compiler native decimal floating point when it is possible? Will it require a code change?
A: DFPAL provides roadmap to migrate application to use compiler native decimal floating point. Using decNN...() macros in association with DFPAL_USE_COMPILER_DFP compile time switch bypasses DFPAL and uses compiler native decimal floating point. Refer to How to compile DFPAL? for more information.


DFPAL Release Notes

Release notes for DFPAL version 2.20

  1. Support for decFloat is added to this release of DFPAL. decFloat is a new module, part of the decNumber, performs decimal arithmetic faster for software execution mode of DFPAL.
  2. The new compile time switch DFPAL_USE_DECFLOAT must be defined to activate decFloat at compile time.
  3. Check for correct endianness is performed in dfpalInit(). The dfpalInit() will fail if decNumber or decFloat is not compiled with correct endian settings.
  4. Linux on Power hardware decimal floating point support, using IBM XLC compiler has been added to this version of DFPAL. Now there is a choice of either GCC or XLC compiler on Linux on Power.
  5. The minimum required decNumber release is version 3.57.





Release notes for DFPAL version 2.10

  1. Linux on Power hardware decimal floating point support, using GCC compiler has been added to this version of DFPAL.
  2. New routine dfpalClearAllStatusFlag() is added to improve performance.
  3. There are some performance improvement by using registers for the operands, rather than processing in the memory, for hardware execution mode of DFPAL.
  4. decimalNNFromPackedBCD() has different semantics as compared to previous release.





Release notes for DFPAL version 2.00

  1. Trap generated by DFPAL in hardware mode is not SIGFPE (it generates "Trace/BPT trap").
  2. There is no hardware instruction for 64-bit unsigned integer to decimal64 or decimal128 conversion. DFPAL does software conversion in either mode.
  3. For complex arithmetic operations such as ln, exp, log, square root, and power, DFPAL uses decNumber implementation in either case.
  4. decimal64 to/from double and decimal128 to/from double conversion uses strtod()/snprintf(). The strtod()/snprintf() behavior in terms of raising floating point exception is not consistent across platforms. Applications should not assume presence or absence of particular floating point exception after these conversions.
  5. For decimal64 to/from double and decimal128 to/from double conversion, current binary floating point rounding mode is used by strtod()/snprintf() (rounding mode is not shared by binary floating point and decimal floating point for POWER6 processor). Application's preference for particular rounding mode for the binary floating conversions [strtod()/snprintf()] can be implemented by using a wrapper around the decimalNN{To|From}Double() routines to set binary floating point rounding mode before calling the conversion routines.
  6. On Windows, for decimal64 to/from double and decimal128 to/from double conversion may return different results than the UNIX platforms. Because strtod()/snprintf() are implemented with slightly different semantics.
  7. Avoid using decimalNNRescale() function, it may be removed from the future release. Use decimalNNQuantize() instead. Due to exponent clamp in the hardware, results are not guaranteed when input number's exponent is close to Emax or Emin.

DFPAL is authored by Punit Shah (punit@us.ibm.com).
Please send any corrections, comments or questions to dfpal-l@austin.ibm.com.
This page was updated on 21 Dec 2007.