This program calculates the Net Present Value (NPV) and Internal Rate of Return (IRR) for a capital investment project. It reads project parameters—initial cost, duration, periodic revenues, expenses, and a discount rate—from DATA statements, then computes discounted cash flows for each period. The IRR is found by iterating a discount rate from 0% to 100% in 0.5% steps until the NPV of cash flows falls to or below that rate. A sensitivity analysis loop allows the user to re-run calculations with a modified discount rate without restarting the program.
Program Analysis
Program Structure
The program is divided into clearly separated phases, each handling a distinct part of the financial calculation:
- Lines 2–18: Variable glossary display with a timed pause before clearing the screen.
- Lines 19–90: Header output and data initialisation; reads initial cost
Cand project durationVfrom DATA, then dimensions six arrays of sizeV. - Lines 100–230: Reads and displays periodic revenues
R(I), expensesD(I), residual valueRO, and discount rateT. - Lines 260–340: Prints the raw forecast table (revenues, expenses, profit per period).
- Lines 360–560: Computes and displays discounted present values for each period, plus the discounted residual value
VR. - Lines 580–660: Prints final results: NPV of cash flow and a profitability index.
- Lines 670–780: Iterative IRR search loop.
- Lines 800–840: Sensitivity analysis prompt; loops back to line 220 if the user requests a new discount rate.
- Lines 850–890: Subroutines — a horizontal rule printer and a column-header printer.
- Lines 900–930: DATA block providing the sample project parameters.
Key Financial Calculations
The core discounting formula applied at line 440–460 is the standard present value formula:
S(I) = R(I) * (1 + T/100)^(-I)— discounted revenue for period IE(I) = D(I) * (1 + T/100)^-I— discounted expense for period IC(I) = S(I) - E(I)— net discounted cash flow for period IVR = RO * (1 + T/100)^(-V-1)— residual value discounted one period beyond the project end (line530)
The NPV (line 630) is B + VR - C, where B is the sum of discounted net cash flows, VR is the discounted residual, and C is the initial cost. The profitability index (line 660) is (RR + VR) / (DD + C) expressed as a percentage, rounded to two decimal places inline rather than using the FN A function.
IRR Search Algorithm
The Internal Rate of Return is found by a simple brute-force scan (lines 680–750). The outer loop variable O steps from 0 to 100 in 0.5% increments. For each candidate rate, the NPV X is recomputed using B(I) (pre-calculated net profits) plus the discounted residual, minus initial cost. The loop exits when X <= O, at which point O approximates the IRR.
There is a subtle bug in line 740: the exit condition IF X <= O compares the NPV against the current rate value rather than against zero (IF X <= 0). This means the loop exits slightly early—when NPV drops below the current percentage value rather than when it crosses zero—potentially overstating the IRR by a small margin. For typical project scales the error is minor but it is technically incorrect.
Variable Name Collision
A significant naming conflict exists: the scalar variable C (initial project cost, read at line 55) is overwritten at line 90 when DIM C(V) is declared, creating an array also named C. In Sinclair BASIC, a scalar and an array of the same name cannot coexist—declaring the array erases the scalar. After line 90, any reference to C as the initial cost (e.g., lines 630, 660, 730) would actually access C(0) (the zeroth element of the array, which defaults to zero), producing incorrect NPV and profitability results. This is a genuine bug in the program as listed.
Notable BASIC Idioms
- User-defined function: Line
19definesFN A(X) = INT(100*X + 0.5)/100, a standard two-decimal-place rounding function used extensively in output formatting. - Subroutine reuse: The horizontal rule subroutine at line
850is called over ten times, keeping the separator output consistent and saving repeated PRINT statements. - Sensitivity loop: Line
830jumps back to line220(re-display of rate, then recalculation) rather than line1, avoiding a full re-read of DATA and allowing repeated what-if analysis cleanly. - TAB positioning: Column alignment throughout the output relies entirely on
TAB()calls, producing a structured multi-column report without any screen editor tricks.
DATA Layout
| Line | Values | Meaning |
|---|---|---|
900 | 18000, 5 | Initial cost C, duration V (5 periods) |
910 | 5000, 5500, 5500, 5000, 5000 | Revenue R(1)–R(5) |
920 | 100, 1000, 1200, 1500, 1500 | Expenses D(1)–D(5) |
930 | 8000, 12 | Residual value RO, discount rate T (%) |
Content
Source Code
2 REM "NET PRES V"
4 PRINT " VARIABLES: ": PRINT
5 PRINT "B TOTAL DISCOUNTED PROFITS"
6 PRINT "B(I) PROFIT FOR PERIOD I"
7 PRINT "C(I) DISCOUNTED PROFIT FOR PER I"
8 PRINT "C INITIAL COST OF PROJECT-- line 900"
9 PRINT "D(I) EXPENSES FOR PERIOD I-- line--920"
10 PRINT "DD TOTAL DISCOUNTED EXPENSES"
11 PRINT "E(I) DISCOUNTED EXP FOR PER I"
12 PRINT "R(I) REVENUES FOR PERIOD I-- line 910"
13 PRINT "RO RESIDUAL VALUE OF PROJECT-- line 930"
14 PRINT "S(I) DISCOUNTED REV FOR PER I"
15 PRINT "T DISCOUNT RATE-- line 930"
16 PRINT "V EST DURATION OF PROJECT-- line 900"
17 PRINT "VR DISCOUNTED RESIDUAL VALUE"
18 PAUSE 340: CLS
19 DEF FN A(X)=INT (100*X+.5)/100
20 PRINT : PRINT
30 PRINT " NET PRESENT VALUE AND"
40 PRINT "INTERNAL RATE OF RETURN"
45 PRINT "-------------------------------"
50 PRINT : PRINT
55 READ C,V
60 PRINT "INITIAL COST OF THE INVESTMENT? ";C
70 PRINT
80 PRINT "ESTIMATED DURATION OF PROJECT? ";V
90 DIM R(V): DIM D(V): DIM B(V): DIM C(V): DIM E(V): DIM S(V)
100 PRINT
110 PRINT "PERIODIC INCOME FROM PROJECT:"
120 FOR I=1 TO V
125 READ R(I)
130 PRINT "--PERIOD #";I;TAB ( 15);R(I)
150 NEXT I: PRINT
160 PRINT "EXPENSES FORECAST:"
170 FOR I=1 TO V
175 READ D(I)
180 PRINT "--PERIOD #";I;TAB ( 15);D(I)
200 NEXT I: PRINT
205 READ RO,T
210 PRINT "RESIDUAL VALUE OF THE INVESTMENT? ";RO
220 PRINT
230 PRINT "RATE OF RETURN ON INVESTMENT? (%) ";T
240 REM PRINT OUTPUT
250 PRINT : PRINT
260 PRINT "FORECASTS:"
270 GO SUB 850
280 GO SUB 870
290 GO SUB 850
300 FOR I=1 TO V
310 LET B(I)=R(I)-D(I)
320 PRINT TAB ( 2);I;TAB ( 8);R(I);TAB ( 15);D(I);TAB 22;B(I)
330 NEXT I
340 GO SUB 850
350 PRINT : PRINT : PRINT
360 REM PRESENT VALUE
370 PRINT "PRESENT VALUE: "
380 GO SUB 850
390 GO SUB 870
395 LET P$="(PRES VAL)"
400 PRINT TAB ( 2);P$;TAB ( 12);P$;TAB ( 22);P$
410 GO SUB 850
420 LET B=0: LET RR=0: LET DD=0
430 FOR I=1 TO V
440 LET S(I)=R(I)*(1+T/100)^(-I)
450 LET E(I)=D(I)*(1+T/100)^-I
460 LET C(I)=S(I)-E(I)
470 LET B=B+C(I)
480 LET RR=RR+S(I)
490 LET DD=DD+E(I)
500 PRINT TAB ( 2);FN A(I);TAB ( 7);FN A(S(I));
505 PRINT TAB ( 15);FN A(E(I));TAB ( 24);FN A(C(I))
510 NEXT I
520 GO SUB 850
530 LET VR=RO*(1+T/100)^(-V-1)
540 PRINT "PRESENT VALUE OF RESIDUAL = ";
550 PRINT TAB ( 25);FN A(VR)
560 GO SUB 850
570 REM PRINT OUTPUT
580 PRINT : PRINT
590 PRINT "RESULTS OF THE ANALYSIS:"
595 PRINT
600 GO SUB 850
610 PRINT "NET PRESENT VALUE OF CASH-FLOW"
620 PRINT "(INCLUDING RESIDUAL VALUE)"
630 PRINT TAB ( 15);" = ";TAB ( 25);FN A(B+VR-C)
640 GO SUB 850
650 PRINT "PROFITABILITY INDEX = ";
660 PRINT TAB ( 25);INT (10000*((RR+VR)/(DD+C))+.5)/100;"%"
670 REM CALCULATE INTERNAL RATEOF RETIURN
680 FOR O=0 TO 100 STEP 0.5
690 LET X=0
700 FOR I=1 TO V
710 LET X=X+B(I)*(1+O/100)^-I
720 NEXT I
730 LET X=X+RO*(1+O/100)^(-V-1)-C
740 IF X<=O THEN GO TO 760
750 NEXT O
760 GO SUB 850
770 PRINT "INTERNAL RATE OF RETURN = ";
780 PRINT TAB (31);FN A(O);"%"
790 GO SUB 850
800 PRINT : PRINT
810 PRINT "PERFORM SENSITIVITY ANALYSIS BY "
820 INPUT "MODIFYING THE RATE OF RETURN?(Y/N) ";C$
830 IF C$="Y" THEN PRINT "Input a new rate": INPUT T: GO TO 220
835 GO TO 840
840 STOP
850 PRINT "-------------------------------"
860 RETURN
870 PRINT "PER EXPECTED ESTIMATED EXPECTED"
880 PRINT " REVENUES EXPENSES PROFITS"
890 RETURN
900 DATA 18000,5
910 DATA 5000,5500,5500,5000,5000
920 DATA 100,1000,1200,1500,1500
930 DATA 8000,12
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

