fixed finance/discounting, added finance/NPV, finance/IRR

This commit is contained in:
zeroflag 2021-08-03 00:25:21 +02:00
parent 7fa71a71a9
commit 390fce921c
5 changed files with 45 additions and 3 deletions

View file

@ -85,6 +85,7 @@
: remove ( l o -- l ) swap :remove/O jvm-call-method ;
: keys ( d -- l ) :keys jvm-call-method ;
: values ( d -- l ) :values jvm-call-method ;
: sum ( c -- n ) 0 swap { + } each ;
: ... ( lower upper step -- lst ) :com.vectron.fcl.types.Range/create/NNN jvm-call-static ;
: .. ( lower upper -- lst ) 1 ... ;

View file

@ -24,6 +24,7 @@
: else immediate ['] jmp , (dummy) swap resolve ;
: then immediate resolve ;
: begin immediate here ;
: again immediate ['] jmp , (offset) ;
: while immediate ['] jmp#f , (dummy) ;
: repeat immediate swap ['] jmp , (offset) resolve ;
: until immediate ['] jmp#f , (offset) ;

View file

@ -18,3 +18,33 @@
: torch ( n -- ) :com.vectron.forthcalc.support.Torch/toggle/O jvm-call-static ;
: match: immediate ` lastword set-predicate ;
: npv ( cashflow rate -- n )
-> rate 0 => year
{ rate year @ dis year inc } map sum ;
: npv* ( .. rate -- n ) >r list* r> npv ;
: npv/npv' ( cashflow rate -- npv/npv' )
1+ -> rate 0 => n
0 0 rot {
dup ( each ) n @ neg * rate n @ 1+ neg pow * ( npv' ) rot +
swap ( each ) rate n @ pow / ( npv ) rot +
swap
n inc
} each / ;
var: irr-guess 0 irr-guess !
: irr ( cashflow -- n/nil )
-> cashflow irr-guess @ 100 / => guess
1000 0 do
guess @ cashflow guess @ npv/npv' - ( new guess )
dup guess @ - abs 0.01 < if
100 * unloop exit
then
guess !
loop
nil ;
: irr* ( cashflow -- n ) list* irr ;

View file

@ -18,7 +18,7 @@
( years ) 1 -
repeat
drop ( years ) r> r> 2drop ;
: dis ( b i n -- t ) swap 100 / neg 1+ swap pow * ;
: dis ( b i n -- t ) swap 100 / 1+ swap pow / ;
: tip1 ( n -- n ) 15 percent ;
: tip2 ( bill split -- total tip ) / dup 115 percent swap 15 percent ;
( trigonometry )

View file

@ -67,6 +67,7 @@ public class FclTest {
@After
public void tearDown() throws Exception {
System.out.println("Transcript: " + transcript.content());
assertEquals(0, fcl.stackSize());
assertEquals(0, fcl.rStackSize());
assertEquals(0, evalPop("psp @").longValue());
@ -210,12 +211,19 @@ public class FclTest {
@Test
public void testFinance() {
assertEquals(1216.65, evalPop("1000 4 5 cin1").doubleValue(), 0.01);
assertEquals(815.37, evalPop("1000 4 5 dis").doubleValue(), 0.01);
assertEquals(821.93, evalPop("1000 4 5 dis").doubleValue(), 0.01);
assertEquals(558.39, evalPop("1000 6 10 dis").doubleValue(), 0.01);
evalDoubles("1000.0 4 5 100 cin2", asList(1000.0, 2240.0, 3529.6, 4870.784, 6265.61536, 7716.2399744));
assertEquals(15, evalPop("100 tip1").doubleValue(), 0.01);
evalDoubles("100 1 tip2", asList(115.0, 15.0));
evalDoubles("100 3 tip2", asList(38.33, 5));
evalDoubles("3421 5 tip2", asList(786.83, 102.63));
assertEquals(-371.68, evalPop("[ -1000 50 100 150 200 250 ] 5 npv").doubleValue(), 0.01);
assertEquals(-371.68, evalPop("-1000 50 100 150 200 250 5 npv*").doubleValue(), 0.01);
assertEquals(-250, evalPop("[ -1000 50 100 150 200 250 ] 0 npv").doubleValue(), 0.01);
assertEquals(12.006, evalPop("[ -500 50 100 150 200 250 ] irr").doubleValue(), 0.01);
assertEquals(-7.431, evalPop("[ -1000 50 100 150 200 250 ] irr").doubleValue(), 0.01);
assertEquals(-28.482, evalPop("-10 irr-guess ! -5000 200 230 400 202 450 irr*").doubleValue(), 0.01);
}
private void evalDoubles(String script, List<Number> expected) {
@ -809,6 +817,8 @@ public class FclTest {
assertEquals(true, evalPop("m 2 at").boolValue());
assertEquals(1, evalPop("m 2 index-of").intValue());
assertEquals(0, evalPop("m clear m size").intValue());
assertEquals(6, evalPop("[ 4 -1 3 ] sum").intValue());
assertEquals(1+2+3+4+5, evalPop("1 5 .. sum").intValue());
}
@Test