QQQ L III BBBB 4 888 Q Q L I B B / 44 8 8 Q Q L I B B / 4 4 8 8 Q Q L I BBBB / 4 4 888 Q Q Q L I B B / 44444 8 8 Q Q L I B B / 4 8 8 QQ Q LLLLL III BBBB 4 888 U S E R ' S G U I D E QLIB/48 Version 1.0 January 1997 By Steve Lindblad 73003.1772@compuserve.com QLIB/48 Version 1.0 Software and User's Guide (c) Copyright 1997 Steven P. Lindblad ALL RIGHTS RESERVED See accompanying README.TXT file for more information. ---------------------------------------------------------------- Disclaimer THIS SOFTWARE AND DOCUMENTATION IS PROVIDED ON AN "AS IS" BASIS, WITHOUT ANY WARRANTIES OR REPRESENTATIONS EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. QLIB/48 User's Guide iii Table of Contents TABLE OF CONTENTS ================= 0. INTRODUCTION AND INSTALLATION ............................ 1 -------------------------------- A. Introduction ............................................. 1 B. Notational Conventions ................................... 2 C. Installation ............................................. 3 D. Assigning QLIB/48 to the Keyboard ........................ 5 E. Removing QLIB/48 ......................................... 6 I. OVERVIEW: Basic Operation ................................ 8 ---------------------------- A. Introduction ............................................. 8 B. The Menu Structure ....................................... 10 II. EXAMPLES: Getting Started ............................... 14 ----------------------------- A. Introduction ............................................. 14 B. Setting Assumptions; Single Life Annuities ............... 14 C. Life Insurances; User-Defined Functions; Programs ........ 18 D. Joint-Life Functions ..................................... 23 E. Non-Actuarial Functions .................................. 27 III. ASSUMPTIONS ............................................ 29 ---------------- A. Introduction ............................................. 29 B. Summary of Assumptions ................................... 29 C. The Assumption Menu ...................................... 29 D. Assumption Recall/Store Commands ......................... 33 E. Additional Assumption Commands ........................... 36 F. The Qpar Variable ........................................ 37 IV. ACTUARIAL FUNCTIONS ..................................... 39 ----------------------- A. Introduction ............................................. 39 B. Function Arguments ....................................... 39 C. Mortality-Based Functions ................................ 41 D. Interest-Only Functions .................................. 47 E. Miscellaneous Commands ................................... 49 F. Nonintegral Ages ......................................... 50 G. The Joint-Life Table ..................................... 53 Table of Contents iv QLIB/48 User's Guide V. MORTALITY TABLE DEFINITIONS AND CALCULATIONS ............. 55 ----------------------------------------------- A. Mortality Table Format ................................... 55 B. Storage of Mortality Tables .............................. 56 C. Setbacks and Terminal Age Truncation ..................... 58 D. The Joint-Life Table ..................................... 59 E. The General Case ......................................... 61 F. Calculating the N's ...................................... 63 VI. MORTALITY TABLE FILES UNDER DOS - The MKQTL Program ..... 64 ------------------------------------------------------- A. Types of Files Supported by MKQTL ........................ 64 B. Examples ................................................. 66 C. Additional Examples ...................................... 71 D. General MKQTL Usage ...................................... 71 VII. ADDITIONAL EXAMPLES .................................... 78 ------------------------ A. Calculations at Nonintegral Ages ......................... 78 B. Using QLIB/48 with HP 48 Applications .................... 80 C. Building Modified Mortality Tables ....................... 82 D. Demographic Functions .................................... 85 VIII. SAMPLE PROGRAMS ....................................... 86 --------------------- A. Introduction ............................................. 86 B. ACTFUNC - Miscellaneous Actuarial Functions .............. 87 C. GAR94 - Building Generational Mortality Tables ........... 89 D. NONFORF - Life Insurance Nonforfeiture Values ............ 91 E. PBGCANN - PBGC Annuities ................................. 94 Appendix A: ERROR MESSAGES .................................. 97 Appendix B: REFERENCES ...................................... 99 QLIB/48 User's Guide 1 0. Installation 0. INTRODUCTION AND INSTALLATION ================================ A. INTRODUCTION --------------- QLIB/48 is a library of actuarial commutation functions that expand the capabilities of the Hewlett-Packard 48 series calculators. With QLIB/48, you can use commutation functions such as DX, NX, and MX just as you would use any built-in function of the calculator. This manual assumes you have a basic working knowledge of actuarial mathematics and the HP 48 calculator. The features of QLIB/48 include: + Actuarial functions that can be used directly from the keyboard, in formulas, and in programs; + Single- and joint-life commutation functions; + A flexible set of assumptions, which can be changed from within programs or interactively from the keyboard; + Consistent handling of nonintegral ages, using linear interpolation or uniform distribution of deaths; + Date handling functions; + Sample pension and life insurance mortality tables, and a DOS program for maintaining your own libraries of tables; + Sample HP 48 programs for life insurance nonforfeiture values, pension PBGC annuities, and GAR-94 generational mortality tables. Best of all, you may use QLIB/48 Version 1.0 for free! (Please see the QLIB/48 README.TXT file for details on how you may use and/or copy QLIB/48.) If you find QLIB/48 useful, I would greatly appreciate hearing from you. Please send any comments, questions, or suggestions you have to me via e-mail at the address listed below. If you do not have access to e-mail, I can also be reached at my address in the Society of Actuaries membership directory. Thank you for your interest! Steve Lindblad 73003.1772@compuserve.com 0. Installation 2 QLIB/48 User's Guide B. NOTATIONAL CONVENTIONS ------------------------- The following notational conventions are used throughout this manual: [ENTER] HP 48 hard keys on the physical keyboard [VAR] {ASSU} Soft menu keys assigned to the A-F menu keys {DX} [<] Left-shift key [>] Right-shift key [<-] Cursor-left key [->] Cursor-right key [up] Cursor-up key [/] Division key [QMAIN] Shorthand for the key to which QLIB/48 has been assigned. See Section D below. \Ga Greek letter alpha \Gd Greek letter delta \Gw Greek letter omega \<< \>> HP 48 program delimiters ([<][-]) [a] Alpha key for toggling alphanumeric entry mode. In the examples, this manual assumes that system flag 60 is clear so that [a][a] is needed to lock alphanumeric entry mode. This is the default for the HP 48. G/GX: The keystrokes that follow apply to the 48G/48GX only. S/SX: The keystrokes that follow apply to the 48S/48SX only. The character sequences beginning with "\" are the HP 48's "TIO 3" (translate IO mode 3) codes for special symbols that are in the HP 48's character set, but are not part of the ASCII character set. For more information, see the section on transferring data in your HP 48 User's Guide. QLIB/48 User's Guide 3 0. Installation C. INSTALLATION --------------- QLIB/48 requires a Hewlett-Packard 48G/GX or 48S/SX Scientific Expandable calculator, a serial interface cable, and a computer and Kermit software that can be used to transfer the QLIB/48 program files to the HP 48. Due to the amount of memory required, a 48GX, or a 48SX with a RAM card, is recommended. However, a 48G or 48S can also be used (but see step 7 below). To install QLIB/48, follow these steps: 1. *** IMPORTANT! *** BACKUP YOUR CALCULATOR'S MEMORY TO YOUR COMPUTER by following the directions in your HP 48 User's Guide. I have tested QLIB/48 very extensively on a 48SX (ROM version E) and 48GX (ROM M), and I believe it to be bug-free. However, any software can have bugs, and bugs can cause memory loss. For your protection, backup your memory before trying any new software on your calculator. 2. Select the port you will use to store the QLIB/48 program library and mortality table (QTL) library. You may use different ports for the program library and the QTL library. On the HP 48, libraries are collections of programs and data used to expand the capabilities of the calculator. Many of the HP 48's own commands, for example, are stored in libraries in ROM. Application programs you purchase on memory cards are also stored in libraries. Ports are special areas in memory used to store libraries, backup objects, and other special objects. A single port can hold as many such objects as will fit into the available memory. Your HP 48 consists of up to three ports: port 0, port 1, and port 2. Ports 1 and 2 refer to memory cards physically plugged into the calculator (thus, they are available only on the GX and SX). These may be ROM cards containing application programs sold by Hewlett-Packard or other vendors, or FREE'd RAM cards. Port 0 is a special area of main memory. Main memory consists of the internal RAM of the calculator, and memory from any MERGE'd RAM cards you have installed. For more information on ports and RAM cards, see your HP 48 User's Guide. If you have a 48G or 48S, or if you do not have a FREE'd RAM card, you must use port 0, as it is the only port available. If you have a FREE'd RAM card in port 1 or port 2, you may use that port. Before completing the remaining steps, be sure the RAM card is not write-protected. If it is, turn off the HP 48 and change the write-protect switch. 0. Installation 4 QLIB/48 User's Guide ** NOTE! ** I have not tested QLIB/48 with port 2. If you wish to store QLIB/48 in port 2 (especially with a large (>128K) memory card on the GX), please test the program carefully. 3. Download the QLIB48.LIB program file to the HP 48. Follow the directions in your HP 48 User's Guide or those supplied with the serial interface cable. 4. Switch to the VAR menu and recall the contents of the 'QLIB48.LIB' variable to the stack: ----- Keystrokes ----- ------ Display ------- [VAR] 1: {QLIB4} 1: Library 926: QLIB.. Note: "{QLIB4}" is the menu key for the 'QLIB48.LIB' variable. The display shown is the stack display AFTER the indicated keystrokes have been executed. 5. Purge the 'QLIB48.LIB' variable: ' {QLIB4} [ENTER] 2: Library 926: QLIB.. 1: 'QLIB48.LIB' [<][PURGE] 1: Library 926: QLIB.. 6. Store the library in the port you selected in step 2. (Replace 0 with the port number you selected.) 0 [ENTER] 2: Library 926: QLIB.. 1: 0 [STO] 1: 7. Repeat steps 3-6 to download and store a mortality table library, replacing 'QLIB48.LIB' with 'SAMPLE.QTL' or the name of your own mortality table library. Note that the examples in this manual assume that you have installed the SAMPLE.QTL library or that you have copied the necessary mortality tables from SAMPLE.QTL to your library. Note 1: If you have only 32K of memory (i.e., you have a 48S, G, or an SX with no RAM card), the SAMPLE.QTL library will probably be too large to install. In this case, you must use the MKQTL program to create a smaller mortality table library. See Chapter VI for more information. QLIB/48 User's Guide 5 0. Installation Note 2: Once you have installed a mortality table library (QTL library), you can later change to another QTL library by following the removal instructions in Section E (step 3) below, and then following steps 3-6 to install the new QTL file. If you do this, however, you should purge any Qpar variables created with the old QTL library, as they may reference the wrong tables. See Section V.B.1 for more information. 8. Turn the HP 48 off. If you stored QLIB/48 in a FREE'd RAM card, you may now set the write-protect switch back to read-only if you wish. 9. Turn the HP 48 back on. The off/on cycle causes the HP 48 to automatically ATTACH the program and mortality table libraries to the HOME directory (which means they will be available for your use in any directory). 10. Now follow the steps in the following section to assign QLIB/48 to a key on your keyboard. This is not strictly required, but will make QLIB/48 much easier to use. The examples in this manual assume you have assigned a key. D. ASSIGNING QLIB/48 TO THE KEYBOARD: The [QMAIN] Key ----------------------------------------------------- QLIB/48 allows you to assign the QLIB/48 MAIN Menu to any key on your keyboard, much like the built-in MatrixWriter and Solve applications are assigned to the [>][ENTER] and [<][7] keys. Doing this has two primary advantages: (1) it gives you quick access to the QLIB/48 MAIN menu, and (2) it allows you to change to the MAIN Menu while editing programs (PRG entry mode) and algebraic expressions (ALG entry mode). The key you assign is called the "[QMAIN]" key. You can use any key on the keyboard, but that key then loses its ordinary function. I find [>][9] convenient, but if you often use the interactive Symbolic menu (on the G/GX) or the equation catalog (on the S/SX), you may want to pick another key. In any event, the [QMAIN] key definition is only in effect while the HP 48 is in USER mode, so you can always access the original function of your key simply by turning USER mode off (with [<][USER]). To assign the key you have selected, follow these steps: 0. Installation 6 QLIB/48 User's Guide 1. Recall the QKEY program to the stack: ----- Keystrokes ----- ------ Display ------- G/GX: [>][LIBRARY]{QLIB/}{QKEY} 1: QMAIN S/SX: [<][LIBRARY]{QLIB/}{QKEY} 2. Enter the code for your key in the rc.p (row/column/plane) format, such as 64.3 for [>][9]. See the ASN command documentation in your HP 48 User's Guide for more information on key codes. 64.3 [ENTER] 2: QMAIN 1: 64.3 3. Use the HP 48 ASN command to assign the QKEY program to the key you have chosen: G/GX: [<][MODES]{KEYS}{ASN} 1: S/SX: [>][MODES]{ASN} 4. Turn USER mode on by pressing [<][USER] ([<][USR] on the S/SX) once or twice, until the USER indicator appears. Now, when [QMAIN] appears in an example, simply press the key you assigned above. If you did not assign a key, you may use [LIBRARY]{QLIB/}{QMAI} to activate the MAIN Menu, but this will not work while editing a program or algebraic expression (that is, this method will terminate PRG or ALG entry mode, as if you pressed [ENTER]). E. REMOVING QLIB/48 ------------------- QLIB/48 is easy to remove from your HP 48: 1. If QLIB/48 is stored on a FREE'd RAM card, turn off the HP 48 and make sure the card is not write-protected. QLIB/48 User's Guide 7 0. Installation 2. Detach and purge the QLIB/48 program library, as shown below. Replace "0" below with "1" or "2" if you stored QLIB/48 in port 1 or 2. ----- Keystrokes ----- ------ Display ------- [>][::] 0 [->] 926 2: 0: 926 [ENTER] [ENTER] 1: 0: 926 G/GX: [<][LIBRARY]{DETAC} 1: 0: 926 S/SX: [<][MEMORY][NXT]{DETAC} [<][PURGE] 1: NOTE: You may see the display "jump" when you execute the PURGE. This is perfectly normal. 3. Similarly, detach and purge the mortality table library: [>][::] 0 [->] 925 2: 0: 925 [ENTER] [ENTER] 1: 0: 925 G/GX: [<][LIBRARY]{DETAC} 1: 0: 925 S/SX: [<][MEMORY][NXT]{DETAC} [<][PURGE] 1: 4. If you stored QLIB/48 in a FREE'd RAM card, turn the HP 48 off and set the write-protect switch back to read-only if you wish. 5. Delete the QKEY assignment if you have one (replace "64.3" with your key code from Section D, step 2 above): ' [a][a] SKEY [ENTER] 1: 'SKEY' 64.3 [ENTER] 2: 'SKEY' 1: 64.3 G/GX: [<][MODES]{KEYS}{ASN} 1: S/SX: [>][MODES]{ASN} 6. Purge the 'Qpar' variable from any directory in which you created a set of assumptions. 'Qpar' is an ordinary variable, and may be purged like any other ordinary variable. Leaving 'Qpar' variables hanging around after you have removed QLIB/48 won't cause any harm, but they can use up a significant amount of memory (about 3K-4K each). I. Overview 8 QLIB/48 User's Guide I. OVERVIEW: Basic Operation ============================ A. INTRODUCTION --------------- QLIB/48 is a library of commands and functions for the HP 48 series calculators that expand the calculator to include basic building-block actuarial functions such as DX, NX, MX, RX and qX (see chapter IV for a complete list). Commands for specifying actuarial assumptions and performing other housekeeping functions are also provided (chapter III). All functions are accessible from the keyboard as well as in programs and algebraic expressions. More complicated functions, or functions not included in QLIB/48, such as AX(x)=MX(x)/DX(x), can easily be created as user-defined functions (see Example 2.11). In addition, you can write quite sophisticated programs using QLIB/48's functions. Several sample programs are included in the QLIB/48 distribution. See chapter VIII for more information. Finally, remember that it is your responsibility as an actuary to be sure your calculations are being performed in a manner appropriate for your application. For your reference, chapters IV and V provide detailed information on how QLIB/48 calculates actuarial values. For mission-critical applications, be sure to test your results very carefully. If possible, you should test the results against other systems. A.1 Primary, Secondary, and Joint-Life Tables --------------------------------------------- Each life-based actuarial function in QLIB/48 actually has separate versions for three different life tables: the primary life (X), secondary life (Y), and joint life (J). In the menus, each X function is available on the unshifted menu key, each Y function is on the left-shifted menu key, and each J function is on the right-shifted menu key. In addition, there is a special fourth version (K) of each function which takes an additional parameter (k) indicating which table to use, X (k=1), Y (k=2), or J (k=3). The K functions are available on a separate menu (see section B.2 below). Mortality for the primary and secondary lives is specified by selecting appropriate mortality tables. Mortality rates for the joint-life table J are calculated from the primary and secondary life tables, based on an age difference you specify. QLIB/48 User's Guide 9 I. Overview A.2 Mortality Tables -------------------- There are two ways of storing mortality tables on your HP 48 for use with QLIB/48: in the QTL library, or in ordinary variables. Generally, the tables you use most often should be kept in the QTL library where they will be conveniently accessible from the menus. Less frequently used tables can be downloaded to or created in variables as they are needed. A QTL library is an HP 48 library, separate from the QLIB/48 program library itself, containing only mortality tables. One library, SAMPLE.QTL, is included with the QLIB/48 distribution. You may also create your own QTL library with the MKQTL program (see chapter VI). There is no limit (other than available memory) on the number of tables that may be placed in a library. Note, however, that only one QTL library may be installed at a time. Also, since it is relatively inconvenient to change the QTL library you have installed, you will probably want to create a QTL library containing the tables you use most often, and then stick with it. The SAMPLE.QTL library includes the following tables: Name Title ------ --------------------- UP84 UP-1984 M83GAM Male 1983 GAM F83GAM Female 1983 GAM M80CSO Male 1980 CSO ANB F80CSO Female 1980 CSO ANB M94GAM Male GAM-94 Static F94GAM Female GAM-94 Static MUP94 Male UP-94 [i.e., the GAM-94 Basic table] FUP94 Female UP-94 MAA94 Male AA Proj. Scale FAA94 Female AA Proj. Scale The names of the tables appear in the menu key labels when you are selecting a table; the titles appear in the Assumption Menu display after you have selected the table. See Example 7.5 for a demonstration of how to use a mortality table stored in a variable. I. Overview 10 QLIB/48 User's Guide A.3 Assumptions --------------- In addition to the mortality tables, you may specify other assumptions to be used, such as age setbacks, the interest rate, and the radix (number of initial lives). All assumptions may be changed interactively from the Assumption Menu (see Example 2.1 and chapter III), or with commands from within a program (see Section III.D). A.4 How QLIB/48 Works; the Qpar Variable ---------------------------------------- Internally, QLIB/48 calculates all commutations from an internal set of N[x] values. The N's are calculated automatically the first time you perform an actuarial function for a given set of assumptions. When this happens, you will see a "Calculating..." message at the top of the screen. This process is called "calculating the assumptions." (See Chapter V for additional information.) All of your assumptions and the calculated N values for all three tables (X, Y, and J) are stored in the variable 'Qpar'. 'Qpar' variables contain a special Library Data object which you cannot view or edit, but they are otherwise ordinary variables. Thus, you may recall, move, copy, download, or purge 'Qpar' variables as you would any ordinary variable. See Section III.F for more information on the 'Qpar' variable. B. THE MENU STRUCTURE --------------------- QLIB/48 provides five menus for use in performing actuarial computations directly from the keyboard and for building programs and algebraic expressions. All QLIB/48 functions and commands may be found in one or more of these menus. Each menu may be activated by pressing its key from another menu, or by directly executing the command for the menu. In addition, you may use the [QMAIN] key you defined (Section 0.D) to activiate the MAIN Menu. Menu Name Command Key to Select Menu --------------- ------- ------------------ MAIN Menu QMAIN {MAIN} or [QMAIN] K Menu QKMENU {KMEN} Assumption Menu QASSU {ASSU} Command Menu QCMDMENU {CMDS} or [<]{ASSU} Table Menu QTBLMENU {TBLS} QLIB/48 User's Guide 11 I. Overview B.1 MAIN Menu ------------- The MAIN Menu includes all commutation and other actuarial functions. For life-based functions (which end in X, Y, or J to indicate the table to be used), the unshifted menu key provides the X function, the left-shifted menu key provides the Y function, and the right-shifted menu key provides the J function. MAIN Menu (QMAIN) ----------------- Key Left Right Label Unshifted Shifted Shifted ----- --------- ------- ------- ASSU Assump Menu Command Menu QADISP DX DX DY DJ NX NX NY NJ N12X N12X N12Y N12J CL12X CL12X CL12Y CL12J lX lX lY lJ SMX SMX SMY SMJ DX DX DY DJ CX CX CY CJ MX MX MY MJ MMX MMX MMY MMJ RMX RMX RMY RMJ \GaX \GaX \GaY \GaJ DX DX DY DJ QX qX qY qJ NMX NMX NMY NMJ CLMX CLMX CLMY CLMJ \GwX \GwX \GwY \GwJ CM CM - - V v - - DM dm - - \Gd \Gd - - IM im - - LTRP LTRP - - DTDIF DTDIF DTBLD DTBRK MO mult. by 1_mo conv. to mo div. by 1_mo CMDS Command Menu - - TBLS Table Menu - QTABLES KMEN K Menu - - ABOUT program info - - Note that the "mo" menu key works just like the menu keys for the built-in units in the HP 48's UNITS menu. I. Overview 12 QLIB/48 User's Guide B.2 K Function Menu ------------------- The K Function Menu is identical to the MAIN Menu (see above), except that it contains the K versions of the life-based functions instead of the X/Y/J versions. The shifted commutation menu keys do nothing. B.3 Assumption Menu ------------------- The Assumption Menu provides an interactive environment for displaying and setting the current assumptions. To enter the Assumption Menu, press the {ASSU} menu key. Press {EXIT} from the Assumption Menu to return to the MAIN Menu. See Example 2.1 and Section III.C for more information on how to use the Assumption Menu. B.4 Command Menu ---------------- The Command Menu contains commands for setting and examining the assumptions, and commands for performing other housekeeping functions. These commands can be used in programs or directly from the keyboard. To enter the Command Menu, press {CMDS} or [<]{ASSU} from the MAIN Menu or any other menu. For each menu key corresponding to an assumption, the unshifted menu key contains the command to recall the current value of the assumption to the stack, and the left-shifted menu key contains the store command for that assumption, which takes the value in level 1 of the stack and stores it as the assumption value. Note that this is similar to the HP 48's VAR menu, where the unshifted menu key evaluates the object for that variable, and the left-shifted key stores a value in the variable. For your reference, the first nine entries of the Command Menu give you the order of the entires in the assumption lists used by the QCURRCL and QCURSTO commands. See Sections III.D and III.E for more information on the assumption commands. QLIB/48 User's Guide 13 I. Overview Command Menu (QCMDMENU) ----------------------- Key Left Right Label Unshifted Shifted Shifted ----- --------- ------- ------- QINT QINT QINTSTO - QUDD QUDD QUDDSTO - TBLX QTBLX QTBLXSTO QGETTBL QSBX QSBX QSBXSTO - TBLY QTBLY QTBLYSTO QGETTBL QSBY QSBY QSBYSTO - QXMY QXMY QXMYSTO - QRADI QRADIX QRADIXSTO - QTw QT\Gw QT\GwSTO - QCUR QCURRCL QCURSTO - QDIRC QDIRCUR - - QGET QGETTBL - - QADIS QADISP - - QCAL QCALC - - QUCA QUCALC - - TBLS Table Menu - QTABLES KMEN K Menu - - MAIN MAIN Menu - - B.5 Table Menu -------------- The Table Menu (QTBLMENU) is a menu of all the mortality tables stored in your QTL library. This is useful for inserting the names of tables in your programs, or for recalling mortality tables to the stack. To enter the Table Menu, press the {TBLS} menu key. The first item of the Table Menu is the QTABLES command, which returns a list of the names of all the tables. Note that the Table Menu is different from the Table Selection Menu reached via the {X/Y} key in the Assumption Menu. The Table Selection Menu immediately changes your current X or Y table. The Table Menu simply gives you independent access to the table XLIB names themselves. II. Examples 14 QLIB/48 User's Guide II. EXAMPLES: Getting Started ============================= A. INTRODUCTION --------------- The examples in this chapter are intended to give you a basic familiarity with how QLIB/48 can be used to solve real-world actuarial problems. The examples only scratch the surface, however. As you become more familiar with QLIB/48, you can use it to customize your HP 48 to become a very powerful machine for solving the specific actuarial problems you encounter. Chapters III, IV, and V provide detailed information about the operation of all commands and functions. However, I recommend that you work through all of the examples in this chapter, as they include information that is not presented elsewhere. Chapter VII provides additional examples. B. SETTING ASSUMPTIONS; SINGLE LIFE ANNUITIES --------------------------------------------- Example 2.1 - Setting assumptions --------------------------------- Suppose we wish to compute the present value of a life annuity payable annually at the beginning of each year to a 50 year-old, assuming UP-1984 mortality set back two years and 8% interest. (The examples in this chapter assume you have installed the SAMPLE.QTL library, or that the mortality table library you are using includes the necessary mortality tables.) We must first specify the assumptions we wish to use. QLIB/48 provides an interactive environment for doing this. Press [QMAIN]{ASSU} (first press the [QMAIN] key you defined in Section 0.D, and then press the {ASSU} soft menu key on the A key). You should see the following Assumption Menu display: +----------------------+ |-- ACTUARIAL ASSUMP --| |X: (no table) | |Y: (no table) | |x-y=0 R:1.000E9| |int=0% LIN| |----------------------| | | |== == == == == ==| +----------------------+ QLIB/48 User's Guide 15 II. Examples with these menu keys (represented above by the =='s): {X/Y} {SB} {X-Y} {INT} {RADIX} {EXIT} Now, follow these steps to set the appropriate assumptions: 1. Specify the mortality table by pressing {X/Y}. A menu of available mortality tables will appear. (The first menu key is {X:}, indicating that you are selecting the X table.) Press the {UP84} key. The UP-1984 table will be selected, and you will be returned to the Assumption Menu. 2. Specify the two year set back by typing 2 and pressing {SB}. 3. Enter 8 and press {INT} to set the interest rate. (You may also enter .08.) Your display should now look like this: +----------------------+ |-- ACTUARIAL ASSUMP --| |X: UP-1984 sb2 | |Y: (no table) | |x-y=0 R:1.000E9| |int=8% LIN| |----------------------| | | |== == == == == ==| +----------------------+ (Note: Don't worry if you have somthing defined for Y; it will not affect this example.) 4. Press {EXIT} to leave the Assumption Menu and return to the MAIN Menu. Example 2.2 - Direct calculation from the keyboard -------------------------------------------------- Continuing with the above example, we are now ready to calculate the age 50 annuity. Your menu keys should look like this (if not, press your [QMAIN] key): ASSU DX NX N12X CL12X lX Follow the steps illustrated below to calculate the annuity. Note: The stack displays in this example assume you have 6 FIX display mode set. This is a useful display mode for actuarial work because it displays large numbers with commas and it II. Examples 16 QLIB/48 User's Guide displays dates with the entire month, day and year visible (e.g., 1.011990). The following keystrokes can be used to set 6 FIX mode: G/GX: [<][MODES]{FMT} 6 {FIX} S/SX: [<][MODES] 6 {FIX} 1. Calculate the N commutation at age 50: ----- Keystrokes ----- ------ Display ------- 50 {NX} 1: 228,617,907.586 Notice that when you pressed {NX}, "Calculating...X" appeared at the top of the screen for a few seconds. During this time, QLIB/48 was calculating and saving a set of N commutation values to be used in calculating all other actuarial values. This will occur every time you use a mortality-based actuarial function after changing the assumptions. 2. Calculate DX(50): 50 {DX} 2: 228,617,907.586 1: 20,136,322.6509 Note that the "Calculating...X" message did not appear this time. QLIB/48 did not need to calculate the assumptions again because the N's were calculated and saved in step 1. 3. Divide to get the annuity: [/] 1: 11.353508 Only 6 decimal places are displayed in 6 FIX mode, but the annuity was actually calculated to 12 digits, the HP 48's maximum precision. To see the additional digits, press [<][EDIT] or set STD display mode. Example 2.3 - Calculating an annuity payable monthly ---------------------------------------------------- Now suppose we wish to calculate the same annuity as in the previous example, but with the annuity payable monthly rather than annually. One way to do this is to follow the same steps as in Example 2.2, but using the N12X commutation function rather than NX: QLIB/48 User's Guide 17 II. Examples ----- Keystrokes ----- ------ Display ------- 1. 50 {N12X} 1: 219,388,759.705 2. 50 {DX} 2: 219,388,759.705 1: 20,136,322.6509 3. [/] 1: 10.895175 (Note: This example assumes you have LIN mode set (the default). In this mode, QLIB/48 calculates N12X(50) using the common NX(50)-11/24*DX(50) approximation. See the description of the NMX function in Section IV.C for more information.) Alternatively, we can calculate the annuity directly using the CL12X function. CL12X(x,n) calculates a general n-year certain and life annuity, payable monthly for the life of (x) or for n years, whichever is longer. In this case there is no certain period, so we just use 0 for n: 1. 50 [ENTER] 2: 50.000000 0 [ENTER] 1: 0.000000 2. {CL12X} 1: 10.895175 As you can see, we get the same result with CL12X(50,0) as we got with N12X(50)/DX(50). Example 2.4 - Annuity payable at the end of each month ------------------------------------------------------ In the previous example, we used the CL12X(x,n) function to compute an annuity payable monthly with payments at the beginning of each month. Another function, CLMX(x,n,m), can be used to calculate certain and life annuities payable with an arbitrary payment frequency. You use a positive payment frequency m for annuities payable at the beginning of each (1/m)th of a year, and a negative m for annuities payable at the END of each (1/-m)th of a year. (Note: The fact that a negative payment frequency gives you annuities payable at the end of each payment period is a consequence of the mathematical definitions of the actuarial functions, not a special case of the CLMX function.) For example, suppose we wish to calculate the same annuity as in the previous example, but with payments at the END of each month. To do this, we use the CLMX function with a payment II. Examples 18 QLIB/48 User's Guide frequency of -12: ----- Keystrokes ----- ------ Display ------- 1. 50 [ENTER] 3: 50.000000 0 [ENTER] 2: 0.000000 12 [+/-] [ENTER] 1: -12.000000 2. [QMAIN][NXT][NXT]{CLMX} 1: 10.811842 Example 2.5 - Annuity payable quarterly with a certain period ------------------------------------------------------------- The example below calculates the annuity CLMX(65,10,4), which - is payable for the life of a 65-year-old; - pays $0.25 at the beginning of each quarter ($1 total per year); and - is guaranteed to be paid for at least ten years (40 payments). (Note: 8% UP84 sb2 is assumed, as in the previous examples.) ----- Keystrokes ----- ------ Display ------- 1. 65 [ENTER] 3: 65.000000 10 [ENTER] 2: 10.000000 4 [ENTER] 1: 4.000000 2. {CLMX} 1: 9.335666 C. LIFE INSURANCES; USER-DEFINED FUNCTIONS; PROGRAMS ---------------------------------------------------- Example 2.6 - Setting new assumptions ------------------------------------- Suppose we wish to calculate the net annual premium for a whole life insurance to a 30-year-old female (age nearest birthday), using the 1980 CSO mortality table and 7% interest. In addition, let's use a radix of 1,000,000 (one million) for the commutation functions rather than the default of 1,000,000,000 (one billion). First, we must change the assumptions we used in the previous examples to reflect the new assumptions: QLIB/48 User's Guide 19 II. Examples 1. Press {ASSU} to change to the Assumption Menu. 2. Enter 7 and press {INT} to set the new interest rate. 3. Enter 1000000 (or 1E6) and press {RADIX} to set the new radix. 4. Press {X/Y} to select the new mortality table for the X functions, and press the {F80CS} menu key to select the Female 1980 CSO (ANB) mortality table. 5. You should now see the following assumption display: +----------------------+ |-- ACTUARIAL ASSUMP --| |X: Female 1980 CSO ANB| |Y: (no table) | |x-y=0 R:1.000E6| |int=7% LIN| |----------------------| | | |== == == == == ==| +----------------------+ Note that QLIB/48 automatically removed the two-year setback we specified for the previous examples. 6. Press {EXIT} to return to the MAIN Menu. Example 2.7 - Calculating the net premium from the keyboard ----------------------------------------------------------- Let's assume the whole life insurance pays $1000 at the end of the year of death, with premiums payable for life at the beginning of each year. The formula for the premium is therefore '1000*MX(30)/NX(30)' and can be computed as follows: ----- Keystrokes ----- ------ Display ------- 1. 30 [QMAIN][NXT]{MX} 1: 8,482.653782 2. 30 [<][PREV]{NX} 2: 8,482.653782 1: 1,819,659.57413 3. [/] 1: 0.004662 4. 1000 [*] 1: 4.661671 Thus the net annual premium, to the nearest penny, is $4.66. II. Examples 20 QLIB/48 User's Guide Note that the "Calculating...X" message appeared when you pressed {MX} in step 1, indicating that the new assumptions you specified were being calculated. Example 2.8 - Calculating using a program ----------------------------------------- Another way to calculate the net premium in the previous example is to store the steps of the calculation in a program, and then execute the program: ----- Keystrokes ----- ------ Display ------- 1. [<] [<< >>] 30 [NXT] 1: \<< 30.000000 MX {MX} 30 [<][PREV] {NX} 30.000000 NX / [/] 1000 [*] [ENTER] 1000.000000 * \>> 2. [EVAL] 1: 4.661671 (Note: The program delimiters are represented above by their TIO 3 character sequences "\<<" and "\>>".) Example 2.9 - Calculating using an algebraic expression ------------------------------------------------------- Similarly, we can calculate the premium by entering the entire formula for it as an algebraic expression, and then evaluating the expression: ----- Keystrokes ----- ------ Display ------- 1. ['] 1000 [*] [NXT] {MX} 1: '1000.000000*MX(30) 30 [->] [/] [<][PREV] /NX(30)' {NX} 30 [ENTER] 2. [EVAL] 1: 4.661671 QLIB/48 User's Guide 21 II. Examples Example 2.10 - Using the EquationWriter to build the algebraic -------------------------------------------------------------- The algebraic expression in the previous example can also be created by using the EquationWriter. This is done in the following manner: 1. Change to the MAIN Menu by pressing [QMAIN] if necessary. You must be in the MAIN Menu BEFORE starting the EquationWriter, because your [QMAIN] key will not work inside the EquationWriter. 2. Press [<][EQUATION] to start the EquationWriter. 3. Type 1000 [*] to enter the start of the expression. 4. Press [up] (the up arrow) to begin entering the numerator of the fraction. Press [NXT] {MX} 30 [->] to enter the MX(30) numerator. 5. Press [->] again to move the cursor to the denominator, and then type [<][PREV] {NX} 30 [->] to enter the denominator. 6. Your screen should now look something like this: MX(30) 1000.------ NX(30)[] (Note: [] represents the cursor.) 7. Press [ENTER] to store the formula and return to the ordinary stack display. You should see the formula in stack level 1: [ENTER] 1: '1000.000000*(MX(30 )/NX(30))' 8. As in Example 2.9, you can use [EVAL] to evaluate the expression: [EVAL] 1: 4.661671 Example 2.11 - Creating a user-defined function ----------------------------------------------- What if we wanted to calculate the net annual premium for many different issue ages? The methods used in the preceding examples, which require several keystrokes just to do one calculation, would get very tedious. A better way to do it would be to create a user-defined function, and then use that function as many times as is needed to calculate all the premiums. II. Examples 22 QLIB/48 User's Guide 1. To create a user-defined function, first enter a formula for the function, using the variable X (or any variable) for the issue age: ----- Keystrokes ----- ------ Display ------- ['] [a][a] PX [<][()] 1: 'PX(X)=1000.000000* X [a] [->] [<][=] 1000 MX(X)/NX(X)' [*] [NXT] {MX} [a] X [->] [/] [<][PREV] {NX} [a] X [ENTER] 2. Use the DEFINE command (on the left-shifted [STO] key) to create the user-defined function. This creates a variable named 'PX' containing the code for the function. [<][DEF] 1: 3. We can now use the PX function to calculate the premium for issue age 30, or any issue age: 30 [VAR] {PX} 1: 4.661671 Note that PX, unlike NX, is simply a variable and is not part of the QLIB/48 library. However, once you have defined it, you can use it from the keyboard and in algebraic expressions and programs, just as you would use any of the built-in QLIB/48 functions. The user-defined function is available in the directory in which it is stored, and in subdirectories of that directory (although it will not appear on the VAR menu of subdirectories). The ability to create user-defined functions is a very powerful feature of the HP 48 calculator that will allow you to create virtually any actuarial function imaginable. There are hundreds of actuarial functions in common usage--life insurances, annuities, pure endowments, endowment insurances, annual premiums, single premiums, increasing annuities, etc. QLIB/48 couldn't possibly implement all of these functions without becoming prohibitively large. Instead, QLIB/48 attempts to provide you with the most basic building blocks, from which you can create the functions you need. The sample programs presented in Chapter VIII are actually directories of user-defined functions that, when downloaded to your HP 48, can be used in the same way we used our PX function in this example. QLIB/48 User's Guide 23 II. Examples D. JOINT-LIFE FUNCTIONS ----------------------- Example 2.12 - Setting joint-life assumptions --------------------------------------------- In this section, we'll use all three tables--the primarily life table X, the secondary life table Y, and the joint-life table J--to compute a 100% joint-and-survivor, or joint-last-to-die, annuity. Let's assume the annuity is payable to a husband age 59 and a wife age 65, and it is to be valued using the 1983 Group Annuity Mortality Table (1983 GAM) and 7.25% interest. First, set the appropriate assumptions: 1. Press {ASSU} to change to the Assumption Menu. 2. Enter 7.25 (or .0725) and press {INT} to set the interest rate. 3. Press [<]{RADIX} or enter 1E9 {RADIX} to reset the radix to the default of 1,000,000,000. However, in the examples of this section, we will be only calculating annuities (which are ratios of commutation functions), not explicit commutation functions, so the actual magnitude of the radix does not matter. 4. Press {X/Y} to select the X mortality table, and then select the Male 1983 GAM table with the {M83G} menu key. 5. Press [<]{X/Y} to select the Y mortality table, and select the Female 1983 GAM table by pressing {F83G}. (Notice that in this instance the first key of the selection menu is {Y:} to remind you that you are selecting a table to be used for Y.) 6. Now, in order for QLIB/48 to be able to compute joint-life annuities, it must know the difference in ages between the primary and secondary annuitants. In this example, the age difference is 59-65=-6. This is easy enough to calculate manually, but you can also do it on the calculator: ----- Keystrokes ----- ------ Display ------- 59 [ENTER] 1: 59.000000 65 [-] 1: -6.000000 Notice that as soon as you pressed [ENTER] the Assumption II. Examples 24 QLIB/48 User's Guide screen disappeared and the normal stack display reappeared. This illustrates that the Assumption Menu is not a program that is "running," but is rather just like any other menu on the calculator, except that it normally hides the stack display behind a display of the current assumptions. 7. Now that we have the age difference -6 in stack level 1, press the {X-Y} menu key to set the age difference assumption. You should now see the updated assumption display: +----------------------+ |-- ACTUARIAL ASSUMP --| |X: Male 1983 GAM | |Y: Female 1983 GAM | |x-y=-6 R:1.000E9| |int=7.25% LIN| |----------------------| | | |== == == == == ==| +----------------------+ 8. We can now leave the Assumption Menu. However, instead of just pressing {EXIT}, try pressing [>]{EXIT}. This will first calculate all three sets of assumptions (X, Y, and J), and then return to the MAIN Menu. Calculating the assumptions now will save us the trouble of waiting for them to be calculated when we calculate the joint annuity. Example 2.13 - Calculating the 100% joint-and-survivor annuity -------------------------------------------------------------- The steps below calculate the present value of the annuity discussed in the previous example, using the formula 'CL12X(59,0)+CL12Y(65,0)-CL12J(59,0)'. Let's assume the annuity pays $100 at the beginning of each month, or $1200 per year, as long as either the husband or wife is alive. 1. Calculate the single-life annuity payable for the life of the husband: ----- Keystrokes ----- ------ Display ------- 59 [SPC] 0 {CL12X} 1: 10.379985 2. Calculate the single-life annuity payable for the life of the wife. The left-shifted {CL12X} menu key provides the CL12Y function, for the female table. Add the two annuities to get QLIB/48 User's Guide 25 II. Examples value of an annuity payable to BOTH the husband and the wife. 65 [SPC] 0 [<]{CL12X} 2: 10.379985 1: 10.417991 [+] 1: 20.797976 3. We now need to subtract an annuity that pays as long as both the husband and wife are alive, because they should receive only one payment while both are alive. The right-shifted {CL12X} menu key provides the CL12J function. The J table is always indexed by the age of the primary life, so we use the husband's age. QLIB/48 implicitly knows the age of the wife because of the -6 age difference assumption. 59 [SPC] 0 [>]{CL12X} 2: 20.797976 1: 8.999422 [-] 1: 11.798554 Thus, the 100% joint-and-survivor annuity factor is 11.798554. 4. Finally, we multiply by the amount of the annual payment: 1200 [*] 1: 14,158.264663 Thus, the present value of the annuity is about $14,158. Another way to do this calculation is to use the JS12 function in the ACTFUNC sample program (see Section VIII.B.2). Example 2.14 - Joint-life commutation functions ----------------------------------------------- When creating joint-life commutation functions, some actuaries define lJ(x) as (lX(x)*lY(y))/QRADIX. QLIB/48 does not do this. Instead, QLIB/48 starts with lJ(aJ)=QRADIX at the earliest valid age aJ of the joint-life table, and then builds the l's just as it would for a single-life table, using q's determined from the X and Y q's. (See Section V.D for more information.) The two methods will result in commutation functions of different magnitudes, but the difference will be a constant ratio. Thus, annuities and other ratios of commutation functions will match. To see why the two methods can result in lJ's of different magnitudes, note that with the (lX(x)*lY(y))/QRADIX method, the earliest possible lJ(x) will be less than QRADIX unless the initial ages of the X, Y, and J tables all coincide (after the II. Examples 26 QLIB/48 User's Guide Y initial age has been adjusted for the age difference). This happens because either lX(x) or lY(y) will be some number less than QRADIX because it already reflects one or more years of mortality rates. With QLIB/48's methodology, however, the earliest possible lJ(x) is BY DEFINITION equal to QRADIX. For example, using the assumptions from the previous example, suppose we wish to compute the probability that (59:65) will survive 5 years, to (64:70). The formula to calculate this is 'lJ(64)/lJ(59)'. Using the (lX(x)*lY(y))/QRADIX method to determine the lJ's, we have ----- Keystrokes ----- ------ Display ------- 1. 64 {lX} 1: 867,024,564.316 2. 70 [<]{lX} 2: 867,024,564.316 1: 890,800,121.422 3. [*] 1: 7.723456E17 4. 1E9 [/] 1: 772,345,587.169 5. 59 {lX} 65 [<]{lX} 2: 772,345,587.169 [*] 1E9 [/] 1: 849,984,063.412 6. [/] 1: 0.908659 Using the QLIB/48 lJ function, we get different values for the joint-life l's (compare step 5 above with step 8 below), but their ratios--the probability we wished to calculate--are identical. 7. 64 [>]{lX} 1: 772,906,549.293 8. 59 [>]{lX} 2: 772,906,549.293 1: 850,601,415.119 9. [/] 1: 0.908659 QLIB/48 User's Guide 27 II. Examples E. NON-ACTUARIAL FUNCTIONS -------------------------- Example 2.15 - Years, months, and days between two dates -------------------------------------------------------- In addition to the actuarial functions, QLIB/48 includes a few other functions that may be useful to actuaries. One of these, DTDIF, calculates the difference between two dates in complete years, months, and days. For example (assuming mm/dd/yy mode and 6 FIX mode are in effect): ----- Keystrokes ----- ------ Display ------- 1. 1.181973 [ENTER] 2: 1.181973 7.041976 [ENTER] 1: 7.041976 2. [QMAIN][<][PREV]{DTDIF} 3: 16_d 2: 5_mo 1: 3_yr 3. [+] 2: 16_d 1: 3.416667_yr The time from 1/18/73 to 7/4/76 is 3 years, 5 months, and 16 days because 3 years takes you from 1/18/73 to 1/18/76, 5 more months takes you to 6/18/76, and finally 16 days takes you to 7/4/76. As step 3 shows, you can get the fractional number of years simply by pressing [+], because QLIB/48 treats a month as 1/12th of a year. The mo unit is not defined by the HP 48, probably because the number of days per month varies. For actuarial work, however, a month is usually treated as 1/12th of a year, so QLIB/48 defines the mo unit this way. Example 2.16 - Linear interpolation ----------------------------------- The LTRP function can be used to do any kind of linear interpolation or extrapolation. For example, suppose you know the present value of some liability is $124,344 assuming 7% interest and $112,432 at 8%, and you wish to estimate the liability at 7.25% using linear interpolation. To do so, enter one of the known points (as a complex number), the x value to be interpolated, and then the other known point: II. Examples 28 QLIB/48 User's Guide ----- Keystrokes ----- ------ Display ------- 1. [<][()] 7 [<][,] 124344 1: (7.000000, [ENTER] 124344.000000) 2. 7.25 [ENTER] 2: (7.000000,124344.0... 1: 7.250000 3. [<][()] 8 [<][,] 112432 3: (7.000000,124344.0... [ENTER] 2: 7.250000 1: (8.000000, 112432.000000) 4. [QMAIN][NXT][NXT][NXT] 1: 121,366.000000 {LTRP} Example 2.17 - Linear interpolation with points one unit apart -------------------------------------------------------------- In the previous example, the x values of the known points were exactly a distance of 1 apart. An easier way to use the LTRP function in this case is to enter only the y values of the known points, and for the value to be interpolated enter the distance from the first point, 0.25 (7.25-7), rather than 7. For example: ----- Keystrokes ----- ------ Display ------- 1. 124344 [ENTER] 1: 124,344.000000 2. .25 [ENTER] 2: 124,344.000000 1: 0.250000 3. 112432 [ENTER] 3: 124,344.000000 2: 0.250000 1: 112,432.000000 4. {LTRP} 1: 121,366.000000 QLIB/48 User's Guide 29 III. Assumptions III. ASSUMPTIONS ================ A. INTRODUCTION --------------- This chapter describes the assumptions available in QLIB/48, and the various ways of setting them. Assumptions must be specified before you can compute actuarial functions. Basically, there are two ways of setting assumptions: by the Assumption Menu, or by the assumption store/recall commands in the Command Menu. The store/recall commands are useful for recalling and setting assumptions within a program, and can also be used directly from the keyboard. In most cases, however, you will probably want to set your assumptions directly from the keyboard using the Assumption Menu. B. SUMMARY OF ASSUMPTIONS ------------------------- The table below lists the assumptions available in QLIB/48, and the Assumption Menu keys and commands (from the Command Menu) used to set them: Assump Menu Recall Store Assumption Key Command Command ---------- ----- ------- ------- Interest rate {INT} QINT QINTSTO UDD or LIN mode {UDD} QUDD QUDDSTO X life mortality table {X/Y} QTBLX QTBLXSTO X table setback {SB} QSBX QSBXSTO Y life mortality table [<]{X/Y} QTBLY QTBLYSTO Y table setback [<]{SB} QSBY QSBYSTO Age diff. for joint-life table {X-Y} QXMY QXMYSTO Initial number of lives (radix) {RADIX} QRADIX QRADIXSTO Terminal age truncation {Tw} QT\Gw QT\GwSTO C. THE ASSUMPTION MENU ---------------------- The Assumption Menu displays the current set of assumptions and allows you to interactively change those assumptions. To activate the Assumption Menu, press the {ASSU} menu key from III. Assumptions 30 QLIB/48 User's Guide the MAIN or K Menu, or execute the QASSU command. To review your current assumptions without actually changing to the Assumption Menu, press [>]{ASSU} or execute the command QADISP. The Assumption Menu displays a screen that looks like this: +----------------------+ |-- ACTUARIAL ASSUMP --| 1 |X: Male 1983 GAM sb2 | 2 |Y: Female 1983 GAM | 3 |x-y=3 R:1.000E9| 4 |int=7.25% Tw111 LIN| 5 |----------------------| | | <- Entry Area |== == == == == ==| <- Menu Keys +----------------------+ The menu has the following menu keys (press [NXT] to toggle between the pages): {X/Y} {SB} {X-Y} {INT} {RADIX} {EXIT} (page 1) {Tw} {UDD} {DISP} {EXIT} (page 2) The {SB}, {X-Y}, {INT}, {RADIX}, and {Tw} keys are white (inverse) menu keys, similar to variable keys you would see in the HP Solve environment. With these keys, you must first enter the desired numeric value of the assumption BEFORE pressing the menu key. The number will appear in the Entry Area as you type it. Note that the Assumption Menu does not put the HP 48 in any kind of special mode. It is just another menu, but with the additional effect of refreshing the assumption screen every time an assumption is changed. (The [<][PLOT] menu is an example of a similar menu on the HP 48.) Even though the stack is usually hidden by the assumptions display, it is still there and any stack operation can still be performed. You can clear the assumption display at any time by pressing [ON] or by performing any ordinary calculator operation, and refresh it by pressing [>]{X/Y} or {DISP}. After specifying your assumptions (as will be described below), press {EXIT} to leave the Assumption Menu and return to the MAIN Menu. The assumptions will be calculated the first time you use them for an actuarial calculation. Pressing [>]{EXIT} will first execute QCALC to recalculate the assumptions that have changed (X, Y, and/or J), before returning to the MAIN Menu. [<]{EXIT} will execute QUCALC to recalculate all assumptions regardless of whether they have changed or not. QLIB/48 User's Guide 31 III. Assumptions C.1 Mortality Tables: The Table Selection Menu ---------------------------------------------- The {X/Y} key is used to specify the primary (X) and secondary (Y) mortality tables (QTBLX and QTBLY). Press {X/Y} to set the X table, or [<]{X/Y} to set the Y table. This switches you to the Table Selection Menu, a menu of the available mortality tables based on the QTL library you have installed. Press one of the menu keys to select the desired table and return to the Assumption Menu. (If you wish to use a table stored in a variable, you must use the QTBLxSTO command; see Section III.D for more information.) Note that changing the mortality table also automatically resets the setback, if any, to zero. The first menu key in the Table Selection Menu will be {X:} or {Y:}, to indicate which table you are selecting. Also, pressing {X:} or {Y:} will return you to the Assumption Menu without changing your table. Pressing [<]{x:} executes a QTBLxSTO command to store a table name from stack level 1, and [>]{x:} executes a QTBLx command to recall the current table name to the stack (x=X,Y). See Section III.D for more information on these commands. C.2 Setbacks ------------ The {SB} menu key allows you to specify the age setback for the X or Y table (QSBX or QSBY). Type in the desired setback (it will appear in the Entry Area) and press {SB} to change the X setback, or [<]{SB} to change the Y setback. To specify a setforward, enter a negative setback. To remove a setback, enter zero. Lines 2 and 3 of the display show the setbacks you have specified, following the titles of the mortality tables. The titles will be truncated, if necessary, so you are always guaranteed to see the full setback. Positive setbacks are shown as "sb" and negative setbacks (setforwards) are shown as "sf". Zero setbacks are not displayed. Setbacks permit you to shift the mortality rates for the entire table down to earlier ages (setforward) or up to later ages (setback). For example, a 2 year setback shifts the age 40 rate for a table from age 40 to age 42, so that a 42-year-old life under the new table has the same chance of dying in the next year as a 40-year-old under the original (sb0) table. Setbacks therefore DECREASE the level of mortality and setforwards INCREASE mortality (that is, if the mortality rates are increasing, as is usually the case). For more information on setbacks, see Section V.C. III. Assumptions 32 QLIB/48 User's Guide C.3 Age Difference ------------------ The {X-Y} menu key specifies the age difference (QXMY) for the joint-life mortality table J. An age difference of 3, for example, means the secondary (Y) life is 3 years younger than the primary (X) life. Note that the entire J table is based on a single age difference. To calculate joint-life values for lives a different number of years apart in age, you must change the age difference. Each change in the age difference causes the J assumptions to be recalculated. To change the age difference, enter the desired value, and press {X-Y}. The new age difference will be shown in line 4 of the display. Pressing [<]{X-Y} resets the age difference to zero. [>]{X-Y} will recall the current age difference to the stack. C.4 Interest Rate ----------------- To change the interest rate (QINT), enter the value and press {INT}. The interest rate may be entered as a decimal (e.g., .0725) or as a percentage (7.25). (QLIB/48 treats values below .25 as decimals and any other values as a percentages.) Either way, the interest rate is displayed as a percentage, so you can verify that the value you intended was stored. Pressing [>]{INT} will recall the current interest rate (as a decimal) and redisplay the stack. C.5 Radix --------- The radix (QRADIX) is the initial number of lives assumed to exist at the initial age of the mortality table. The radix does not affect the calculation of annuities, life insurance premiums, or other ratios of commutation functions (as long as the radix is nonzero), but you may want to change it to get commutation values of a desired magnitude. The default value is 1,000,000,000 (1E9). To change the radix, enter the desired value and press {RADIX}. The radix is shown in line 4, preceded by "R:". The radix is always shown in 3 ENG mode. Additional digits of precision may exist, but they are not displayed. The radix can be recalled to the stack for review by pressing [>]{RADIX}. Pressing [<]{RADIX} resets the radix to its default value (1E9). QLIB/48 User's Guide 33 III. Assumptions C.6 Terminal Age Truncation Option ---------------------------------- The terminal age truncation assumption (QT\Gw) permits you to specify an age beyond which tables are not permitted to extend. If the terminal age of the table would otherwise exceed the Tw ("T-omega") value, mortality rates at the end of the table are discarded to force the desired terminal age. For more information, see Section V.C. You will probably not need the terminal age truncation option for most applications. It is provided to aid in matching commutations calculated with tables truncated at a fixed age, regardless of the age setback. To set a truncation age, enter the desired age and press {Tw}. To clear the truncation age so mortality rates are never discarded (the default), press [<]{Tw}. Press [>]{Tw} to recall the current truncation age to the stack (a value of 9.99999999999E499, the largest number the calculator can represent, indicates that no truncation will take place). C.7 UDD/LIN Mode ---------------- The {UDD} menu key toggles between UDD and LIN mode. This determines whether commutation functions for nonintegral ages are determined assuming uniform distribution of deaths (UDD) or by simple linear interpolation (LIN). In addition, UDD/LIN mode determines whether NMX(x,m) should be calculated based on a true UDD assumption, or by using the common NX(x)-(m-1)/(2*m)*DX(x) approximation (LIN mode). For more information on UDD/LIN mode, see Sections IV.F and IV.G and the descriptions of the NMX, MMX, and qJ functions in Section IV.C. The default is LIN mode. [>]{UDD} recalls the current mode value to the stack. 0 indicates LIN mode and any nonzero value indicates UDD mode. [<]{UDD} stores the value from level 1 of the stack as the UDD/LIN mode indicator. D. ASSUMPTION RECALL/STORE COMMANDS ----------------------------------- This section describes the assumption recall and store commands. These commands enable you to recall and change assumptions from within a program. All of the commands are available in the Command Menu (press [<]{ASSU} or {CMDS}). The unshifted menu key is the recall function, and the left-shifted key is the store command. (The right-shifted menu keys have III. Assumptions 34 QLIB/48 User's Guide various other uses.) QINT QINTSTO QUDD QUDDSTO Command: QSBX QSBXSTO QSBY QSBYSTO QXMY QXMYSTO QRADIX QRADIXSTO QT\Gw QT\GwSTO ------ --------- Stack Diagram: --> real real --> These commands store or recall the real-value numeric assumptions. The recall commands may be used in algebraic expressions; for example, '(1+QINT)^-5' and 'QRADIX*qX(\GaX)'. QINT and QINTSTO always treat the interest rate as a decimal; for example, .0725 and NOT 7.25 for 7.25% interest. Note that this is different from the {INT} key in the Assumption Menu, which DOES permit interest rates to be entered as percentages. For QUDD/QUDDSTO, zero indicates LIN mode and any nonzero value indicates UDD mode. For the X and Y age setbacks, a negative setback is an age setforward. Use a zero setback for no age adjustment. Use 'S' QT\GwSTO to delete a terminal age truncation option you previously specified. When no terminal age truncation is in effect (the default), QT\Gw will return 9.99999999999E499, the largest real number the HP 48 can represent. Command: QTBLX QTBLXSTO QTBLY QTBLYSTO ----- -------- Stack --> xlibqname xlibqname --> Diagram: --> pathqname { xlibqname } --> pathqname --> 'var' --> These commands set and recall the X and Y mortality assumptions. An xlibqname is the name (called an XLIB name, in HP 48 parlance) for a table stored in your QTL library. Since there is no direct way to put an xlibqname on the stack (the HP 48 will evaluate the xlibqname and return the table itself, not its name, to the stack), the QTBLxSTO commands permit the xlibqname to be enclosed in a list. For example, to write a program to set the X table to UP-1984: QLIB/48 User's Guide 35 III. Assumptions CORRECT: \<< { UP84 } QTBLXSTO \>> INCORRECT: \<< UP84 QTBLXSTO \>> The Table Menu ({TBLS} key) is a menu of all the xlibqnames in your QTL library. The QTABLES command will return a list of the xlibqnames. A pathqname is a path (a list of subdirectories starting with HOME and ending with a variable name) to a variable containing the desired qtable (see Section V.A for the correct qtable format); for example, { HOME MYTABLES PENSION TABLE1 }. If the variable is in the current directory, you may simply pass the variable name ('TABLE1'), and it will automatically be expanded to a full pathqname. QLIB/48 always stores absolute path lists. This allows 'Qpar' variables to be moved between directories without affecting the results of calculations. See Example 7.5 for an example of storing a mortality table in a variable. ** NOTE! ** If you change the mortality rates stored in a qtable, you must either delete the affected Qpar variables and respecify the assumptions, or manually recalculate the assumptions using QUCALC. QLIB/48 only looks at the NAME of the X or Y mortality table to determine whether a recalculation is necessary. See Section V.B for more information. Note that the QTBLxSTO commands do not automatically reset the age setback to zero as the Assumption Menu does when you select a new mortality table from the Table Selection Menu. The QTBLx commands return the name (xlibqname or pathqname) of the current X or Y mortality table. To get the actual contents of the qtable, use the QGETTBL command; for example, \<< QTBLX QGETTBL \>>. Do not use \<< QTBLX EVAL \>>, as this will change the current directory path if the table is a pathqname. Command: QCURRCL QCURSTO ------- ------- Stack Diagram: --> currassu currassu --> QCURRCL and QCURSTO recall and store the entire set of current assumptions as a single list. The format of the currassu list is shown below. The names of the assumption recall commands, in lower case, are used to represent the assumptions. { qint qudd qtblX qsbX qtblY qsbY qxmy qradix qTw } The individual assumptions are in the same order as the assumption commands in the Command Menu, so you can use the Command Menu as a guide when working with the QCURRCL and QCURSTO commands. III. Assumptions 36 QLIB/48 User's Guide The rules for specifying each assumption for QCURSTO are identical to the rules for the individual assumption store commands. E. ADDITIONAL ASSUMPTION COMMANDS --------------------------------- The following commands perform additional functions related to setting and calculating assumptions. These commands are all available in the Command Menu ({CMDS} key). QADISP Displays current assumptions, without changing to the Assumption Menu. QADISP is available in the Command Menu, and on the [>]{ASSU} key. QCALC Makes sure the current assumptions are completely calculated (same as pressing the [>]{EXIT} key while in the Assumption Menu). QUCALC Recalculates ALL assumptions, regardless of whether or not QLIB/48 thinks they have changed. [<]{EXIT} in the Assumption Menu performs the same function. QDIRCUR Makes sure the current assumptions (i.e., the Qpar variable) are stored in the current directory. Normally, QLIB/48 accesses or changes the assumptions in the first Qpar variable it can find in the current directory or a parent directory. This is normally desirable, as it prevents multiple Qpar variables from being created. QDIRCUR forces the current assumptions to be stored in a Qpar variable in the current directory. If there are no assumptions, a default (empty) set is stored. QDIRCUR assumes you intend to change the assumptions, and therefore discards any calculated values (N's) before creating the new Qpar variable. However, Qpar variables in parent directories are not affected. See Section F below for more information on Qpar variables. QGETTBL Converts the output from a QTBLx command or any other valid QTBLxSTO command input to the corresponding qtable. See Section V.A for information on qtables. QLIB/48 User's Guide 37 III. Assumptions QTABLES Returns a list of the mortality tables in the QTL library. QTABLES is actually part of in the QTL library itself, not the QLIB/48 program library. F. THE Qpar VARIABLE -------------------- QLIB/48 stores your current assumptions, the calculated N commutation values for each table (X, Y, and J), and the assumptions that produced the calculated N's, in a special Library Data object stored in the variable 'Qpar'. You cannot directly manipulate the contents of the Library Data object. However, Qpar variables may be moved, copied, purged, and downloaded just as you would any ordinary variable. Each Qpar variable effectively creates an "actuarial universe" (set of assumptions) for the directory in which the Qpar variable resides, and for all subdirectories of that directory which do not have Qpar variables of their own. Each time an actuarial function is invoked, QLIB/48 uses the assumptions stored in the first Qpar variable it can find in the current directory or in the nearest parent directory. F.1 Contents of the Qpar Variable --------------------------------- Each Qpar variable contains the following information: currassu current set of assumptions calcassuX X table calculated assumptions calcassuY Y table calculated assumptions calcassuJ J table calculated assumptions anX calculated N's for X table anY calculated N's for Y table anJ calculated N's for J table Each time you use an actuarial function, the appropriate calcassux (x=X,Y,J) is compared to currassu. If they don't match, anx is recalculated using the current assumptions, and calcassux is set equal to currassu. This scheme allows the calculation of the N's (in anx) to be deferred to the last possible moment, eliminating any unnecessary calculations. It also allows you to, for example, temporarily change the interest rate for a calculation with the X table, and then change the interest rate back to the original value, without affecting the need to recalculate the Y and J assumptions. (This scheme is used by the PBGC sample program, for example; see Section VIII.E.2.) III. Assumptions 38 QLIB/48 User's Guide F.2 Storing the Qpar Variable ----------------------------- Qpar variables can be large--3000 bytes or more with a full set of calculated assumptions for X, Y, and J. If a memory is at a premium, a useful approach is to store the Qpar variable in the HOME (root) directory. This way there will only be one Qpar variable, and it will be used from all subdirectories (provided you never execute the QDIRCUR command). To create a single Qpar variable in the HOME directory, first delete all Qpar variables in subdirectories. Then switch to the HOME directory and define any set of assumptions. All future assumption changes will be made to the Qpar variable in the HOME directory. On the other hand, if you can afford the memory, you could create separate subdirectories for each client or project, and keep a Qpar variable in each subdirectory defined with the appropriate actuarial assumptions for that client or project. This saves you the trouble of respecifying the assumptions and waiting for them to be recalculated when you switch clients or projects. QLIB/48 User's Guide 39 IV. Functions IV. ACTUARIAL FUNCTIONS ======================= A. INTRODUCTION --------------- This chapter describes the functions available to you for performing actuarial calculations. QLIB/48 provides basic building-block commutation functions. You can define additional actuarial functions from these by making use of HP 48 user-defined functions. QLIB/48 can perform computations with three different mortality tables: the primary life table X, the secondary life table Y, and the joint-life table J. Mortality rates for the X and Y tables are specified by the tables you select when setting your assumptions. QLIB/48 calculates the mortality rates for the J table as the probability of the X life OR the Y life dying (see Section G below for more information). There is a separate version of each mortality-based actuarial function for each of the three tables, X, Y, and J. The last letter of the function indicates the table on which it operates. When a feature of an X table function is discussed in this manual, remember that an analogous comment will always hold for the Y and J versions of the functions. There is also a fourth K version of each function. The K functions take an additional argument k indicating which table to use: X (k=1), Y (k=2), or J (k=3). This allows you to write programs when you don't know ahead of time which table will be used. For direct calculations from the keyboard, however, it is easiest to use the individual X/Y/J functions. B. FUNCTION ARGUMENTS --------------------- B.1 Overview ------------ The QLIB/48 actuarial functions take zero or more real number arguments and return a real number result. In the lists in Sections C and D below, the functions are shown in function syntax. For example, the function CL12X(x,n) takes an age argument x and the number of years n in the certain period, and returns the n-year certain and life annuity at age x. Its stack diagram is x n --> annuity . IV. Functions 40 QLIB/48 User's Guide In addition, the order of function arguments generally follows the rule that similar functions have the same arguments in the same order, with additional arguments needed appearing at the end (i.e., in the lower levels of the stack). For example, NMX(x,m) is generalization of the NX(x) function, so it takes the age x as its first argument and the additional argument m as its second argument. Similarly, NMK(x,m,k) is a generalization of NMX(x,m), so the additional argument k appears at the end. B.2 Symbols Used ---------------- The following table summarizes the symbols used in the descriptions of the QLIB/48 functions: Symbol Use ------ --- aX initial age of X table wX terminal age of X table x age for X or J table; x >= aX or aJ y age for Y table; y >= aY z age for K function; z >= a(k) k table for calc: k = 1 (X), 2 (Y), or 3 (J) n period of n years m payment frequency (e.g., m=12 for monthly); m is assumed to be a nonzero integer B.3 General Rules That Apply to All Functions --------------------------------------------- 1) For x < aX the commutation functions will return an Undefined Result error. For aX <= x < wX, the normal commutation value is returned. For x >= wX, the commutation functions return 0. This enables you to write expressions like 'DX(x+n)/DX(x)' without concern for whether x+n will extend beyond the end of the mortality table. 2) Negative values of m can be used to calculate values assuming payment at the opposite endpoint of the (m)th. For example, 'NMX(x,-4)/DX(x)' is an annuity payable at the END of each quarter, and 'MMX(x,-12)/DX(x)' is a life insurance payable at the BEGINNING of the month of death. This is a consequence of the mathematical definitions of the actuarial functions, not a special case of the QLIB/48 functions. 3) When calculating values for the J table, enter the x age only. The y age is automatically implied by the QXMY (x-y) assumption you defined. For example, if QXMY=3 then 'DJ(20)' QLIB/48 User's Guide 41 IV. Functions is the D[20:17] value for the joint-life status (20:17). To calculate D[20:30] you must set QXMY to -10 and then calculate 'DJ(20)' again. For more information on calculations with the J table, see Section G below. 4) When using QLIB/48 functions in an algebraic expression, variables may be used in place of any argument. The HP 48 will automatically substitute the value of the variable when you evaluate the expression. Formal variables (variables without a stored value) are not allowed, however. Unlike the HP 48's built-in functions, QLIB/48 will not build a formal expression when a formal variable is passed to a function. Thus, \<< X DX \>> or 'DX(X)' will work just fine if a real number is stored in X, but \<< 'X' DX \>> will result in a Bad Argument Type error. 5) QLIB/48 does not define inverses or derivatives for the functions. Thus, QLIB/48 functions are not Analytic Functions in the sense defined by the HP 48. 6) The internal formula used to calculate the desired value is shown in the description of each function (generally in HP 48 and QLIB/48 syntax). The formulas are shown in terms of N's, since that is the basic function from which all mortality-based functions are calculated (except qX). For more information on how the basic array of N's is calculated, see Section V.F. 7) Calculations are performed internally using 15 digits of precision, and then rounded to the HP 48's standard 12 digits of precision before the final result is returned to the stack. 8) QLIB/48 does no other rounding of values it calculates; for example, commutation values are NOT rounded to the nearest integer. You must perform your own rounding for intermediate steps of a calculation, if any is needed. This gives you complete flexibility over how the calculation is performed. By using user-defined functions, you can easily implement functions using any rounding rules you like. C. MORTALITY-BASED FUNCTIONS ---------------------------- The mortality-based actuarial functions provided by QLIB/48 are summarized below. This manual assumes you are familiar with the meaning and use of these functions. For more information, consult a text on actuarial mathematics or life contingencies, such as one of those listed in Appendix B. IV. Functions 42 QLIB/48 User's Guide \GaX initial age of mortality table \GaY \GaJ \GaX = aX \GaK(k) \GaX is the initial age of the X table. For ages below this initial age, the commutation functions return an Undefined Result error. The function name is the Greek letter alpha, followed by X, Y, J, or K. \GwX terminal age of mortality table \GwY \GwJ \GwX = wX \GwK(k) \GwX is the terminal age of the X table. For ages greater than or equal to \GwX, the commutation functions return 0. The function name is the Greek letter omega, followed by X, Y, J, or K. CL12X(x,n) n-year certain and life annuity at age x CL12Y(y,n) payable at the beginning of each month CL12J(x,n) CL12K(z,n,k) CL12X(x,n) = CLMX(x,n,12) See CLMX for more information. CLMX(x,n,m) n-year certain and life annuity at age x CLMY(y,n,m) payable at the beginning of each (1/m)th CLMJ(x,n,m) CLMK(z,n,m,k) CLMX(x,n,m) = CM(n,m) + NMX(x+n,m)/DX(x) CLMX(x,n,m) is the present value of an annuity paying $1/m at the beginning of each (1/m)th of a year. The annuity pays for the life of (x), but at least for n years. For annuities payable at the END of each (1/m)th, use a negative m. For nonintegral ages, note that when using LIN (linear interpolation) mode, the NMX(x+n,m) and DX(x) commutation functions are interpolated, and then the annuity is computed. The integral age ANNUITIES are not interpolated. When you are using UDD mode and nonintegral ages with |m|>1, there is a small error in the calculation. See Section IV.F for more information. QLIB/48 User's Guide 43 IV. Functions CX(x) C commutation function CY(y) CJ(x) CX(x) = v*NX(x)-(1+v)*NX(x+1)+NX(x+2) CK(z,k) The CX(x) commutation function is usually described by the formula (lX(x)-lX(x+1))*v^(x+1) [lX(x)-lX(x+1) is the number of deaths between age x and x+1]. CX(x)/DX(x) is the net premium for a one-year term life insurance on (x) paying $1 at the end of the year if death occurs in the year. DX(x) D commutation function DY(y) DJ(x) DX(x) = NX(x)-NX(x+1) DK(z,k) The DX(x) commutation function is usually described by the formula lX(x)*v^x. DX(x+n)/DX(x), for example, is the present value of an n-year pure endowment, which pays $1 if (x) is alive at the end of n years. lX(x) l commutation function lY(y) lJ(x) lX(x) = DX(x)/v^x lK(z,k) The lX(x) commutation function is the number of people alive at age x out of the original cohort of QRADIX lives at the initial age aX. lX(x) can be used to do calculations not involving interest. For example, 'lX(x)-lX(x+1)' is the number of deaths between age x and x+1, and 'lX(x+1)/lX(x)' is the probability that (x) will survive the upcoming year. QLIB/48 calculates the lX functions by backing the interest factor out of the DX value. Therefore, QLIB/48 will force a recalculation every time you change the interest rate, even if you are only calculating lX values. Note that for nonintegral ages x, the value of lX(x) is the same whether UDD or LIN mode is set. UDD is BY DEFINITION linear interpolation of the lX(x) values. QLIB/48 can compute many other demographic functions by setting the interest rate to zero and using interest-based commutation functions. For example, TX(x) equals NMX(x,1E99) (within the precision of the calculator) assuming UDD and QINT=0. See Section VII.D for more information. IV. Functions 44 QLIB/48 User's Guide MX(x) M commutation function MY(y) MJ(x) MX(x) = v*NX(x)-NX(x+1) MK(z,k) The MX(x) commutation function is usually described as the sum of the CX values from x to the end of the table. For example, '(MX(x)-MX(x+20))/DX(x)' is the net single premium at age x for a 20-year term life insurance paying $1 at the end of the year in which death occurs. MMX(x,m) M(m) commutation function MMY(y,m) MMJ(x,m) MMX(x,m) = im(1)/im(m)*MX(x) MMK(z,m,k) The MMX(x,m) commutation function is used in calculating life insurances payable more frequently than once a year. For example, '(MMX(x,12)-MMX(x+20,12))/DX(x)' is the net single premium at age x for a 20-year temporary life insurance paying $1 at the end of the month in which (x) dies. For a life insurance payable at the BEGINNING of the (1/m)th of a year of death, use a negative m. For a life insurance payable at the moment of death, use a very large m, so that im(m) will equal \Gd (delta, the force of interest) within the precision of the calculator. An m of 1E99 is sufficiently large for this purpose. Note that regardless of the UDD mode setting, MMX(x,m) (for integral ages x) is calculated based on a true uniform distribution of deaths (UDD) assumption. For nonintegral x, the integral age MMX(x0,m) and MMX(x0+1,m) values are computed assuming UDD (because this is the assumption that implies the im(1)/im(m) adjustment at integral ages), and then the appropriate UDD/LIN interpolation formula is applied to calculate MMX(x,m) at the nonintegral age x. When you are using UDD mode and nonintegral ages with |m|>1, there is a small error in this calculation. See Section IV.F for more information. NX(x) N commutation function NY(y) NJ(x) NX(x) = NX(x) NK(z,k) The NX(x) commutation function is usually described by DX(x)+..., the sum of the D's from age x to the end of the table. It is used in calculating annuities payable at the QLIB/48 User's Guide 45 IV. Functions beginning of each year. For example, MX(30)/NX(30) is the net annual premium payable at the beginning of each year for a whole life insurance to (30). N12X(x) N(12) commutation function N12Y(y) N12J(x) N12X(x) = NMX(x,12) N12K(z,k) The N12X(x) commutation function is used in calculating annuities payable monthly. For example, the present value of an annuity paying $1 per month ($12 per year) for the life of a 50-year-old is 12*N12X(50)/DX(50). If UDD mode is set, N12X(x) is calculated based on a true UDD assumption. If LIN mode is set, the common NX(x)-11/24*DX(x) approximation is used. See the description of the NMX function and Section IV.F for more information. NMX(x,m) N(m) commutation function NMY(y,m) NMJ(x,m) NMX(x,m) = Am*NX(x)+Bm*NX(x+1) NMK(z,m,k) The NMX(x,m) commutation function is used in calculating annuities paying $(1/m) at the beginning of each (1/m)th of a year. For annuities payable at the END of each (1/m)th use a negative m. For annuities payable continuously, use a large m such as 1E99. This will produce the value of the annuity payable continuously within the precision of the calculator. If UDD mode is set, Am and Bm are calculated as follows: Am = (im(m)-dm(1))/(im(m)*dm(m)) Bm = (im(1)-im(m))/(im(m)*dm(m)) . For integral ages x (i.e., ages an integral distance from the initial age of the table), this provides an exact value of NMX(x,m) (within the precision of the calculator, of course) based on a uniform distribution of deaths assumption. For nonintegral ages with values of m other than 1 or -1, there is a small error in the calculation. See Section IV.F for more information. If LIN mode is set or if the interest rate is 0, NMX(x,m) is calculated using the common NX(x) - (m-1)/(2*m)*DX(x) approximation; that is, Am and Bm are defined as follows: Am = (m+1)/(2*m) Bm = (m-1)/(2*m) . IV. Functions 46 QLIB/48 User's Guide Note that the LIN mode Am/Bm are the limits of the UDD mode Am/Bm as QINT approaches zero. qX(x) probability of (x) dying within one year qY(y) qX(x)=1-(1-qX(b))/(1-t*qX(b))*(1-t*qX(b+1)), qJ(x) where x=b+t and b and t are defined such qK(z,k) that b=aX+n for some integer n, and 0<=t<1. The qX(x) function returns the probability that (x) will die within one year. qX(x) is calculated based on a true uniform distribution of deaths assumption, regardless of the current UDD/LIN mode setting. For integral ages x (i.e., ages an integral distance from the initial age aX: x=b=aX+n), qX(x) is simply the appropriate mortality rate directly from the table you specified in the assumptions. The domain of the qX(x) function is given by aX <= x < wX. Any other values of x will result in an Undefined Result error. For wX-1 <= x < wX, qX(x)=1. You can use the qJ function to examine the mortality rates that QLIB/48 calculated for the J table; namely, qJ(aJ), qJ(aJ+1), qJ(aJ+2), ..., qJ(wJ-1). When using the qJ(x) function, remember that for nonintegral x (i.e., when x-aJ is not an integer), QLIB/48 assumes a uniform distribution of terminations of the JOINT-LIFE STATUS (x:y), not the individual lives (x) and (y). Thus, qJ(x) = 1-(1-qX(x))*(1-qY(x-QXMY)) only holds true for integral x. In fact, the J table mortality rates are DEFINED by this formula at the X table integral ages, and then the J table is treated in exactly the same manner as the X and Y tables. The "lives" for the J table are the joint-life statuses. See Section IV.G below for more information. The qX, qY, and qJ functions directly access the necessary mortality tables, and therefore they do not force a recalculation of the assumptions. RMX(x,m) R(m) commutation function RMY(y,m) RMJ(x,m) RMX(x,m) = im(1)/im(m)*(NX(x)-(1-v)*Sx) RMK(z,m,k) where Sx = NX(x)+NX(x+1)+NX(x+2)+... For any age x, the RMX(x,m) commutation function is usually described as MMX(x,m)+MMX(x+1,m)+MMX(x+2,m)+..., the sum of the M(m)'s from age x to the end of the table. It is the standard R[x] commutation function generalized for insurance payable at (1/m)th of a year. For example, RMX(x,12)/DX(x) is the net single premium (present value) of a life insurance paying $1 if QLIB/48 User's Guide 47 IV. Functions death occurs in the first year, $2 if death occurs in the second year, etc., where the death benefit is paid at the end of the month in which death occurs. Note that even though the payment frequency is 12, the death benefit still only increases annually. To get the standard R[x] commutation, you must use RMX(x,1). When you are using UDD mode and nonintegral ages with |m|>1, there is a small error in the calculation. See Section IV.F for more information. Also see the description of the SMX function. SMX(x,m) S(m) commutation function SMY(y,m) SMJ(x,m) SMX(x,m) = Am*Sx+Bm*(Sx-NX(x)) SMK(z,m,k) where Sx = NX(x)+NX(x+1)+NX(x+2)+... The SMX(x) commutation is usually described as the sum of the N(m)'s from age x to the end of the table. SMX(x,12)/DX(x) is a present value of an annuity that pays $(1/m) at the beginning of each month in the first year, $(2/m) for each month in the second year, ..., and $(n/m) for each month in the nth year. Am and Bm are defined as they are for the NMX function. The RMX(x,m) and SMX(x,m) functions actually sum the necessary internal calculated N's to compute Sx. Thus, they are significantly slower than the other commutation functions, and the execution time is longer for lower ages. You will probably not notice the additional execution time in direct calculations from the keyboard, however. When you are using UDD mode and nonintegral ages with |m|>1, there is a small error in the calculation. See Section IV.F for more information. D. INTEREST-ONLY FUNCTIONS -------------------------- These functions are based on interest only, and so do not force a recalculation of any assumptions. IV. Functions 48 QLIB/48 User's Guide \Gd force of interest \Gd = LNP1(QINT) The function name is the Greek letter delta. Since \Gd is a QLIB/48 function, it cannot be used as a variable name. (See the description of the v function for more information.) CM(n,m) n-year certain annuity payable at the beginning of each (1/m)th CM(n,m) = (1-v^n)/dm(m) For annuities payable at the END of each (1/m)th of a year, use a negative m. dm(m) nominal discount rate compounded (m)thly dm(m) = im(-m) im(m) nominal interest rate compounded (m)thly im(m) = m*EXPM(LNP1(QINT)/m) Note: The EXPM portion of the calculation is only calculated to 12 digits of precision internally, rather than the usual 15. This should not matter for most uses since results are converted to 12 digits of precision before being returned to the user. This also affects the dm and CM functions, which use the im function internally. v interest discount factor v = INV(1+QINT) Note that since they are QLIB/48 functions, you cannot use v and \Gd as global variable names, much like e and i are unavailable because the HP 48 defines them as the mathematical constants 2.718... and (0,1). v and \Gd (and e and i, for that matter) can still be used as a local (temporary) variable names in your programs, however. QLIB/48 User's Guide 49 IV. Functions E. MISCELLANEOUS COMMANDS ------------------------- Linear interpolation LTRP((x0,y0),x,(x1,y1)) = (x1-x)/(x1-x0)*y0 + (x-x0)/(x1-x0)*y1 LTRP(y0,x,y1) = (1-x) *y0 + x *y1 LTRP interpolates between two points by linear interpolation. The first form interpolates (or extrapolates) between any two arbitrary points using the given formula. The second form is identical to the first form, except x0 is assumed to be 0 and x1 is assumed to be 1. For example, 'LTRP(100,.3,200)' is 130, 3/10ths of the way from 100 to 200. \<< (10,1400) 15 (18,1700) LTRP \>> calculates 1587.5, the point at x=15 on the line between the points (10,1400) and (18,1700). Note that the value of x need not lie between x0 and x1. For x outside of x0 and x1, the value is extrapolated using the formulas above. mo Month unit (1/12)_yr (i.e., 0.0833333333333_yr) The HP 48 does not include any time unit for months, since the number of days in a month varies. In actuarial work it is usually useful to think of a month as 1/12th of a year, so QLIB/48 defines the mo unit this way. DTBLD Build a date in the HP 48 date format d m y --> date The DTBLD command takes numbers for the day, month, and year from the stack and returns the corresponding HP 48 date number, respecting the current setting of system flag 42. For example, 18 1 1973 DTBLD returns 1.181973 if flag 42 is clear (mm.ddyyyy mode), and 18.011973 if flag 42 is set (dd.mmyyyy mode). If the arguments do not describe a valid date, an Invalid Date error occurs. DTBLD is [<]{DTDIF} on the MAIN Menu. DTBRK Break a date into day, month, and year date --> d m y The DTBRK command breaks up an HP 48 date (expressed in IV. Functions 50 QLIB/48 User's Guide mm.ddyyyy or dd.mmyyyy format, as indicated by system flag 42) into the day, month, and year numbers. DTBRK is [>]{DTDIF} on the MAIN Menu. DTDIF Compute complete years, months, and date1 date2 --> d_d m_mo y_yr days between two dates. The DTDIF command computes the number of complete years, months, and days (with units) between date1 and date2. For example, the time from 1/18/73 to 7/4/76 is 3 years, 5 months, and 16 days (see Example 2.15). The results of the DTDIF command are returned with units, so you can calculate the fractional number of years simply by pressing +. The results of \<< date2 date1 DTDIF \>> are the same as \<< date1 date2 DTDIF \>> except the years, months, and days have the opposite sign. F. NONINTEGRAL AGES ------------------- This section discusses issues pertaining to using mortality- based functions with nonintegral ages. F.1 Definition of "Integral Age" -------------------------------- When you specify mortality assumptions, the initial age of the table (after reflecting any setback) determines the ages to which the mortality rates (q's) apply. The q's of the table are the probabilities of death, in one year increments starting at the initial age. For example, if the initial age is 15, the first q is the probability of dying between ages 15 and 16, the second q is the probability of dying between ages 16 and 17 (assuming the life survived to age 16), and so on. Similarly, if the initial age is 7.3, the q's apply to ages 7.3, 8.3, 9.3, etc. These one-year ages (15, 16, ..., or 7.3, 8.3, ...) are called "integral ages" (even though they do not necessarily have to be integers). A "nonintegral age" is an age which is not an integral age. QLIB/48 User's Guide 51 IV. Functions F.2 Distribution of Deaths Between Integral Ages ------------------------------------------------ Basic commutation functions such as CX(x), DX(x), and NX(x) are directly computable from the q's at integral ages x. That is, their values depend only on the number of lives [lX(x)] at integral ages. The distribution of deaths between the integral ages does not affect the value. For nonintegral ages, however, the distribution of deaths between the integral ages DOES matter. For example, the value of DX(30.4) depends greatly upon how many of the lX(30)-lX(31) deaths between ages 30 and 31 occur before age 30.4. QLIB/48 allows you to assume a uniform distribution of deaths (UDD) between integral ages (i.e., lX(x) is assumed to be linear between integral ages). Other assumptions for the distribution of deaths, such as the constant force of mortality or Balducci assumptions, are not supported by QLIB/48. As an alternative to UDD, you may select LIN mode. In this mode, QLIB/48 uses simple linear interpolation when calculating ANY commutation function at a nonintegral age. This is commonly done in practical applications. The results in LIN mode are not in general identical to UDD mode, but the differences are negligible. LIN mode may be useful when attempting to match values calculated by other systems. Note that LIN mode is not a true (consistent) distribution of deaths assumption. F.3 Interpolation Formula ------------------------- The actual formula used to calculate commutation functions at nonintegral ages is given below. Let Z denote the desired commutation function. Let x=x0+t be the age at which Z is to be computed, where x0 is an integral age and 0<=t<1. Then Z(x) is given by Z(x) = Z(x0+t) = (1-t)*vu^t*Z(x0) + t*vu^(t-1)*Z(x0+1) , where vu is v for UDD mode or 1 for LIN mode (the above formula reduces to simple linear interpolation when vu=1). Note that since v=1 when QINT=0, UDD and LIN modes are identical when QINT=0. For example, if aX is 15 and LIN mode is in effect, the value of CX(55.7) is calculated as CX(55.7) = CX(55+.7) = .3*CX(55) + .7*CX(56) . Note that the integral-age values CX(55) and CX(56) are calculated based on the appropriate linear combination of N's IV. Functions 52 QLIB/48 User's Guide (see the description of CX above) BEFORE the interpolation is performed. F.4 Error in UDD Mode --------------------- There are two ways in which the UDD or LIN assumption is used: (1) when using the above interpolation formula to find the value of a function at a nonintegral age, and (2) when calculating the value of a function involving a payment frequency (m), such as NMX or MMX. The calculation routines used for (1) or (2) each individually provide the exact value of the function (within the precision of the calculator). However, when they are used together (for example, when N12X is calculated at a nonintegral age), there is a small error. One way of thinking of the error is that the formulas used to calculate values for |m|>1 at an age x=x0+t (where x0 is an integral age and 0<=t<1) are really based on the assumption that there is a uniform distribution of deaths between the ages x, x+1, x+2, .... The interpolation formula, on the other hand, assumes that the UDD assumption applies between the ages x0, x0+1, x0+2, .... When x is nonintegral, this inconsistency causes the error to arise. When x is an integral age, x=x0 and there is no error. It may be helpful to note that this is just the same error you would obtain if you applied the appropriate UDD formulas from Bowers, et al.--such as the formula for N(m)[x]--at a nonintegral age, using interpolated values of N[x] and D[x] (or whatever values are needed). These formulas assume that the UDD assumption applies between ages x, x+1, etc. Since this is inconsistent with QLIB/48's assumption that UDD applies between the INTEGRAL ages, the error arises. For ages not near the terminal age of the table, the amount of error is small. For example, the relative error in N12X (m=12) for 7% interest and the UP-1984 mortality table is as follows: Approx. Age Rel. Error ----------- ---------- 25 .003% 50 .01% 60 .01% 65 .008% 70 .003% 75 .03% 80 .1% 90 .6% 100 4% 110 87% QLIB/48 User's Guide 53 IV. Functions The relative errors shown are the maximum errors for ages near the given integral age (the error at the integral age itself is 0 of course). Similar errors are obtained for other mortality tables and other commutation functions. The large relative error for ages near the terminal age of the table (112 for UP-1984) may not be such a large concern, because mortality tables which artificially impose some terminal age are known to not give very accurate results near the terminal age anyway. Thus, even though the calculations may depart from a true UDD methodology, there probably isn't any particular reason to believe the UDD assumption is a good one at such high ages. This section is not meant to cause you concern, but only to point out that if you're interesting in sticking to the letter of the law with the uniform distribution of deaths assumption, you should be aware of this inconsistency. Since the amount of error is small and only arises for nonintegral ages, and because avoiding the error would have added significantly to the complexity of the calculations, I made the choice to accept the slight inconsistency in order to obtain a smaller and faster program. It appears unlikely that this will affect how actuaries are likely to use QLIB/48 in practice. Finally, remember that the error occurs only when the age is nonintegral (i.e., a nonintegral distance from the initial age) and the payment frequency is not 1 or -1. In all other cases, the error is zero. In particular, note that all functions that do not reflect a payment frequency, such lX, DX, NX, CX, and MX, are always calculated with no error. Also, the comments in this section are not applicable to LIN mode, where all commutation functions, regardless of payment frequency, are BY DEFINITION determined using linear interpolation between integral ages. G. THE JOINT-LIFE TABLE ----------------------- QLIB/48 provides the J table for calculating joint-life commutation functions. The J table is handled internally exactly like the single-life X and Y tables. The only difference is the J table mortality rates are calculated from the X and Y rates, rather than coming directly from a stored mortality table. Section V.D describes how this is done. Mortality-based QLIB/48 functions for the J table are indexed by the X (primary life) age. QLIB/48 knows the Y (secondary life) age implicitly, from the age difference assumption (QXMY) that you define. IV. Functions 54 QLIB/48 User's Guide It is important to remember that once QLIB/48 has calculated the qJ mortality rates, the J table is handled EXACTLY like the X and Y tables. This has the following consequences, for instance: 1) A cohort of QRADIX joint-life statuses is assumed at the initial age aJ. The lJ's are not computed as (lX*lY)/QRADIX, as some actuaries do. This may mean that you won't match the commutation functions computed outside of QLIB/48. However, annuities, net premiums, and any other actuarial values which age computed as ratios of commutation functions will still match. (See Example 2.14.) 2) When using UDD mode, remember that since QLIB/48 treats the J table as essentially a third single-life table, values at nonintegral J table ages are calculated assuming a uniform distribution of TERMINATIONS OF THE JOINT-LIFE STATUS. This is NOT the same as assuming the individual X and Y lives follow UDD. For example, if the X and Y tables are both UP-1984 with no setback and QXMY=2, then qX(90.2) = .185103 (rounding to 6 places) qY(88.2) = .157425 but qJ(90.2) = .312779 <> .313388 = 1-(1-.185103)*(1-.157425) . Note that this will affect you only if you use UDD mode with nonintegral ages or with payment frequencies greater than 1. The above calculation will always match for integral ages because this is how the qJ values are DEFINED. QLIB/48 User's Guide 55 V. Mortality Tables V. MORTALITY TABLE DEFINITIONS AND CALCULATIONS =============================================== This chapter describes how mortality tables are defined and stored for use with QLIB/48, and how assumptions such as age setbacks modify the mortality rates used in calculations. The last section describes how the N commutation function values are calculated from the mortality rates. A. MORTALITY TABLE FORMAT ------------------------- QLIB/48 mortality tables are stored as HP 48 list objects, in the following format (called the "qtable" format): { "title" a0 [ q's ] } The "title" is a string containing the table title. The title is displayed by the Assumption Menu when the table is selected. The title should be short, since the assumption screen will display at most 19 characters (and fewer than that if a setback is defined). The initial age a0 is the age at which it the table starts. It may be any real number. [ q's ] is a single-dimensional array of the mortality rates that make up the table. Each rate q in the array is assumed to satisfy the inequality 0<=q<1. The first element of the array is the mortality rate q(a0), the second is q(a0+1), and so on. In addition, there is assumed to be an implicit mortality rate of 1 (not included in the [q's] array) at the end of the table. The ensures that the mortality table will have a terminal age; that is, an age at which all lives are assumed to have died. For example, suppose the X table is assigned to the following table (with no setback or terminal age truncation): { "Sample Table" 1 [ .1 .2 .3 .4 .5 .6 .7 .8 .9 ] } V. Mortality Tables 56 QLIB/48 User's Guide Then qX(1)=.1, qx(2)=.2, ..., qX(9)=.9, and qX(10)=1. The initial age aX of the table returned by the \GaX function is 1. Since qX(10) is 1, lX(11) must be zero and therefore the terminal age wX (\GwX) of the table is 11. To see the contents of one of the built-in tables stored in the QTL library that you installed, switch to the Table Menu with the {TBLS} key. Pressing the menu key of one of the mortality tables will then recall that table to the stack. You can edit the table ([<][EDIT]) to scroll through it. B. STORAGE OF MORTALITY TABLES ------------------------------ Mortality tables can be stored for use with QLIB/48 in two ways: - in the QTL mortality table library - in ordinary HP 48 variables B.1 Mortality Table Libraries ----------------------------- Mortality tables you frequently use can be assembled under DOS into a library of mortality tables. Chapter VI provides information on the MKQTL program used to do this. These libraries are called QTL files, because the files have an extension of .QTL under DOS. The SAMPLE.QTL file distributed with QLIB/48 is an example. Once you have created a QTL file, you can download and install it on the HP 48 as described in Chapter 0. Exactly one QTL library must be installed at all times. The tables of the library appear in the Table Menu ({TBLS} key) and the Table Selection Menu ({X/Y} from the Assumption Menu). This makes it easy to select the table you wish to use. QTL libraries cannot be changed using the HP 48 itself. Any changes or additions must be made on the PC before the QTL library is installed. ** WARNING ** If you change QTL libraries by detaching an old one and installing a new one (see Chapter 0), any existing Qpar variables will still reference the old library. For example, if the third table of LIB1.QTL was used to calculate a set of N's, and you replace LIB1.QTL with LIB2.QTL, QLIB/48 will think QLIB/48 User's Guide 57 V. Mortality Tables that the third table of LIB2.QTL is the one that produced the N's, and will not force a recalculation of the assumptions. Therefore, if you change QTL libraries you must either delete any old Qpar variables, or execute a QUCALC command in every directory containing a Qpar variable to force a recalculation of the assumptions. B.2 Storing Mortality Tables in Variables ----------------------------------------- Mortality tables can also be stored in variables. This can be useful, for example, if you want to temporarily download a single table for a special project without permanently adding it to your QTL library. Another use is to create a new mortality table on the fly by performing some arithmetic operation on the mortality rates of another table. To set X or Y to a mortality table stored in a variable, you must use the QTBLXSTO or QTBLYSTO command. The mortality tables stored in variables do not appear on the Table Selection Menu when you press the {X/Y} menu key from within the Assumption Menu. For your convenience, however, the QTBLxSTO command is assigned to the [<]{x:} menu key in the selection menu. For an example of how to use a table stored in a variable, see Example 7.5. ** WARNING ** Generally, you should not change the contents of a mortality table stored in a variable. If you do, you must manually force the recalculation of any Qpar variable referencing that table (with the QUCALC command). QLIB/48 stores only the variable NAME in the Qpar variable, so it will not know if the mortality rates have changed. V. Mortality Tables 58 QLIB/48 User's Guide C. SETBACKS AND TERMINAL AGE TRUNCATION --------------------------------------- The age setback and terminal age truncation assumptions can be used to modify a mortality table before it is used in the calculation of actuarial values. C.1 Setbacks ------------ A setback adjusts the entire table up or down a specified number of ages. For example, a setback of 3 sets the mortality rate for age 50 to the rate for age 47 in the original table. Since mortality rates normally increase by age, this in effect lowers the mortality for the table. Setbacks may be specified individually for the X and Y tables (QSBX and QSBY). A setforward, which sets mortality rates equal to rates for OLDER ages (thus increasing the level of mortality), is simply a negative setback. C.2 Terminal Age Truncation --------------------------- The terminal age truncation assumption (QT\Gw) will cause mortality rates at the end of the table to be discarded, if necessary, to force the terminal age of the table to be the specified age. This can be useful when trying to match commutation functions produced with software based on truncated tables. If the terminal age of the table is already less than the QT\Gw value, the terminal age truncation assumption has no effect. For example, if Q\TGw is 100, then mortality rates above 99 will be discarded, and qx(99) will be set to 1, so that the terminal age of the table will be 100. The same terminal age truncation assumption (QT\Gw) is used for both the X and Y mortality tables. Also, the terminal age truncation is applied AFTER any setbacks. Thus, the larger the setback, the greater the number of rates that will be discarded. QLIB/48 User's Guide 59 V. Mortality Tables C.3 Examples ------------ The following examples illustrate the effect of the setback and truncation assumptions on the sample mortality table given in Section A: Original Table QSBX=0 QSBX=2 QSBX=0 QSBX=2 QSBX=2.2 QTw=max QTw=max QTw= 9 QTw= 9 QTw= 9.7 -------- -------- -------- -------- --------- Init.Age 1 3 1 3 3.2 Term.Age 11 13 9 9 10.2 ======== ======== ======== ======== ========= x qX(x) x qX(x) x qX(x) x qX(x) x qX(x) -- ----- -- ----- -- ----- -- ----- --- ----- 1st rate 1 0.1 3 0.1 1 0.1 3 0.1 3.2 0.1 2nd rate 2 0.2 4 0.2 2 0.2 4 0.2 4.2 0.2 3rd rate 3 0.3 5 0.3 3 0.3 5 0.3 5.2 0.3 4th rate 4 0.4 6 0.4 4 0.4 6 0.4 6.2 0.4 5th rate 5 0.5 7 0.5 5 0.5 7 0.5 7.2 0.5 6th rate 6 0.6 8 0.6 6 0.6 8 1.0 8.2 0.6 7th rate 7 0.7 9 0.7 7 0.7 9.2 1.0 8th rate 8 0.8 10 0.8 8 1.0 9th rate 9 0.9 11 0.9 10th rate 10 1.0 12 1.0 As the last example shows, there is no requirement that the setback or truncation age be an integer. The setback, whatever it is, is simply added to the original initial age to arrive at the initial age of the new table. The truncation age is rounded to the nearest age that is an integral distance from the initial age, because only an integral number of mortality rates can be discarded from the table. D. THE JOINT-LIFE TABLE ----------------------- In addition to the X and Y single life mortality tables, QLIB/48 supports a joint-life mortality table J to provide commutation functions for joint-life statuses (x:y) which consist of a life (x) from the X table and a life (y) from the Y table. V. Mortality Tables 60 QLIB/48 User's Guide D.1 The Age Difference ---------------------- The mortality rates for the J table are determined from the mortality rates of the X and Y tables and the assumed age difference (QXMY). QXMY is the fixed number of years that the (x) life is older than the (y) life; that is, x=y+QXMY. The "M" in "QXMY" is meant to be thought of as "minus" to remind you that the age difference is x-y. The J table is indexed by the X ages; for example, DJ(x) is the value of the D commutation function for (x:y). The y age does not need to be specified because it is determined from the value of the QXMY assumption. If you wish to calculate joint-life commutations based on another age difference, you must respecify the QXMY assumption. (This will cause the J assumptions to be recalculated.) D.2 Calculation of J Mortality Rates ------------------------------------ Since the joint-life status (x:y) survives a given year only if BOTH (x) and (y) survive the year, the J table mortality rates are calculated by the following formula: qJ(x) = 1 - (1-qX(x)) * (1-qY(x-QXMY)) This formula is applied for each integral age of the J table: aJ, aJ+1, ..., wJ-1. By definition (see Section E below), the integral ages for the J table will always be integral for the X table, so the value of qX(x) is always taken directly from the X mortality table. On the other hand, x-QXMY might not be an integral age for the Y table. In this case, qY(x-QXMY) is determined based on a uniform distribution of deaths (UDD) assumption, using the formula given in the definition of the qX function (Section IV.C). The J mortality rates are calculated internally to 15 digits of precision, and this full precision is used to determine the J table commutation functions. The initial age aJ of the J table is max(aX,aY+QXMY), because below this age either qX(x) or qY(x-QXMY) will not exist. The terminal age wJ is min(wX,wY+QXMY) because since (x) cannot survive beyond age wX and (y) cannot survive beyond wY, the joint-life status (x:y) cannot survive beyond min(wX,wY+QXMY). QLIB/48 User's Guide 61 V. Mortality Tables D.3 Example ----------- The example below shows how the mortality rates of the J table are calculated. The example is based on the sample mortality table given in Section A. Assumptions ----------- QSBX = 0 (X table setback) QSBY = 1 (Y table setback) QT\Gw = maximum (no terminal age truncation) QXMY = -3 (age difference) Ages ----- x y qX(x) qY(y) qJ(x) -- -- ----- ----- ------------------------ -2 1 -1 2 0.1 0 3 0.2 1 4 0.1 0.3 1-(1-0.1)*(1-0.3) = 0.37 2 5 0.2 0.4 1-(1-0.2)*(1-0.4) = 0.52 3 6 0.3 0.5 1-(1-0.3)*(1-0.5) = 0.65 4 7 0.4 0.6 1-(1-0.4)*(1-0.6) = 0.76 5 8 0.5 0.7 1-(1-0.5)*(1-0.7) = 0.85 6 9 0.6 0.8 1-(1-0.6)*(1-0.8) = 0.92 7 10 0.7 0.9 1-(1-0.7)*(1-0.9) = 0.97 8 11 0.8 1.0 1-(1-0.8)*(1-1.0) = 1.00 9 12 0.9 10 13 1.0 11 14 Init.Age 1 2 1 Term.Age 11 12 9 E. THE GENERAL CASE ------------------- This section describes the general case for the setback, terminal age truncation, and joint-life calculations described in the preceding sections. V. Mortality Tables 62 QLIB/48 User's Guide E.1 Single-Life Tables ---------------------- Let a0X = original initial age of the X mortality table, before any setbacks or age truncations have been applied w0X = the original terminal age of the X table a1X = a0X + QSBX w1X = w0X + QSBX w2X = min(w1X,QTw). Then the initial and terminal ages of the X table are aX = min(a1X,w2X) wX = w2X rounded to the nearest age that is an integer distance from aX. The initial age aY and terminal age wY of the Y table are defined analogously. E.2 Joint-Life Table -------------------- For the joint-life table J, let aY' = aY + QXMY, raised to the next X-table integral age (if aY'-aX is not already an integer) wY' = wY + QXMY, raised to the next X-table integral age a1J = max(aX,aY'). Then the initial and terminal ages of the J table are wJ = min(wX,wY') aJ = min(a1J,wJ). E.3 Comments ------------ 1) Due to the rounding of aY' and wY', it follows that X-table integral ages will always also be integral ages for the J table. 2) The terminal age wx (for x=X,Y,J) will always be an integral age for that table; that is, wx-ax will always be an integer. If a terminal age truncation (QT\Gw) assumption is in effect and its value is not an integral distance from the initial age of the table, the actual terminal age for the table will be QTw rounded to the nearest integral age. 3) If a terminal age truncation (QT\Gw) definition is in effect, neither the initial age nor the terminal age will QLIB/48 User's Guide 63 V. Mortality Tables exceed that age. For example, if a0X=1.1, QTw=99.5, and QSBX=100, then a1X=101.1 and w2X=99.5, so aX=wX=99.5. In this degenerate case, NX(x)=0 for x>=99.5 (as is usually the case) and NX(x) is undefined for x<99.5. Also, since qX(x) is defined only for aX<=xmkqtl mylib.qtl +up84.qtb +m83gam.qtb +f83gam.qtb | | MKQTL v1.0 - QTL library builder for QLIB/48. | | Library MYLIB.QTL does not exist. Create it (y/n)? y | | | | Summary of MYLIB.QTL (QTL format): | | # Name InitAge TermAge Size Title | | -- ---------- ------- ------- ---- ------------------- | | 1 UP84 15 112 96 UP-1984 | | 2 M83GAM 5 111 105 Male 1983 GAM | | 3 F83GAM 5 111 105 Female 1983 GAM | | | | C:\>_ | +--------------------------------------------------------------+ After the command was entered, MKQTL first found that the MYLIB.QTL library did not exist, and asked us to verify that we wanted to create it. After we answered Yes, MKQTL loaded the three mortality tables we specified in the "+" commands and added them in turn to the new library. Finally, after it reached the end of the command line, MKQTL saved the new MYLIB.QTL file and displayed a summary of its new contents. As you can see, the tables were added to the library in the order they were specified. Also, the names of the tables in the library are the same as the file names of the individual QTB files in which the tables were stored. These names are used as HP 48's XLIB (command) names. In addition, they are the names that will appear in the Table Selection Menu. The other information shown in the summary comes from the contents of the QTB files. The title is the title that will be displayed on the Assumption Menu screen when the table is selected. The following command lines are equivalent to the one used in this example: mkqtl mylib +up84 +m83gam +f83gam mkqtl mylib.qtl +up84,m83gam.qtb,f83gam VI. MKQTL Program 68 QLIB/48 User's Guide Example 6.2 - Copying tables from other libraries ------------------------------------------------- Sometimes you may wish to create a new library consisting of selected tables from one or more other libraries. You can do this by adding the libraries to your new library, and then deleting the tables you do not need. This is illustrated below for one QTL library. To combine multiple QTL files, list the additional QTL files in the "+" command, separated by commas. +--------------------------------------------------------------+ | C:\>mkqtl newlib +sample.qtl | | MKQTL v1.0 - QTL library builder for QLIB/48. | | Library NEWLIB.QTL does not exist. Create it (y/n)? y | | | | Summary of NEWLIB.QTL (QTL format): | | # Name InitAge TermAge Size Title | | -- ---------- ------- ------- ---- ------------------- | | 1 UP84 15 112 96 UP-1984 | | 2 M83GAM 5 111 105 Male 1983 GAM | | 3 F83GAM 5 111 105 Female 1983 GAM | | 4 M80CSO 0 100 99 Male 1980 CSO ANB | | 5 F80CSO 0 100 99 Female 1980 CSO ANB | | 6 M94GAM 1 121 119 Male GAM-94 Static | | 7 F94GAM 1 121 119 Female GAM-94 Static| | 8 MUP94 1 121 119 Male UP-94 | | 9 FUP94 1 121 119 Female UP-94 | | 10 MAA94 1 121 119 Male AA Proj. Scale | | 11 FAA94 1 121 119 Female AA Proj Scale| | | | C:\>mkqtl newlib -4-7 -MAA94 -FAA94 | | MKQTL v1.0 - QTL library builder for QLIB/48. | | | | Summary of NEWLIB.QTL (QTL format): | | # Name InitAge TermAge Size Title | | -- ---------- ------- ------- ---- ------------------- | | 1 UP84 15 112 96 UP-1984 | | 2 M83GAM 5 111 105 Male 1983 GAM | | 3 F83GAM 5 111 105 Female 1983 GAM | | 4 MUP94 1 121 119 Male UP-94 | | 5 FUP94 1 121 119 Female UP-94 | | | | C:\>_ | +--------------------------------------------------------------+ Note that the above commands could also have been combined into a single MKQTL run, as follows: mkqtl newlib +sample.qtl -4-7 -MAA94 -FAA94 QLIB/48 User's Guide 69 VI. MKQTL Program Example 6.3 - Re-ordering libraries ----------------------------------- You can change the order of the tables in a library with the # command. The "#" command works similar to the HP 48's ORDER command: the specified tables are moved to the beginning of the library, in the indicated order. The remaining tables follow the specified tables, and retain their original order. +--------------------------------------------------------------+ | C:\>mkqtl newlib #F83GAM,M83GAM | | MKQTL v1.0 - QTL library builder for QLIB/48. | | | | Summary of NEWLIB.QTL (QTL format): | | # Name InitAge TermAge Size Title | | -- ---------- ------- ------- ---- ------------------- | | 1 F83GAM 5 111 105 Female 1983 GAM | | 2 M83GAM 5 111 105 Male 1983 GAM | | 3 UP84 15 112 96 UP-1984 | | 4 MUP94 1 121 119 Male UP-94 | | 5 FUP94 1 121 119 Female UP-94 | | | | C:\>_ | +--------------------------------------------------------------+ Example 6.4 - Using Table Manager files --------------------------------------- The Table Manager program, a project of the Computer Science Section of the Society of Actuaries, is a Microsoft Windows program that provides access to several large databases of mortality tables. Many actuaries have contributed hundreds of tables to these databases, and they are an excellent source of the electronic versions of mortality tables. Additional information, as well a copies of the program and databases (which are free), are available from the Actuaries Online forum on CompuServe. To use tables stored in a Table Manager database, you must first extract the desired mortality tables into TXT files. See the Table Manager program Help for more information on doing this. Let's assume we have extracted the Male 1958 CSO table into T5.TXT. After the desired tables have been extracted, the = command can be used to convert the TXT file to a QTB file. By editing the QTB file, you can see exactly what mortality rates QLIB/48 will use. (Note that in the "=t5.txt=m58cso.qtb" command below, the first "=" is the command, and the second "=" is the part of the command syntax that provides an alternate name for the file.) VI. MKQTL Program 70 QLIB/48 User's Guide +--------------------------------------------------------------+ | C:\>mkqtl =t5.txt=m58cso.qtb | | MKQTL v1.0 - QTL library builder for QLIB/48. | | | | Summary of M58CSO.QTB (QTB T(3)F(.) format): | | Table title: 1958 CSO, Age Nearest, Male | | Initial age: 0 | | Terminal age: 100 | | Number of rates: 99 (excluding implicit 1) | | Rates: .00708 .00176 .00152 ... .40056 .48842 .66815 ( 1 ) | | | | C:\>_ | +--------------------------------------------------------------+ As you can see, MKQTL displayed a summary of the new table it wrote. "T(3)F(.) format" indicates that the header of the file, used by the HP 48 if the file is downloaded to the calculator, is "%%HP:T(3)F(.);". The "Rates:" line summarizes the first three and last three mortality rates in the file. "( 1 )" reminds you that QLIB/48 will automatically assume an implicit mortality rate of 1 at the end of the table. Note that if the TXT file actually contains an explicit 1, MKQTL will delete it automatically. The table title for the new file is taken from the "Table name" line of the TXT file. Since the QLIB/48 Assumption Menu will display at most 19 characters of a table's title, you may wish to edit the M58CSO.QTB file and shorten the title of the new table (for example, to "Male 1958 CSO ANB"). Once we are happy with the contents of the file, we can download the table to the HP 48 or add it to the MYLIB.QTL library as illustrated in Example 6.1: mkqtl mylib.qtl +m58cso.qtb Alternatively, we could add the original TXT file directly to the library and change its name and title all at the same time: mkqtl mylib.qtl +t5.txt=M58CSO/t"Male 1958 CSO ANB" Note that the ".txt" extension is required in "t5.txt"; otherwise MKQTL will look for a file called T5.QTB. Also, the new table name to the right of the equal sign is case sensitive, so you must enter it in all capital letters if you want it to appear that way in the library. QLIB/48 User's Guide 71 VI. MKQTL Program C. ADDITIONAL EXAMPLES ---------------------- Examples of other useful MKQTL commands are given below: 1) If you have uploaded a QTB file from a variable on your HP 48, you can use the MKQTL = command to reformat the file so it is more readable: mkqtl =up84.qtb 2) The "!" command can be used to extract individual tables from a library. The extension of the extracted file tells MKQTL what format to use. mkqtl sample.qtl !f80cso.qtb mkqtl sample.qtl !f80cso.txt This may be useful if you want to use a table from a library without having to install that library. 3) You can check the format and contents of any file simply by listing it on the MKQTL command line. If no commands are given the contents of the file are summarized and no change is made to the file: mkqtl mylib up84.qtb t5.txt 4) Entering "MKQTL" alone on the command line will give you a brief summary of the options and commands. D. GENERAL MKQTL USAGE ---------------------- The MKQTL command line consists of a list of one or more file names, options, and/or commands, separated by spaces. In addition, a reference of the form "@" will cause file names, options, and commands to be read from the response file . Comments may be included in response files by using the semicolon (;) comment character (comments extend from the semicolon to the end of the line). Options (but not file names or commands) are first read from the environment variable MKQTL. This enables you to customize MKQTL for your preferences. Response files may be used in the MKQTL variable, provided they contain no file names or commands. VI. MKQTL Program 72 QLIB/48 User's Guide D.1 File Names -------------- When a file name is given on the command line, any currently open QTL library is closed, and the named file is read. If the file is a QTB or TXT file, a summary of the contents of the file is displayed and the file is immediately closed. If the file is a QTL library, the library is retained in memory so subsequent commands can act upon it. When the final command is processed or when another file name is encountered, the library is saved (if it was changed), and a summary of its contents is displayed. D.2 Options ----------- The MKQTL program options are listed below. All must be preceded with "/". In all cases, "/x-" resets the option to its default value. /reset ------ Resets all options to their default values. /bk --- Indicates whether to keep original files as backups after a new file is written. By default (/bk-), no backups are kept. Note, however, that if the write fails the original file is always retained. /bk indicates to also keep a backup copy of the original file when a new file is written. Backup files are of the form .nnn where nnn is a 3-digit number which starts at 000 and increases as additional backups are created. /nv --- Normally (/nv-), MKQTL will ask the user to verify that a new library is to be created or that a file is to be overwritten. (Note, however, that MKQTL never asks before overwriting a file with a new version of the same file.) With /nv ("no verify") in effect, MKQTL will create the library or overwrite the file without asking (and it is therefore a dangerous option to use). /nl --- Normally (/nl-), any time MKQTL writes a file (either a new or QLIB/48 User's Guide 73 VI. MKQTL Program modified file) it displays a summary of that file. /nl ("no list") suppresses the listing of written files. Summaries are always displayed for files listed alone on the command line, however. /s -- Normally (/s-), MKQTL displays informative messages on the console as files are read and written. The /s ("silent") option suppress these messages. /w /n /f ------- These options simply provide the default values of the corresponding command parameters. See Section D.4 below. /hash (/hash2) /hash1 /hash- (/hash0) --------------- Indicates whether hash values are to be checked when TXT files are read, and written when TXT files are saved. By default (/hash- or /hash0), no hash values are checked or written. /hash1 forces hash values to be checked and written using the methodology in Table Manager ver. 1.1 (12/95). This includes ignoring the last 12 bytes that would otherwise be included in the hash calculation, due to a bug in Table Manager. /hash (or /hash2) works the same as /hash1, but does not ignore the last 12 bytes. /tio /fm ---- These options set the default TIO and fraction mark modes for the program. The default modes are /tio3 and /fm. and should not normally need to be changed. Note that QTB files with a valid header of the form "%%HP:T(3)F(.);" are always read using the modes specified in the header. D.3 Commands ------------ The following commands perform a specific action when given on the command line or in a response file. Note that the commands are not preceded with "/", except where specifically indicated. VI. MKQTL Program 74 QLIB/48 User's Guide The following symbols are used in the command argument descriptions: filespec - a DOS filespec referring to a QTB or TXT file. Filespec's are automatically converted to upper case. When needed, the name portion of the filespec (without the path or extension) also serves as a qname. qname - the name of a qtable in the library. Qname's are case sensitive, but if no match is found another search is done ignoring case. Note: You should avoid qname's that conflict with the names of HP 48 and QLIB/48 commands. qnum - the number of a qtable in the library, or a range of numbers (e.g., 3-7) libspec.QTL - a DOS filespec referring to a QTL library /params - A string of zero or more command parameters, each preceded with a "/" (but not separated with spaces). See Section D.4 below. Note that multiple table references (separated by commas) may be given with any command. This is necessary, in particular, with the # command. Portions of the syntax enclosed in square brackets ([]'s) are optional. +filespec/params -+filespec/params +filespec=qname/params -+filespec=qname/params +libspec.QTL -+libspec.QTL ---------------------- ----------------------- These commands add the specified qtables to the currently loaded library. + adds the new tables to the END of the library, and an error occurs if the table already exists. -+ is the same as +, except that if the table already exists in the library, it is replaced with the new version (and the table's position within the library stays the same). The third version of each command adds all the tables in the specified library to the current library. With the third version of the + command, any tables already in the library are left unchanged. !filespec/params -!filespec/params !qname=filespec/params -!qname=filespec/params !qnum[=filespec]/params -!qnum[=filespec]/params ----------------------- ------------------------ These commands extract the specified tables from the library, and write them to DOS files. If the extension of the DOS file is .TXT, the table is written in the Table Manager TXT format; otherwise the table is written in QTB format. The ! command leaves the library unchanged, and the -! command deletes the extracted tables from the library. With the second and third forms of the command, the name portion of the filespec can be QLIB/48 User's Guide 75 VI. MKQTL Program omitted and MKQTL will fill in the name of the table from the library (converting to a valid DOS name, if necessary). -qname -qnum ------ Deletes the specified table(s) from the library. :qname :qnum ------ Displays summaries of the specified tables in the currently loaded QTL library. The summaries are displayed regardless of the current /nl option setting. # #qname #qnum ------ Reorders and/or renumbers the library, placing the specified tables at the beginning (like the HP 48 ORDER command). # also removes any holes in the table numbering resulting from tables that were deleted with the - and -! commands. (Holes are also removed automatically when a QTL library is written.) /close ------ Closes the currently open library. Has no effect if no library is open. Note that any file listed on the command line causes the current library to be closed automatically. /list ----- This command lists the current library, reflecting commands performed up to this point. (It will also show the holes in the table numbering resulting from deleted tables.) /mem ---- Displays total and unused amount of memory available for loading files. =filespec/params =filespec=newfspec/params ------------------------- Reformats (reads and writes) the specified qtable (QTB/TXT) file. The format of the file can be changed by specifying a VI. MKQTL Program 76 QLIB/48 User's Guide new filespec (newfspec) with the desired extension. The name portion of newfspec is optional; if it is missing, a file with the original name and the new extension is written. If the drive/path portion of newfspec is missing, the new file is written to the current directory. The = command has no effect on the currently loaded library. D.4 Command Parameters ---------------------- The following are the parameters (the "/params") that may be used with the commands: /w /n ------- The /w and /n parameters determine the number of mortality rates to write per line when writing a QTB file (rates in TXT files are always written one per line). /w and /n each override the effect of the other, so only the most recent /w or /n setting is used. /w specifies the maximum line width to allow. In this case, 1, 5, or 10 rates, the largest number that will fit within the specified width, are written per line. /n specifies the actual number of rates to write per line. The lines of the file will be as wide as is necessary to accommodate the specified number of rates. The default setting is /w79. /f ------- The /f parameter specifies what ages should be listed first in each line of the QTB file. The rates will be written to the file so that the integer part of the first age in each line, minus the /f value, is divisible by the number of rates per line. For example, if 5 rates are being listed per line, /f0 will write the rates for ages 0, 5, 10, etc. at the beginning of each line, and /f1 will write ages 1, 6, 11, etc. Any negative /f value will cause the first line to start with the initial age, regardless. The default /f value is /f0. /t"string" /a ---------- These parameters allow you to changes the title and/or initial age of the table being read or written. QLIB/48 User's Guide 77 VI. MKQTL Program /x -------- This parameter allows you to specify the desired select age when reading a Table Manager Select (TXT) file. If no /x parameter is supplied, or if no select rates are available for the specified select age, then only the ultimate rates are read from the file. VII. Additional Examples 78 QLIB/48 User's Guide VII. ADDITIONAL EXAMPLES ======================== This chapter provides additional examples of how QLIB/48 can be used. A. CALCULATIONS AT NONINTEGRAL AGES ----------------------------------- Example 7.1 - Linear interpolation (LIN mode) --------------------------------------------- This example will show how LIN mode uses linear interpolation to calculate commutation functions at nonintegral ages. Suppose we wish to calculate DX(50.3) using simple linear interpolation between DX(50) and DX(51). 1. For this example, set your assumptions to the UP84 mortality table (no setback and no terminal age truncation), 7% interest, 1E9 radix, and LIN mode. 2. Calculate DX(50.3): ----- Keystrokes ----- ------ Display ------- 50.3 {DX} 1: 31,076,576.3518 To verify that DX(50.3) was computed using linear interpolation, do the interpolation manually: 3. 50 {DX} 2: 31,076,576.3518 1: 31,749,693.5941 4. .3 [ENTER] 3: 31,076,576.3518 2: 31,749,693.5941 1: 0.300000 5. 51 {DX} 4: 31,076,576.3518 3: 31,749,693.5941 2: 0.300000 1: 29,505,969.4532 6. [<][PREV] [<][PREV] 2: 31,076,576.3518 {LTRP} 1: 31,076,576.3518 As you can see, the two results match. QLIB/48 User's Guide 79 VII. Additional Examples Example 7.2 - Uniform distribution of deaths (UDD mode) ------------------------------------------------------- In this example we will see how UDD mode calculates commutation functions at nonintegral ages using a true uniform distribution of deaths assumption. 1. Set the assumptions as in the previous example, but press the {UDD} key to change the LIN/UDD mode to UDD. 2. Calculate DX(50.3): 50.3 {DX} 1: 31,059,330.4026 Note that the "Calculating...X" message did not appear, even though we changed the assumptions in step 1. This is because LIN/UDD mode only affects the calculation of the final commutation values from the internal calculated N's. It does not affect the calculation of the internal N's themselves, because they are calculated at integral ages only. To verify that DX(50.3) was indeed calculated using UDD, let's calculate it "manually." UDD is by definition linear interpolation of the lX's, so we can do this by calculating lX(50.3) using linear interpolation, and then multiplying by v^50.3 to get the true DX(50.3) value: 3. 50 {lX} 2: 31,059,330.4026 1: 935,251,519.947 4. .3 [ENTER] 3: 31,059,330.4026 2: 935,251,519.947 1: 0.300000 5. 51 {lX} 4: 31,059,330.4026 3: 935,251,519.947 2: 0.300000 1: 929,999,147.411 6. [<][PREV] [<][PREV] 2: 31,059,330.4026 {LTRP} 1: 933,675,808.186 7. {V} 50.3 [y^x] 3: 31,059,330.4026 2: 933,675,808.186 1: 0.033266 8. [*] 2: 31,059,330.4026 1: 31,059,330.4021 As you can see, the results match. The small difference is due to the fact that our calculations were done to the HP 48's standard 12 digit precision, whereas QLIB/48 does its calculations internally to 15 digits of precision. VII. Additional Examples 80 QLIB/48 User's Guide B. USING QLIB/48 WITH HP 48 APPLICATIONS ---------------------------------------- Example 7.3 - Using QLIB/48 with the Solver ------------------------------------------- The median future lifetime of a life (x) is the number of years for which (x) has a 50% probability of surviving. In other words, given a life aged X, the median future lifetime N is given by the equation 'lX(X+N)/lX(X)=.5'. There is no way to solve this equation algebraically, but the HP 48's powerful Solve application makes it a cinch to solve the equation numerically. For example, suppose we wish to find the median future lifetime of a 20-year-old using the UP-1984 mortality table. 1. First, set the X table to UP84 with no setback (and no terminal age truncation). 2. Enter the equation to solve: ----- Keystrokes ----- ------ Display ------- [QMAIN] ['] {lX} [a] X 1: 'lX(X+N)/lX(X)= [+] [a] N [->] [/] {lX} 0.500000' [a] X [->] [<][=] .5 [ENTER] 3. Store the equation in the EQ variable. (Note: This will overwrite any equation you currently have stored in EQ.) G/GX: [<][SOLVE]{ROOT}[<]{EQ} 1: S/SX: [<][SOLVE]{STEQ} (Note: On the G/GX, you can also use the interactive Solver application ([>][SOLVE]) instead of the command-based {SOLVR} environment ([<][SOLVE]) that is used here.) 4. Switch to the Solver menu: {SOLVR} 1: 5. Enter the age: 20 {X} 1: 6. Solve for the median future lifetime: [<]{N} 1: N: 56.906513 QLIB/48 User's Guide 81 VII. Additional Examples Example 7.4 - Plotting the survivorship function ------------------------------------------------ QLIB/48 functions can be graphed using the PLOT application. For example, suppose we wish to graph the survivorship function 'lX(X)'. To do so, 1. Enter the expression to be graphed: ----- Keystrokes ----- ------ Display ------- [QMAIN] ['] {lX} [a] X 1: 'lX(X)' [ENTER] 2. Change to the PLOT menu and store the equation: G/GX: [<][PLOT] [<]{EQ} 1: S/SX: [<][PLOT] {STEQ} 3. Select the FUNCTION plot type: {PTYPE} {FUNCTION} 1: 4. Enter the range of ages: 0 [SPC] 115 [ENTER] 2: 0.000000 1: 115.000000 5. Store the range of ages: G/GX: {PPAR} {XRNG} 1: [NXT] [NXT] {PLOT} S/SX: {PLOTR} {XRNG} 6. Determine the y-axis scale automatically, erase the graphics display, draw the axes, and plot the function: G/GX: [NXT] {AUTO} [<][PREV] {ERASE} {DRAX} {DRAW} S/SX: {AUTO} The lX function for your currently defined mortality assumptions will be plotted. Note that there may be a gap from the y-axis to the start of the graph, depending on the mortality table you selected. This is because the lX function is not defined before the initial age of the table. (To check the initial age of your table, use the \GaX (alpha-X) function on the third page of the MAIN Menu.) For ages above the terminal age (\GwX, or omega-X), on the other hand, lX is always 0. VII. Additional Examples 82 QLIB/48 User's Guide C. BUILDING MODIFIED MORTALITY TABLES ------------------------------------- Example 7.5 - Using a modified mortality table ---------------------------------------------- QLIB/48's ability to use mortality tables stored in variables enables you to create your own mortality tables on the fly. For example, suppose you wish to create a unisex mortality table consisting of a 50%/50% weighting of the male and female mortality rates from the 1983 GAM. This can be done in the following manner: 1. Recall the male table to the stack: ----- Keystrokes ----- ------ Display ------- [QMAIN] [<][PREV] {TBLS} 1: { "Male 1983 GAM" {M83G} 5.000000 [ 0.000342 0.00031... } 2. Extract the components of the table from the list object: G/GX: [PRG] {TYPE} {OBJ->} 4: "Male 1983 GAM" S/SX: [PRG] {OBJ} {OBJ->} 3: 5.000000 2: [ 0.000342 0.00031... 1: 3.000000 3. Using the Interactive Stack editing environment, edit the table title to be the title for the new table: [up] [up] [up] [up] 4: "Unisex 1983 GAM" [<][EDIT] [->] 3: 5.000000 [DEL] [DEL] [DEL] [DEL] 2: [ 0.000342 0.00031... [a][a] U [<][a] nisex 1: 3.000000 [ENTER] [ENTER] 4. Drop the "3" (the number of objects from the OBJ-> command) and weight the male mortality rates by 50%: [DROP] .5 [*] 3: "Unisex 1983 GAM" 2: 5.000000 1: [ 0.000171 0.00015... 5. Recall the female mortality table and extract its components: [>][MENU] {F83G} 4: "Female 1983 GAM" [>][MENU] {OBJ->} 3: 5.000000 2: [ 0.000171 0.00014... 1: 3.000000 QLIB/48 User's Guide 83 VII. Additional Examples 6. Drop the number of objects, the table title, and the initial age for the female table, and weight the female rates by 50%: [DROP] 4: "Unisex 1983 GAM" [SWAP] [DROP] 3: 5.000000 [SWAP] [DROP] 2: [ 0.000171 0.00015... .5 [*] 1: [ 0.000086 0.00007... 7. Add the weighted vectors of mortality rates: [+] 3: "Unisex 1983 GAM" 2: 5.000000 1: [ 0.000257 0.00022... 8. Round the vector of unisex mortality rates to six decimal places, to match the original tables: G/GX: 6 [MTH] {REAL} [NXT] 3: "Unisex 1983 GAM" [NXT] {RND} 2: 5.000000 S/SX: 6 [MTH] {PARTS} [NXT] 1: [ 0.000257 0.00022... [NXT] [NXT] {RND} 9. Store the new table in a list: G/GX: 3 [PRG] {LIST} {->LIST} 1: { "Unisex 1983 GAM" S/SX: 3 [PRG] {OBJ} {->LIST} 5.000000 [ 0.000257 0.00022... } 10. Enter the variable name for the new table: ['] [a][a] U83GAM [ENTER] 2: { "Unisex 1983 GAM... 1: 'U83GAM' 11. Store the table in the variable: [STO] 1: 12. Recall the name of the table to the stack so it can be used to specify the table to QLIB/48: [VAR] ['] {U83G} [ENTER] 1: 'U83GAM' 13. Store the table name as the X table by using the QTBLXSTO command: [QMAIN] [<]{ASSU} [<]{TBLX} 1: You can now set the remaining assumptions using the ordinary Assumption Menu, and do your actuarial calculations as you normally would with a built-in mortality table. In the Assumption Menu display, you will see that the "Unisex 1983 GAM" title appears. VII. Additional Examples 84 QLIB/48 User's Guide Note: The table published in IRS Revenue Ruling 95-6, which is also a 50% male and 50% female weighting of the 1983 GAM, is 0.000001 lower than the rates calculated above at ages 24, 27, 43, 53, 61, 67, 69, 76, 103, and 108. Example 7.6 - Changing a mortality table stored in a variable ------------------------------------------------------------- Suppose after doing the previous example you decided to change the table so that the unisex mortality is a 40% male and 60% female weighting of the mortality rates, rather than 50%/50%. The best way to do this is to store the new unisex table in a completely different variable, so there is no danger of the tables being confused. QLIB/48 only checks the NAME of the mortality table to determine whether the assumptions need to be calculated, so if you change the contents of a table that is currently specified as the X or Y table, QLIB/48 will not know that it needs to recalculate the assumptions to get the correct commutation functions. For more information, see the warnings in Section V.B.2. QLIB/48 User's Guide 85 VII. Additional Examples D. DEMOGRAPHIC FUNCTIONS ------------------------ In addition to the built-in lX(x) demographic function, you can use QLIB/48 to compute other demographic functions by setting QINT=0 and using interest-based commutation functions. The following table illustrates how some common demographic functions can be estimated using interest-based functions. The description indicates the interpretation of the demographic function, based on an original cohort of QRADIX lives at the initial age of the table. Demographic QLIB/48 Formula(s) Function (QINT=0 assumed) Description ----------- ------------------ --------------------------- lX(x) lX(x) number lives at age x DX(x) (all ages x) LX(x) (lX(x)+lX(x+1))/2 number of years lived (integral x) between ages x and x+1 TX(x) NMX(x,inf) number of years lived after (integral x) age x [LX(x)+LX(x+1)+...] eX(x) NX(x+1)/DX(x) curtate expectation of life CLMX(x,0,-1) (all ages x) ecX(x) CLMX(x,0,inf) complete expectation of (integral x) life [TX(x)/lX(x)] In the above table, "inf" represents a large number, such as 1E99, to approximate "infinity." For lX(x) and eX(x), the above formulas are exact for all ages, assuming a uniform distribution of deaths (UDD) between the integral ages of the table. For the other functions, the formulas are exact for integral ages (assuming UDD). For nonintegral ages, the formulas provide an approximation ultimately based on the common approximation LX(x)=(lX(x)+lX(x+1))/2. You may want to verify these formulas for yourself (and develop others), by going back to the basic definitions of the demographic and interest-based functions. VIII. Sample Programs 86 QLIB/48 User's Guide VIII. SAMPLE PROGRAMS ===================== This chapter provides information on the sample programs included in the QLIB/48 distribution. A. INTRODUCTION --------------- A.1 User-Defined Functions -------------------------- The ability to create user-defined functions and programs on the HP 48, together with the basic actuarial building blocks provided by QLIB/48, enable you to implement almost any actuarial function in a convenient way. These functions can be used from the keyboard, in algebraic expressions, and in your programs just as you would use a built-in HP 48 or QLIB/48 function. You can therefore make the HP 48 a very efficient, highly customized machine for solving the actuarial problems you encounter in your daily work. As we saw in Example 2.11, you can easily create user-defined functions "on the fly" by use of the HP 48 DEFINE command. Another convenient way to create user-defined functions is to create them in a text file on your PC, and then download the file to the calculator. This enables you to use comments and whitespace to make your programs more readable and more easily modifiable. Another advantage to creating your functions and programs in a text file is you can create an entire directory within a single file. This is useful if you want to create several functions at once because they are similar or because they need to call a common subroutine also stored in the directory. Note: There is no difference between a FUNCTION and a PROGRAM on the HP 48, except that a FUNCTION generally means a program that takes a specific number of numeric arguments (via the \-> operator), and returns a single numeric result, so that it may be used in algebraic expressions. A more general PROGRAM might return multiple results to the stack, or non-numeric results. The QLIB/48 distribution includes several sample programs that provide additional useful functionality, and which may be used as guides when creating your own programs and directories of actuarial functions. QLIB/48 User's Guide 87 VIII. Sample Programs A.2 QLIB/48 Sample Programs --------------------------- The following sample programs are included with QLIB/48: ACTFUNC - general actuarial functions GAR94 - GAR-94 generational mortality tables NONFORF - life insurance nonforfeiture values PBGCANN - pension PBGC deferred annuities These "programs" are really directories of related programs and user-defined functions (except GAR94 which is a single stand-alone program). To download the files, follow the directions in your HP 48 User's Guide or in the instructions included with your serial interface cable. Note that the QLIB/48 library must be installed prior to downloading the files since the programs make use of QLIB/48 functions. The remaining sections of this chapter describe the use of these programs. In addition, the following comments apply to all of the sample programs: - To use a function, you must change to the directory in which the function is stored (or a subdirectory of that directory). - If you forget the order of arguments to one of the functions, recall the function program to the stack. Every function begins with something like "\<< \-> x r n m \<<" which will show you the number and order of the program's arguments. - Subroutines used by the programs are stored at the end of the directories, and their names are preceded with "$" to remind you that they are generally not intended to be used directly. - A good way to understand how the programs work is to use the HP 48's debugging facilities to trace through the steps of the program. See your HP 48 User's Guide for more information on debugging. - The source listings of the programs provide additional information not discussed in this manual. B. ACTFUNC - MISCELLANEOUS ACTUARIAL FUNCTIONS ---------------------------------------------- B.1 Directory Contents ---------------------- The ACTFUNC directory contains the following functions: VIII. Sample Programs 88 QLIB/48 User's Guide Function Description ------------- ----------------------------------------------- AX(x) PV of life ins paying at end of year of death ACX(x) PV of life ins paying at moment of death EX(x,n) n-year pure endowment at age x JS12(x,p) p% Joint & Survivor annuity payable monthly JSM(x,p,m) p% J&S annuity payable (m)thly These functions are examples of functions that may be useful in general for actuarial work, but were excluded from QLIB/48 itself due to space constraints. Obviously this is just a small sample of the functions you may wish to include in this directory. You can add your own functions to the directory as you need them, using the other functions as a guide. B.2 Example - Calculating a J&S annuity --------------------------------------- In Example 2.13, we calculated a 100% joint-and-survivor (or joint-last-to-die) annuity payable monthly to a 59-year-old male and his 65-year-old wife. With the ACTFUNC directory, we can calculate this annuity very easily using the JS12(x,p) function: 1. Switch to the ACTFUNC directory. 2. Set the assumptions to 7.25% interest, 1983 GAM (male for X and female for Y, with no setbacks), -6 age difference, no terminal age truncation, and LIN mode. Note that even though you are in the ACTFUNC subdirectory, QLIB/48 still accesses the assumptions you defined in a parent directory, if any. Now enter the arguments and execute the function. Note that, as with the J table functions, the primary (X) life age is used with the JS12(x,p) function. p, the percentage, is 100 because the full annuity amount continues to the wife after the death of the husband. ----- Keystrokes ----- ------ Display ------- 3. 59 [ENTER] 100 [ENTER] 2: 59.000000 1: 100.000000 4. [VAR] {JS12} 1: 11.798554 As you can see, this matches the annuity factor calculated in Example 2.13. QLIB/48 User's Guide 89 VIII. Sample Programs C. GAR94 - BUILDING GENERATIONAL MORTALITY TABLES ------------------------------------------------- C.1 Introduction ---------------- The GAR94 program permits you to use the GAR-94 and UP-94 mortality tables, projected on a fully generational or static basis. For more information, see the Final Reports from the Society of Actuaries Task Forces (see Appendix B), and the comments in the GAR94 source file. For fully generational mortality tables (i.e., GAR-94 or UP-94G), the GAR94 program takes the year and age of the life you wish to value, and builds the appropriate projected "static" mortality table; that is, a table of specific q's for a range of ages. (All mortality tables used by QLIB/48 must be static in this sense.) The projected table is then stored in a variable, and the variable is stored as the X and/or Y mortality table. Thus, once you have run the GAR94 program, you may use QLIB/48 functions as you normally would to obtain actuarial values for lives with the corresponding year of birth. Note that when using fully generational mortality tables, a separate table must be built and stored each time you want to calculate actuarial values for a different year of birth. There is in effect a separate "static" table for each year of birth. Each time you run the GAR94 program, you get one of these static tables. For tables projected on a static basis (e.g., UP-94 @2004), you specify the year and the GAR94 program will project all base table rates from 1994 to the specified year. C.2 Program Arguments --------------------- The GAR94 program takes the following arguments: sex - 1=Male GAR-94 or GAM-94 Static 2=Female GAR-94 or GAM-94 Static -1=Male UP-94G or UP-94 -2=Female UP-94G or UP-94 age - Age of life for whom you want to generate a fully generational table; or -1 to generate a table projected on a static basis. year - Year in which the life was the specified age; or, if age=-1, the year to which the table should be projected on a static basis. tbl - 1 to store table as X table; 2 for Y; 3 for both; 0 for neither. VIII. Sample Programs 90 QLIB/48 User's Guide Note that regardless of what you specify for tbl, the projected table will be built and stored in a variable. C.3 Example - Using the GAR-94 generational mortality table ----------------------------------------------------------- Suppose we wish to calculate the annuity payable monthly to a male age 65 in 2004, using the GAR-94 mortality table and 7% interest. First we use the GAR94 program to specify the mortality table. We need to specify the sex (1 for Male GAR-94), age and year (65 in 2004, or equivalently, 0 in the 1939 year of birth), and tbl (let's use 1, for the X table): ----- Keystrokes ----- ------ Display ------- 1. 1 [ENTER] 4: 1.000000 65 [SPC] 2004 [ENTER] 3: 65.000000 1 [ENTER] 2: 2,004.000000 1: 1.000000 2. [VAR] {GAR9} 1: After a short pause, the program execution will be complete and the arguments will be removed from the stack. If you look at the VAR menu, you will see the first menu key is now "{M193}". The entire name of the variable is 'M1939GAR94', which tells you that it is a GAR-94 fully generational mortality table for a male born in 1939. 3. Next, switch to the QLIB/48 Assumption Menu and specify the 7% interest rate. You should see the following assumption screen (the Y table and x-y do not matter): +----------------------+ |-- ACTUARIAL ASSUMP --| |X: Male 65in2004 GAR94| |Y: (no table) | |x-y=0 R:1.000E9| |int=7% LIN| |----------------------| | | |== == == == == ==| +----------------------+ As you can see, the X table title reminds you of the parameters you specified when running the GAR94 program. 4. We can now calculate the annuity using QLIB/48's CL12X function: 65 [SPC] 0 {CL12X} 1: 10.079986 QLIB/48 User's Guide 91 VIII. Sample Programs C.4 Example - Using a table projected on a static basis ------------------------------------------------------- Suppose now that we wish to calculate the same annuity as in the above example, but using the UP-94 mortality table projected to 2004 on a static basis (the UP-94 @2004 table). As before, we specify the sex (-1 for Male UP-94), age (-1 for a static projection), year (2004), and tbl (1 for X): ----- Keystrokes ----- ------ Display ------- 1. 1 [+/-] [ENTER] 4: -1.000000 1 [+/-] [SPC] 2004 [ENTER] 3: -1.000000 1 [ENTER] 2: 2,004.000000 1: 1.000000 2. [VAR] {GAR9} 1: This creates the variable 'M2004UP94' containing the Male UP-94 @2004 table. If you review the assumption screen, you will see that the X table title is now "Male @2004 UP94". 3. Calculate the annuity using CL12X: 65 [SPC] 0 {CL12X} 1: 9.694823 D. NONFORF - LIFE INSURANCE NONFORFEITURE VALUES ------------------------------------------------ D.1 Directory Contents ---------------------- The NONFORF sample program contains programs for calculating cash values, adjusted premiums, and first year expense allowances under the 1980 and 1941 Standard Nonforfeiture Laws. The following are the programs included in the NONFORF directory. All programs assume a general n-year life insurance issued to (x) paying $1000 at the end of the year of death, with an endowment benefit of $e if (x) survives the n-year term. Premiums are assumed to be payable annually at the beginning of each year, for h years. VIII. Sample Programs 92 QLIB/48 User's Guide Function Description ------------- ----------------------------------------------- CV80(x,h,n,e) n by 1 matrix of the cash values \ PA80(x,h,n,e) adjusted premium |- 1980 law E180(x,h,n,e) first year expense allowance / CV41(x,h,n,e) n by 1 matrix of the cash values \ PA41(x,h,n,e) adjusted premium |- 1941 law E141(x,h,n,e) first year expense allowance / D.2 Programming Comments ------------------------ One interesting aspect of the NONFORF directory is the methodology used by the PA41 program to calculate the adjusted premium. Under the 1941 law, the adjusted premium has the unusual property of being defined in terms of itself [Bowers, pp. 435-6]. The equation cannot be solved algebraically to isolate the adjusted premium, so it can only be solved by repeated approximation. This can be done easily with the HP 48 ROOT command, which invokes the Solver to loop until a numerical solution is found. The PA41 program uses ROOT twice: once to find the adjusted premium for an ordinary whole life policy, and again to find the adjusted premium for the insurance described by the call to PA41. Each time, the program simply builds the equation for the adjusted premium (including the circular reference) and then invokes ROOT. ROOT loops repeatedly until the adjusted premium converges to the numerical solution. D.3 Example - Calculating an adjusted premium --------------------------------------------- Suppose we wish to compute nonforfeiture values for a 20-pay whole life insurance policy issued to a 45-year-old male. Assume the face value of the policy will be paid as an endowment benefit if the insured survives to age 100. For purposes of this example, let's use the 1980 CSO mortality table, 5% interest, and the 1980 Standard Nonforfeiture Law. To calculate the adjusted premium per $1000 of insurance, we use the PA80 program: 1. Set the assumptions described above: Male 1980 CSO ANB (M80CSO) for the X table and 5% interest. (Note that the UDD/LIN mode setting will have absolutely no affect on this example, since all of the premiums and death benefits will paid at integral ages of the insured.) 2. Enter the issue age x (45) and the number of premium payment QLIB/48 User's Guide 93 VIII. Sample Programs years h (20): ----- Keystrokes ----- ------ Display ------- 45 [ENTER] 20 [ENTER] 2: 45.000000 1: 20.000000 3. Calculate the number of policy years n (the number of years from issue at age 45 until the endowment benefit is paid at age 100), and enter the endowment benefit ($1000): 100 [SPC] 45 [-] 4: 45.000000 1000 [ENTER] 3: 20.000000 2: 55.000000 1: 1,000.000000 (Note that in this example, any number of policy years greater than or equal to 55 would work because age 100 is both the endowment age and the terminal age of the 1980 CSO table. Similarly, the amount of the endowment benefit doesn't matter.) 4. Calculate the adjusted premium: [VAR] {PA80} 1: 24.997954 D.4 Example - Calculating cash values ------------------------------------- To calculate the actual cash values per $1000, the same steps as in the previous example are followed but the CV80 program is used rather than PA80: ----- Keystrokes ----- ------ Display ------- 1. 45 [SPC] 20 [SPC] 55 [SPC] 4: 45.000000 1000 [ENTER] 3: 20.000000 2: 55.000000 1: 1,000.000000 2. {CV80} 1: [[ -17.706769 ] [ 2.749271 ] [ 23.941958 ] [ 45.910434 ] Only a small portion of the cash value matrix will be shown in the stack display. To scroll through all of the cash values, press the down arrow to view the matrix in the MatrixWriter environment. In this environment, the row numbers of the matrix correspond to policy durations. VIII. Sample Programs 94 QLIB/48 User's Guide E. PBGCANN - PBGC ANNUITIES --------------------------- E.1 Directory Contents ---------------------- The PBGCANN sample program calculates PBGC (Pension Benefit Guaranty Corporation) deferred annuities with the graded PBGC interest rates in the deferral period. The following programs are included: Program Description -------------- ---------------------------------------------- PB100(x,r,n,m) annuity using 100% of the graded interest rates PB120(x,r,n,m) annuity using 120% of the graded interest rates LS(x,r,n,m,b) lump sum benefit using a 100% or 120% annuity The PB100(x,r,n,m) function calculates the present value at age x of an n-year certain-and-life annuity paying $1 per year in (m)thly installments starting at age r. It is similar to 'DX(r)/DX(x)*CLMX(r,n,m)', except that the following interest rates are used instead of the flat QINT interest rate: Interest rate Period for which rate is used ------------- -------------------------------------------- QINT annuity payment period (PBGC immediate rate) QINT-.0075 first 7 years of the deferral period QINT-.02 next 8 years of the deferral period 0.04 remaining years of the deferral period Note that payments are discounted for mortality as well as interest during the deferral period; that is, it is assumed that no payments will be made if (x) does not survive the deferral period. To discount for interest only, see the comments in the PBGCANN source file for notes on how to modify the program. The PB120(x,r,n,m) function calculates the same annuity as PB100, except that 120% of the graded interest rates are used. The LS(x,r,n,m,b) program calculates the lump sum value of the annuity described by the x, r, n, and m arguments, that pays an annual benefit of $b. The lump sum is first calculated based on the 120% interest rates. If this amount is $25,000 or more, it is the lump sum value. Otherwise, the lump sum is the amount calculated based on the 100% interest rates, but no more than $25,000. QLIB/48 User's Guide 95 VIII. Sample Programs E.2 Programming Comments ------------------------ PBGCANN demonstrates how you can temporarily change assumptions to perform a specific calculation. To calculate PB120 annuities, PBGCANN changes QINT to 120% of its normal value, calculates the annuity, and then changes QINT back to its original value. By changing the value back, QINT stays equal to the PBGC immediate interest rate, as you (the user) would expect. This enables you to use the PB100 and PB120 programs interchangeably, without any need to manually change the interest rate. This also demonstrates an advantage of QLIB/48's method of maintaining the current assumptions separate from the calculated assumptions. The first time PB120 is used, the interest rate has changed so a recalculation of the assumptions is needed. After this, however, the internal assumptions retain the 120% interest rate even though the current assumptions have been returned to the original 100% interest rate. Thus, if the user calculates another 120% annuity, the assumptions do not need to be recalculated again. Another advantage is the fact that the Y and J calculated assumptions are kept separate from the X assumptions. This way, changing the interest rate temporarily for calculations done with the X table does not affect the Y and J tables, and it does not require their assumptions to be recalculated. E.3 Example - Calculating a 120% PBGC annuity --------------------------------------------- Suppose we wish to calculate a 120% PBGC annuity factor for a life-only annuity payable at age 65 to an employee who is now age 43. The annuity pays monthly at the beginning of each month, and the N12X(x)=NX(x)-11/24*DX(x) approximation is used in calculating the monthly annuity. The PBGC immediate interest rate is 5.50% and UP-1984 mortality setback 3 years is assumed. This is how we would calculate the desired annuity factor: 1. Set the assumptions: UP-1984 sb3, 5.5% interest, and LIN mode (LIN mode selects the 11/24 approximation). 2. Calculate the annuity factor by running PB120 with x=43, r=65, n=0, m=12: ----- Keystrokes ----- ------ Display ------- 43 [SPC] 65 [SPC] 0 [SPC] 1: 2.784316 12 {PB120} VIII. Sample Programs 96 QLIB/48 User's Guide The graded deferral rates for a 5.50% immediate rate are 4.75% (5.50%-.75%) for the first 7 years, 4.00% (5.50%-2%, but not less than 4%) for the next 8 years, and 4.00% for the remaining years. In our example, the deferral period is 65-43=22 years, so the 120% deferral period interest rates are 4.75%*120%=5.70% for the first 7 years and 4.00%*120%=4.80% for the remaining 15 years. The interest rate used in the payment period is 5.50%*120%=6.60%. E.4 Example - Calculating a PBGC lump sum ----------------------------------------- Now suppose the employee in the above example has an accrued age 65 annual pension benefit of $10,000. What is the equivalent PBGC lump sum value of this benefit? What is the lump sum if the accrued benefit is $8,000? $5,000? 1. To calculate the lump sum value of the $10,000 benefit, enter the same arguments as in the previous example, plus the benefit amount of $10,000, and press the {LS} variable menu key: ----- Keystrokes ----- ------ Display ------- 43 [SPC] 65 [SPC] 0 [SPC] 1: 27,843.158575 12 [SPC] 10000 {LS} 2. Similarly for the $8,000 benefit: 43 [SPC] 65 [SPC] 0 [SPC] 1: 25,000.000000 12 [SPC] 8000 {LS} For the $8,000 benefit, the lump sum value is greater than $25,000 when computed with the 100% annuity factor, and less than $25,000 with the 120% factor, so under the PBGC rules the lump sum is set to exactly $25,000. 3. Finally, for the $5,000 benefit: 43 [SPC] 65 [SPC] 0 [SPC] 1: 18,065.292482 12 [SPC] 5000 {LS} Note that in step 3, the "Calculating...X" message appeared TWICE. This is because the LS program had to calculate PBGC annuity factors with both the 100% and 120% interest rates. It first tried to calculate the 120% lump sum which forced a recalculation because the most recent interest rate that had been calculated was the 100% rate (in step 2). When it found that the 120% lump sum was too small, it calculated a lump sum based on the 100% interest rate which forced another recalculation. QLIB/48 User's Guide 97 A. Error Messages Appendix A: ERROR MESSAGES ========================== The following is a listing of error messages that may arise when using QLIB/48. Error codes above #39E00h are specifically defined by QLIB/48, and the others are general HP 48 error messages. For any error messages not listed below, consult your HP 48 User's Guide. Message/Error Number Meaning/Possible Causes -------------------- --------------------------------------- Assumptions Needed No Qpar variable is currently defined, #39E02h and you executed a QLIB/48 command that requires actuarial assumptions. Bad Argument Type You specified the incorrect type of #202h argument to a command or function. For example: - You called a QLIB/48 function with an undefined variable as an argument, or passed an algebraic expression as the argument. QLIB/48 will not build an algebraic expression from a formal algebraic expression. - A variable or XLIB name that does not contain a valid qtable was passed to QTBLXSTO, QTBLYSTO, or QGETTBL. - The list passed to QCURSTO contains the incorrect number of elements, or contains an invalid type of object. Bad Argument Value The value of an argument passed to a #203h function was incorrect. For example, the k value passed to a K function was not 1 (X), 2 (Y), or 3 (J). Infinite Result The function you specified resulted in #305h an N/0 (N nonzero) calculation. For example, NMX(x,0) or CL12X(\GwX,-5). Invalid Mort. Table The contents of a variable or XLIB name #39E03h used as a mortality table no longer contains a valid qtable. You will only get this message if the contents of the variable or XLIB name changes. If you pass an invalid variable or XLIB name to a QTBLXSTO command, you will get a "Bad Argument Type" error. A. Error Messages 98 QLIB/48 User's Guide Message/Error Number Meaning/Possible Causes -------------------- --------------------------------------- Invalid Qpar Variable The current Qpar variable does not #39E01h contain a valid Library Data object expected by QLIB/48. Purge the Qpar variable (which may be in the current or a parent directory), and redefine your assumptions. Too Few Arguments You did not specify enough arguments #201h for the command you used. Undefined Name The variable you specified (e.g., as #204h the argument to a QTBLXSTO command) does not exist, or the X or Y table references a variable which no longer exists. If you get this message when entering the Assumption Menu, simply select new X and Y tables with the {X/Y} key. Undefined Result The age you specified to a actuarial #304h function was out of the valid range for the function, or resulted in a 0/0 calculation. For example: - DX(x) for x < \GaX - qX(x) for x < \GaX or x >= \GwX - CL12X(x,0) for x >= \GwX Undefined XLIB Name You tried to execute a command from a #004h library that is not installed. You may get this error if you do not have both the QLIB/48 program library and a QTL mortality library installed. QLIB/48 User's Guide 99 B. References Appendix B: REFERENCES ====================== A. ACTUARIAL REFERENCES ----------------------- Bowers, N. L., Gerber, H. U., Hickman, J. C., Jones, D. A., and Nesbitt, C. J., ACTUARIAL MATHEMATICS, first edition (Society of Actuaries, 1986). Fellers, William W., and Jackson, Paul H., "Noninsured Pension Mortality/The UP-1984 Table," THE PROCEEDINGS, CONFERENCE OF ACTUARIES IN PUBLIC PRACTICE, vol. 25 (1976), pp. 456-502. Jordan, C. W., LIFE CONTINGENCIES, second edition (Society of Actuaries, 1982). Society of Actuaries, Special Committee to Recommend New Mortality Tables for Valuation, "Report on New Mortality Tables for Valuation of Individual Ordinary Insurance," TRANSACTIONS, vol. XXXIII (1981), pp. 617-74. Society of Actuaries, Committee on Annuities, "Development of the 1983 Group Annuity Mortality Table," TRANSACTIONS, vol. XXXV (1983), pp. 859-99. Society of Actuaries, Group Annuity Valuation Table Task Force, "Final Report/1994 Group Annuity Mortality Table and 1994 Group Annuity Reserving Table" (May 1995; to be published in TRANSACTIONS, vol. XLVII). Society of Actuaries, UP-94 Task Force, "Final Report/The 1994 Uninsured Pensioner Mortality Table" (May 1995; to be published in TRANSACTIONS, vol. XLVII). Society of Actuaries, Committee on Retirement Systems Research and Committee on Retirement Systems Practice Education, "Final Report/The UP-94 and GAR-94 Tables/Issues in Choosing the Appropriate Table" (May 1995; to be published in TRANSACTIONS, vol. XLVII). Strommen, Stephen, "Table Manager Program Version 1.1" (a project of the Society of Actuaries Computer Science Section) (December 1995). B. References 100 QLIB/48 User's Guide B. PROGRAMMING REFERENCES ------------------------- Brittenson, Jan, MLDL program, version 1.02 (1991). Heiskanen, Mika, DEBUG program. Hewlett-Packard Company, "HP 48G Series User's Guide," edition 2 (1993). Hewlett-Packard Company, "HP 48SX Scientific Expandable Owners Manual," edition 1 (1990). Hewlett-Packard Company, "HP 48 Programmer's Reference Manual," edition 1 (1990). Hewlett-Packard Company, "RPL Programming Guide" (RPLMAN.DOC) (1991). Hewlett-Packard Company, SASM.DOC (Saturn Assembly Language manual) (1991). Horn, Joseph K., ed., Goodies Disks #1 to #8 (EduCalc). Mueller, Detlef, and Hellstern, Raymond, RPL48 program, version 5.0 (1993). Nickel, Derek S., "HP 48SX Internals" (January 1991). Nickel, Derek S., "Voyager" program, version 1.0-6 (January 1991). Wickes, William C., HP 48 INSIGHTS: I. PRINCIPLES AND PROGRAMMING (Larken Publications, 1991).