Thursday, December 22, 2005
RPG To The Rescue!
Solution: ILE RPG subprocedures
Details:
An application written in C needs to operate on zoned and packed decimal data. The ILE C compiler directly supports a packed-decimal data type called _Decimal. Conversion between _Decimal data and other built-in data types, like integer and float, are well defined and efficient. However, the compiler/language does not support a zoned-decimal data type. Instead, zoned data must be built from non-scalar types, such as a char array or a struct. In addition, because zoned is not a native type, conversions between zoned data and other data types must be implemented with runtime functions.
The recommended technique for converting between zoned and packed is to use CPYNV. For example, the following snippet shows how to convert from packed(15,5) to zoned(15,5):
#include
: : :
char znd[15];
_Decimal pkd(15,5);
: : :
_CPYNV( NUM_DESCR(_T_ZONED, 15, 5), znd,
NUM_DESCR(_T_PACKED, 15, 5), (char*)&pkd );
Simple, but not speedy enough if your application is doing millions of conversions.
RPG to the rescue. RPG directly supports both zoned and packed decimal data types. Seemingly, the compiler should be able to generate more efficient code sequences for converting between these types. Because ILE supports inter-language binding, let's replace _CPYNV with a RPG subprocedure. Here's one version of a subprocedure to convert from packed to zoned:
H nomain
* Prototypes for functions
D CVPDZD pr
D znd 15s 5
D pkd 15p 5 const
** Translate packed(15,5) to zoned(15,5))
P CVPDZD b export
D CVPDZD pi
D znd 15s 5
D pkd 15p 5 const
*
C Eval znd = pkd
C* Eval(h) znd = pkd (if you want rounding)
C return
*
P CVPDZD e
Use CRTRPGMOD to compile the RPG code, and use CRTPGM to bind it with your C code, which now resembles this:
extern void CVPDZD( char*, decimal(15,5)* );
: : :
char znd[15];
_Decimal pkd(15,5);
: : :
CVPDZD( znd, &pkd );
My measurements reveal that the RPG solution is approximately 7 times faster.
If you want a nicer name (not all uppercase) for the C program to call, you can use the EXTPROC keyword on the prototype to give the better name:
D cvPdZd pr extproc('cvPdZd')
Caveat:
By default, RPG code is not thread safe. To make it thread-safe, you can code THREAD(*SERIALIZE) in the H spec.
References:
C/C++ Programmer's Guide: (http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/books/sc092712.pdf)
ILE C/C++ for AS/400 MI Library Reference: (http://publib.boulder.ibm.com/infocenter/iseries/v5r3/topic/books/sc092418.pdf)