Skip to content

Commit 2675411

Browse files
committed
Merge branch 'docs' into develop
2 parents 1a50317 + 63462bc commit 2675411

21 files changed

+303
-157
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Changelog
22

33
- Unreleased
4+
- 0.12.0-rc1 (2024-06-18)
45
- TVM
56
- add `C/YR` menu (number of compoundings per year)
67
- uses the same variable as the `C/Y` variable of the "Finance" app
@@ -21,6 +22,10 @@
2122
flag of the "Finance" app provided by TI-OS
2223
- display status message 'TVM Calculated (Multiple)' if the TVM equation
2324
has 2 solutions, but only one of them was found
25+
- docs
26+
- simplify pandoc processing pipeline
27+
- change PDF font to FreeSerif and FreeMono to render the U+2220 (angle)
28+
symbol properly
2429
- 0.11.0 (2024-05-28)
2530
- **Warning**: Previously saved RPN stack and storage registers are
2631
incompatible and are lost when upgrading to this version.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ Missing features (partial list):
113113
- vectors and matrices
114114
- keystroke programming
115115

116-
**Version**: 0.11.0 (2024-05-28)
116+
**Version**: 0.12.0-rc1 (2024-06-18)
117117

118118
**Changelog**: [CHANGELOG.md](CHANGELOG.md)
119119

docs/DEVELOPER.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Notes for the developers of the RPN83P app, likely myself in 6 months when I
44
cannot remember how the code works.
55

6-
**Version**: 0.9.0 (2024-01-06)
6+
**Version**: 0.12.0-rc1 (2024-06-18)
77

88
**Project Home**: https://github.com/bxparks/rpn83p
99

docs/FUTURE.md

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ because it is faster and easier to use compared to a web app, especially for
1414
small features that can be described in a few sentences. Usually only the larger
1515
and more complicated features will get their own GitHub tickets.
1616

17-
**Version**: 0.11.0 (2024-05-28)
17+
**Version**: 0.12.0-rc1 (2024-06-18)
1818

1919
**Parent Document**: [USER_GUIDE.md](USER_GUIDE.md)
2020

@@ -30,26 +30,6 @@ and more complicated features will get their own GitHub tickets.
3030

3131
## Near Future
3232

33-
- `TVM` (time value of money)
34-
- improve TVM Solver for `I%YR`
35-
- The current default initial guess is 0% and 100% so that positive
36-
interest rates are required (because a sign change over the initial
37-
guesses are required). If there is a rounding error, the actual
38-
numerical solution could be slighlty negative, which would cause an
39-
`TVM Not Fount` error message because a sign-change is currently
40-
required over the 2 initial guesses.
41-
- One solution could be use something like `-1%` for the lower guess,
42-
and then check for a sign change over 2 sub-intervals: `[-1%,0%]` and
43-
`[0%,100%]`. We also have to careful to detect cases where expected
44-
solution is exactly `0%`.
45-
- The terminating tolerance could be selectable or more intelligent.
46-
- Maybe change the root solving algorithm from Secant method to Newton's
47-
method for faster convergence.
48-
- support `C/YR` (compounding periods per year) as a separate parameter
49-
- currently `C/YR` is set to be the same as `P/YR` (payments per year)
50-
for ease of implementation
51-
- there are apparently jurisdictions (Canada, UK) where it is common for
52-
`C/YR` to be different from `P/YR`
5333
- add a `ROOT > CLR > CLAL` (Clear All) menu function
5434
- becomes useful as more features and configuration options are added
5535
- allow numbers in any base to be entered regardless of the BASE mode

docs/TVM.md

Lines changed: 117 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Equations, algorithms, and other tricks used to calculate the Time Value of
44
Money (TVM) variables in the RPN83P calculator app.
55

6-
**Version**: 0.9.0 (2024-01-06)
6+
**Version**: 0.12.0-rc1 (2024-06-18)
77

88
**Project Home**: https://github.com/bxparks/rpn83p
99

