home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1991
/
10
/
strucprg.asc
< prev
next >
Wrap
Text File
|
1991-09-10
|
9KB
|
239 lines
_STRUCTURED PROGRAMMING COLUMN_
by Jeff Duntemann
[LISTING ONE]
TITLE('COMPUTE MONTHLY PAYMENTS')
PAYMENT PROGRAM
INCLUDE('\CLARION\STD_KEYS.CLA') !STANDARD KEYCODE EQUATES
SCREEN SCREEN HLP('PAYMENT'),HUE(7,0,0)
ROW(4,25) PAINT(13,32),HUE(7,1)
COL(25) STRING('<201,205{30},187>')
ROW(5,25) REPEAT(3);STRING('<186,0{30},186>') .
ROW(8,25) STRING('<204,205{30},185>')
ROW(9,25) REPEAT(7);STRING('<186,0{30},186>') .
ROW(16,25) STRING('<200,205{30},188>')
ROW(6,28) STRING('CALCULATE MONTHLY PAYMENTS')
ROW(13,32) STRING('Payment :')
ROW(15,30) STRING('Press Ctrl-Esc to Exit')
ROW(9,32) STRING('Principal:')
COL(44) ENTRY(@N7),USE(AMOUNT),INS,NUM
ROW(10,32) STRING('Rate {5}:')
COL(44) ENTRY(@N7.3),USE(RATE),INS,NUM
ROW(11,32) STRING('Years :')
COL(49) ENTRY(@N2),USE(YEARS),INS,NUM
PAYMENT ROW(13,42) STRING(@N9.2)
.
AMOUNT DECIMAL(7) !PRINCIPAL AMOUNT
RATE DECIMAL(7,3) !ANNUAL PERCENTAGE RATE
YEARS DECIMAL(3) !TERM IN YEARS
MONTHS DECIMAL(3) !TERM IN MONTHS
MON_RATE REAL !MONTHLY RATE
TEMP REAL !INTERMEDIATE VALUE
CODE !START THE CODE SECTION
ALERT(CTRL_ESC) !ENABLE THE CTRL-ESC KEY
HELP('PAYMENT') !OPEN THE HELP FILE
OPEN(SCREEN) !DISPLAY THE SCREEN LAYOUT
LOOP !LOOP THROUGH THE FIELDS
ACCEPT !GET A FIELD FROM THE KEYBOARD
IF KEYCODE() = CTRL_ESC THEN RETURN. !EXIT ON CTRL-ESC
IF AMOUNT * RATE * YEARS <> 0 !WHEN ALL FIELDS ARE ENTERED:
MONTHS = YEARS * 12 !COMPUTE MONTHS
MON_RATE = RATE / 1200 !COMPUTE MONTHLY RATE
TEMP = 1 / ((1 + MON_RATE) ^ MONTHS) !COMPUTE MONTHLY PAYMENT
PAYMENT = AMOUNT * (MON_RATE / (1 - TEMP))
ELSE !OTHERWISE:
PAYMENT = 0 ! SET MONTHLY PAYMENT TO ZERO
. !END THE IF STATEMENT
IF FIELD() = ?YEARS !AFTER THE LAST FIELD
SELECT(?AMOUNT) ! SELECT THE FIRST FIELD
. . !END THE IF AND LOOP STATEMENTS
[LISTING TWO]
{ By Jeff Duntemann -- From DDJ for October 1991 }
UNIT Mortgage;
INTERFACE
TYPE
Payment = RECORD { One element in the amort. table. }
PayPrincipal : Real;
PayInterest : Real;
PrincipalSoFar : Real;
InterestSoFar : Real;
ExtraPrincipal : Real;
Balance : Real;
END;
PaymentArray = ARRAY[1..2] OF Payment; { Dynamic array! }
PaymentPointer = ^PaymentArray;
PMortgage = ^TMortgage;
TMortgage =
OBJECT
Periods : Integer; { Number of periods in mortgage }
PeriodsPerYear : Integer; { Number of periods in a year }
Principal : Real; { Amount of principal in cents }
Interest : Real; { Percentage of interest per *YEAR*}
MonthlyPI : Real; { Monthly payment in cents }
Payments : PaymentPointer; { Array holding payments }
PaymentSize : LongInt; { Size in bytes of payments array }
CONSTRUCTOR Init(StartPrincipal : Real;
StartInterest : Real;
StartPeriods : Integer;
StartPeriodsPerYear : Integer);
PROCEDURE SetNewInterestRate(NewRate : Real);
PROCEDURE Recalc;
PROCEDURE GetPayment(PaymentNumber : Integer;
VAR ThisPayment : Payment);
PROCEDURE ApplyExtraPrincipal(PaymentNumber : Integer;
Extra : Real);
PROCEDURE RemoveExtraPrincipal(PaymentNumber : Integer);
DESTRUCTOR Done;
END;
IMPLEMENTATION
FUNCTION CalcPayment(Principal,InterestPerPeriod : Real;
NumberOfPeriods : Integer) : Real;
VAR
Factor : Real;
BEGIN
Factor := EXP(-NumberOfPeriods * LN(1.0 + InterestPerPeriod));
CalcPayment := Principal * InterestPerPeriod / (1.0 - Factor)
END;
CONSTRUCTOR TMortgage.Init(StartPrincipal : Real;
StartInterest : Real;
StartPeriods : Integer;
StartPeriodsPerYear : Integer);
VAR
I : Integer;
InterestPerPeriod : Real;
BEGIN
{ Set up all the initial state values: }
Principal := StartPrincipal;
Interest := StartInterest;
Periods := StartPeriods;
PeriodsPerYear := StartPeriodsPerYear;
{ Here we calculate the size that the payment array will occupy. }
{ We retain this because the number of payments may change...and }
{ we'll need to dispose of the array when the object is ditched: }
PaymentSize := SizeOf(Payment) * Periods;
{ Allocate payment array on the heap: }
GetMem(Payments,PaymentSize);
{ Initialize extra principal fields of payment array: }
FOR I := 1 TO Periods DO
Payments^[I].ExtraPrincipal := 0;
Recalc; { Calculate the amortization table }
END;
PROCEDURE TMortgage.SetNewInterestRate(NewRate : Real);
BEGIN
Interest := NewRate;
Recalc;
END;
{ This method calculates the amortization table for the mortgage. }
{ The table is stored in the array pointed to by Payments. }
PROCEDURE TMortgage.Recalc;
VAR
I : Integer;
RemainingPrincipal : Real;
PaymentCount : Integer;
InterestThisPeriod : Real;
InterestPerPeriod : Real;
HypotheticalPrincipal : Real;
BEGIN
InterestPerPeriod := Interest/PeriodsPerYear;
MonthlyPI := CalcPayment(Principal,
InterestPerPeriod,
Periods);
{ Round the monthly to cents: }
MonthlyPI := int(MonthlyPI * 100.0 + 0.5) / 100.0;
{ Now generate the amortization table: }
RemainingPrincipal := Principal;
PaymentCount := 0;
FOR I := 1 TO Periods DO
BEGIN
Inc(PaymentCount);
{ Calculate the interest this period and round it to cents: }
InterestThisPeriod :=
Int((RemainingPrincipal * InterestPerPeriod) * 100 + 0.5) / 100.0;
{ Store values into payments array: }
WITH Payments^[PaymentCount] DO
BEGIN
IF RemainingPrincipal = 0 THEN { Loan's been paid off! }
BEGIN
PayInterest := 0;
PayPrincipal := 0;
Balance := 0;
END
ELSE
BEGIN
HypotheticalPrincipal :=
MonthlyPI - InterestThisPeriod + ExtraPrincipal;
IF HypotheticalPrincipal > RemainingPrincipal THEN
PayPrincipal := RemainingPrincipal
ELSE
PayPrincipal := HypotheticalPrincipal;
PayInterest := InterestThisPeriod;
RemainingPrincipal :=
RemainingPrincipal - PayPrincipal; { Update running balance }
Balance := RemainingPrincipal;
END;
{ Update the cumulative interest and principal fields: }
IF PaymentCount = 1 THEN
BEGIN
PrincipalSoFar := PayPrincipal;
InterestSoFar := PayInterest;
END
ELSE
BEGIN
PrincipalSoFar :=
Payments^[PaymentCount-1].PrincipalSoFar + PayPrincipal;
InterestSoFar :=
Payments^[PaymentCount-1].InterestSoFar + PayInterest;
END;
END; { WITH }
END; { FOR }
END; { TMortgage.Recalc }
PROCEDURE TMortgage.GetPayment(PaymentNumber : Integer;
VAR ThisPayment : Payment);
BEGIN
ThisPayment := Payments^[PaymentNumber];
END;
PROCEDURE TMortgage.ApplyExtraPrincipal(PaymentNumber : Integer;
Extra : Real);
BEGIN
Payments^[PaymentNumber].ExtraPrincipal := Extra;
Recalc;
END;
PROCEDURE TMortgage.RemoveExtraPrincipal(PaymentNumber : Integer);
BEGIN
Payments^[PaymentNumber].ExtraPrincipal := 0.0;
Recalc;
END;
DESTRUCTOR TMortgage.Done;
BEGIN
FreeMem(Payments,PaymentSize);
END;
END. { MORTGAGE }