@@ -20,7 +20,7 @@ Money (TVM) variables in the RPN83P calculator app.
2020
- [Taming Overflows](#taming-overflows)
2121
- [Secant Method](#secant-method)
2222
- [Initial Guesses](#initial-guesses)
23-
- [Tolerance](#tolerance)
23+
- [Terminating Conditions](#terminating-conditions)
2424
- [Maximum Iterations](#maximum-iterations)
2525
- [Convergence](#convergence)
2626
- [References](#references)
@@ -69,23 +69,55 @@ NPV = NFV * (1+i)^N
6969

7070
## Interest Rate Conversions
7171

72-
The variable `i` in the `NPV` and `NFV` equations defines the interest rate per
73-
payment period. For most real-life problems, it is more convenient to express
74-
the interest rate per year. The relationship between these quantities are:
72+
Most real-life problems express the nominal annual interest rate `I%YR` as a
73+
percentage instead of a dimensionless fraction `IYR` which is more useful in
74+
computation. So let's define:
75+
76+
```
77+
IYR = I%YR / 100
78+
```
79+
80+
The variable `i` in the `NPV` and `NFV` equations is the interest rate per
81+
payment period, which is defined from the nominal interest rate `IYR` by:
7582

7683
```
7784
i = IYR/PYR
7885
```
7986

80-
where:
87+
where `PYR` is the number of payments per year
88+
89+
However, this is true only if `PYR` is equal to `CYR`, the number of
90+
compoundings per year. It seems that in some countries (e.g. Canada and the UK),
91+
lenders are required to calculate the `CYR` differently from the `PYR`.
92+
93+
When the 2 quantities are different, the total effective annual interest rate
94+
that results from compounding for each payment period at interest rate `i` must
95+
equal the total effective annual interest rate when compounded using the `CYR`
96+
compounds per year. In other words, the following defines the meaning of `CYR`:
97+
98+
```
99+
(1 + i) ^ PYR = (1 + IYR/CYR) ^ CYR
100+
```
101+
102+
We can rearrange the equation to solve the payment-period interest rate `i`
103+
which is used on the TVM equations:
104+
105+
```
106+
i = (1 + IYR/CYR) ^ (CYR/PYR) - 1
107+
= expm1[ (CYR/PYR) log1p(IYR/CYR) ]
108+
```
109+
110+
where we have used the `expm1()` and `log1p()` functions that we defined below.
111+
112+
Since the `expm1()` and `log1p()` functions are inverses of each other, we can
113+
easily get the formula for calculating `IYR` from `i`:
114+
81115
```
82-
IYR = nominal interest rate per year (without compounding)
83-
PYR = number of payments per year
116+
IYR = CYR expm1[ (PYR/CYR) log1p(i) ]
84117
```
85118

86-
In addition, most real-life problems express the annual interest rate as a
87-
percentage instead of a dimensionless fraction. So `IYR = I%YR / 100`, where
88-
`I%YR` is the nominal interest percentage per year.
119+
From `IYR`, we can calculate the nominal percent interest rate `I%YR` as
120+
`100*IYR`.
89121

90122
## TVM Formulas
91123

@@ -361,6 +393,12 @@ equation are *unchanged*. Let's define a new term `CFN(i,N)`:
361393

362394
```
363395
CFN(i,N) = CF2(i)/N = [(1+i)^N-1]/Ni
396+
397+
expm1(N log1p(i)) / Ni (i!=0)
398+
/
399+
=
400+
\
401+
1 (i==0)
364402
```
365403

366404
(Note that this is slightly different than the `C(i,N)` function defined by
@@ -374,8 +412,9 @@ called `NPMT(i)`:
374412

375413
```
376414
NPMT(i) = NFV(i) / CFN(i,N)
377-
= PV (1+i)^N Ni / [(1+i)^N-1] + (1+ip)N*PMT + FV / CFN(i,N)
378-
= PV (-N)i / [(1+i)^(-N)-1] + (1+ip)N*PMT + FV / CFN(i,N)
415+
= PV (1+i)^N Ni / [(1+i)^N-1] + (1+ip)N*PMT + FV Ni / [(1+i)^N-1]
416+
= PV (1+i)^N Ni / [(1+i)^N-1] + (1+ip)N*PMT + FV Ni / [(1+i)^N-1]
417+
= PV (-N)i / [(1+i)^(-N)-1] + (1+ip)N*PMT + FV Ni / [(1+i)^N-1]
379418
= PV / CFN(i,-N) + (1+ip)N*PMT + FV / CFN(i,N)
380419
```
381420

@@ -432,11 +471,18 @@ beginning or end of the cash flow. The `NPMT(i)` function essentially averages
432471
all 3 terms over the entire duration of the `N` payment periods, instead of
433472
pulling everything to the present or pushing everything to the future.
434473

435-
**Implementation Note**: The `inverseCompoundingFactor()` routine calculates the
436-
reciprocal of `CFN(i,N)`. In other words, it calculates `ICFN(i,N) = 1/CFN(i,N)
437-
= Ni/((1+i)^N-1)` for a slight gain in efficiency by avoiding a division or two.
438-
This makes `ICFN(i,N)` similar to the `C(n)` function given by Albert Chan in
439-
[TVM formula error in programming
474+
**Implementation Note**:
475+
476+
The `inverseCompoundingFactor()` routine calculates the reciprocal of
477+
`CFN(i,N)`. In other words, it calculates
478+
479+
```
480+
ICFN(i,N) = 1/CFN(i,N) = Ni/((1+i)^N-1)
481+
```
482+
483+
for a slight gain in efficiency by avoiding a division or two. This makes
484+
`ICFN(i,N)` similar to the `C(n)` function given by Albert Chan in [TVM formula
485+
error in programming
440486
manual?](https://www.hpmuseum.org/forum/thread-20739-post-179371.html#pid179371)
441487
(2023), within a factor of `(1+i)^N`, or equivalently, a substitution of `-N`
442488
for `N`.
@@ -472,20 +518,31 @@ of about 1e-8 within 7-8 iterations.
472518
### Initial Guesses
473519

474520
The Secant method (as well as other root finding methods) requires 2 initial
475-
guesses to be provided. The TVM Solver currently (v0.9.0) uses the following
476-
defaults:
477-
478-
- `i0` = 0
479-
- `i1` = 1/PYR, where PYR is the number of payments per year.
480-
481-
The value of `i0` can be set to `0` because all of our various terms and
482-
equations (`ICFN(i,N)`, `NPMT(i)`) have been defined to remove their singularity
483-
at `i=0`. Those functions are now continuous (and probably infinitely
484-
differentiable) at `i=0`.
485-
486-
The value of `i1` is actually specified as `IYR1` of 100%, a nominal yearly rate
487-
of 100%. Most real-life problems will never need to search for an interest rate
488-
higher than 100%/year. The `i1` variable is `IYR/PYR` or `100%/PYR` or `1/PYR`.
521+
guesses to be provided. The TVM Solver (v0.12.0) uses the following defaults:
522+
523+
- `IYR1` = -50%
524+
- `IYR2` = 100%
525+
526+
We calculate the internal payment-period initial guesses `i1` and `i2` using the
527+
formula `i=expm1[(CYR/PYR) log1p(IYR/CYR)]` as given above. From these starting
528+
points `i1` and `i2`, the TVM Solver makes a few more heuristic guesses:
529+
530+
- If the interval `[i1, i2]` overlaps the 0% point, the intervals are split into
531+
two on either side of the `0`:
532+
- `[i1,0]` and `[0,i2]`
533+
- the positive interest interval `[0,i2]` is checked first, and if no sign
534+
change is detected, then,
535+
- the negative interest interval is checked
536+
- If no sign change is detected in either `[i1,0]` and `[0,i2]`, then we take
537+
the positive interval `[0,i2]` and decompose that into 2 intervals again:
538+
- check the lower interval `[0,(i1+i2)/2]` first, and if no sign change
539+
is found, then
540+
- check the upper interval `[(i1+i2)/2, i2]`
541+
542+
The value of `i=0` is allowed in the various candidate intervals because all of
543+
our various terms and equations (`ICFN(i,N)`, `NPMT(i)`) have been defined to
544+
remove their singularity at `i=0`. Those functions are now continuous (and
545+
probably infinitely differentiable) at `i=0`.
489546

490547
The following posts by Albert Chan suggest that there are better initial guess:
491548

@@ -502,38 +559,46 @@ checks if the very first guesses bracket a root with a change in sign of the
502559
`NPMT(i)` function. If no sign change is detected, a `TVM No Solution` error
503560
message is returned.
504561

505-
### Tolerance
562+
### Terminating Conditions
506563

507-
Currently (v0.9.0), the TVM Solver iterates until the relative tolerance between
508-
two successive iterations is less than 1e-8. The value of 1e-8 is hardcoded.
564+
TVM Solver iterates until the relative tolerance between two successive
565+
iterations is less than some amount. The root finding iteration stops when one
566+
of the following conditions are met:
509567

510-
To avoid division by zero, the tolerance is calculated as:
568+
- `f0==0`
569+
- `f1==0`
570+
- `f1==f0` and `iterationCount>=3`
571+
- `|i1-i0|<=tol*max(|i1|,|i0|)`, `tol=1e-10`
511572

512-
```
513-
|i1 - i0| / |i1|, if |i1|!=0
514-
/
515-
tol =
516-
\
517-
|i1 - i0|, if i1==0
573+
The values `f0` and `f1` are defined to be `f0=NPMT(i0)` and `f1=NPMT(i1)` and
574+
the conditions `f0==0` and `f1==0` detect the situation where an iteration lands
575+
directly on the root of the equation.
518576

519-
```
577+
The `f1==f0` condition happens when the 2 successive iteration produces no
578+
change in the value of `NPMT(i)`. The `iterationCount>=3` comes from avoiding
579+
the situation where the very early guesses just happened to evaluate to a secant
580+
line with zero slope, which results in a division-by-zero error when evaluating
581+
the next iteration.
520582

521-
I am sure this is not optimal, but I needed a quick way to avoid a division by
522-
zero if `i1` was equal to zero.
583+
The complicated equation involving the `tol` parameter detects the convergence
584+
of successive iterations of `i0` and `i1`. The equation was selected to deal
585+
with situations where the solution converges to a value that is equal or very
586+
close to `0`.
523587

524-
Maybe the tolerance limit (1e-8) should be exposed to the user and be
525-
configurable? I believe the HP calculators use the number of significant digits
526-
in its `FIX` mode to determine the tolerance limit. But TI calculator users tend
527-
not to use `FIX` modes, leaving the calculator with the maximum number of
528-
significant digits (i.e. the `FIX(-)` mode). I'm not sure that using the number
529-
of digits from the `FIX` mode is a reasonable mechanism for the RPN83P app.
588+
The tolerance limit (`tol=1e-10`) is hard coded and not configurable by the
589+
user. (I'm not sure if it's useful to make that configurable). I believe the HP
590+
calculators use the number of significant digits in its `FIX` mode to determine
591+
the tolerance limit. But TI calculator users tend not to use `FIX` modes,
592+
leaving the calculator with the maximum number of significant digits (i.e. the
593+
`FIX(-)` mode). I'm not sure that using the number of digits from the `FIX` mode
594+
is a reasonable mechanism for the RPN83P app.
530595

531596
### Maximum Iterations
532597

533598
To avoid an infinite loop, the maximum iterations used by the TVM Solver is
534599
limited to `TMAX`. By default, `TMAX` is set to 15, but can be configured by the
535600
user. Empirically, the TVM Solver (using the Secant method) seems to converge to
536-
the tolerance of 1e-8 within about 7-8 iterations. So I set the default `TMAX`
601+
the tolerance of 1e-10 within about 7-8 iterations. So I set the default `TMAX`
537602
to be about double that, which is where the 15 came from.
538603

539604
### Convergence

docs/USER_GUIDE.md

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
RPN calculator app for the TI-83 Plus and TI-84 Plus inspired by the HP-42S.
44

5-
**Version**: 0.11.0 (2024-05-28)
5+
**Version**: 0.12.0-rc1 (2024-06-18)
66

77
**Project Home**: https://github.com/bxparks/rpn83p
88

@@ -150,7 +150,8 @@ Summary of features:
150150
- carry flag and bit masks: `CCF`, `SCF`, `CF?`, `CB`, `SB`, `B?`
151151
- word sizes: `WSIZ`, `WSZ?`: 8, 16, 24, 32 bits
152152
- time value of money (TVM), inspired by HP-12C, HP-17B, and HP-30b
153-
- `N`, `I%YR`, `PV`, `PMT`, `FV`, `P/YR`, `BEG`, `END`, `CLTV` (clear TVM)
153+
- `N`, `I%YR`, `PV`, `PMT`, `FV`
154+
- `P/YR`, `C/YR`, `BEG`, `END`, `CLTV` (clear TVM)
154155
- complex numbers, inspired by HP-42S and HP-35s
155156
- stored in RPN stack registers (`X`, `Y`, `Z`, `T`, `LASTX`) and storage
156157
registers `R00-R99`
@@ -1420,6 +1421,7 @@ buttons just under the LCD screen. Use the `UP`, `DOWN`, `ON` (EXIT/ESC), and
14201421
- `PMT`: set or calculate Payment per period
14211422
- `FV`: set or calculate Future Value
14221423
- `P/YR`: set number of payments per year
1424+
- `C/YR`: set number of compoundings per year
14231425
- `BEG`: payment occurs at the Beginning of each period
14241426
- `END`: payment occurs at the End of each period
14251427
- `CLTV`: clear TVM variables and parameters
@@ -2163,16 +2165,17 @@ The RPN83P app interacts with the underlying TI-OS in the following ways.
21632165
exiting. Changing the `MODE` settings in one app will not cause changes to
21642166
the other.
21652167
- TVM variables
2166-
- RPN83P uses some of the same TI-OS floating point variables used by the
2167-
`Finance` app (automatically provided by the TI-OS on the TI-84 Plus).
2168-
- `N`, `I%YR`, `PV`, `PMT`, `FV`, and `P/YR`
2169-
- These variables appear in the Finance app with slightly different names:
2170-
- `N`, `I%`, `PV`, `PMT`, `FV`, and `P/Y`
2171-
- Two variables not synchronized between the 2 apps are:
2172-
- `BEG`/`END` flag
2173-
- could not figure out where the Finance app stores this
2174-
- `C/Y` (compoundings per year)
2175-
- always set equal to `P/YR` in the RPN83P app
2168+
- RPN83P uses the exact same TI-OS floating point variables and flags used
2169+
by the `Finance` app (automatically provided by the TI-OS on the TI-84
2170+
Plus). When these variables are changed in RPN83P, they automatically
2171+
appear in the `Finance` app, and vise versa:
2172+
- RPN83P variable names:
2173+
- `N`, `I%YR`, `PV`, `PMT`, `FV`, `P/YR`, `C/YR`, `BEG`, `END`
2174+
- TI-OS Finance app variable names:
2175+
- `N`, `I%`, `PV`, `PMT`, `FV`, `P/Y`, `C/Y`, `BEGIN`, `END`
2176+
- An interesting consequence of sharing these variables with the TI-OS
2177+
Finance app is that these are the only RPN83P variables which are *not*
2178+
saved in the `RPN83SAV` appVar.
21762179

21772180
## Future Enhancements
21782181

docs/USER_GUIDE_BASE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
# RPN83P User Guide: BASE Operations
1+
# RPN83P User Guide: BASE Functions
22

33
This document describes the `BASE` functions of the RPN83P application which
44
allow numbers to be converted between 4 different bases (DEC, HEX, OCT, and BIN)
55
and support various arithmetic and bitwise operations similar to the HP-16C. It
66
has been extracted from [USER_GUIDE.md](USER_GUIDE.md) due to its length.
77

8-
**Version**: 0.11.0 (2024-05-28)
8+
**Version**: 0.12.0-rc1 (2024-06-18)
99

1010
**Parent Document**: [USER_GUIDE.md](USER_GUIDE.md)
1111

docs/USER_GUIDE_COMPLEX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ independent of each other. For example, a complex number can be entered in
1010
rectangular form, even if the current display mode is polar form. Internally,
1111
complex numbers are *always* stored in rectangular format.
1212

13-
**Version**: 0.11.0 (2024-05-28)
13+
**Version**: 0.12.0-rc1 (2024-06-18)
1414

1515
**Parent Document**: [USER_GUIDE.md](USER_GUIDE.md)
1616

0 commit comments

Comments
 (0)