Looking for TVM contributions
|
06-18-2024, 09:22 AM
Post: #61
|
|||
|
|||
RE: Looking for TVM contributions
(06-18-2024 03:27 AM)robve Wrote: Let me illustrate with the "time reversed" TVM problem, which is essentially the same. The forward npmt() is best for this TVM example (the backward npmt() line is fatter): I think both time direction are equally good here. 1 ULP difference, may even be caused by scaling by 100 for percentage! If I have to pick one, I would go for r = expm1(log1p(i)*n) to be positive. (== i*n > 0) We can map positive to negative without too much error, but not the other way. lua> i, n = .1, 100 lua> r1, r2 = EFF(i,n), EFF(i,-n) lua> r1, r2 13779.612339822266 -0.9999274342840985 lua> -r2/(1+r2), -r1/(1+r1) 13779.612339813315 -0.9999274342840985 But, there are many things going on ... this is only 1 factor out of many. See solve for n example, https://www.hpmuseum.org/forum/thread-21...#pid187533 |
|||
06-18-2024, 11:59 AM
Post: #62
|
|||
|
|||
RE: Looking for TVM contributions
(06-17-2024 09:03 PM)robve Wrote: Assuming TYPE is 0 for END and 1 for BGN, then we recognize PV and FV are switched and their signs inverted and N is inverted: Time reversed NFV turns into NPV, and vice versa. We are solving same problem, but curve totally different. (05-31-2024 10:39 PM)Albert Chan Wrote: 10 B=1 @ N=40 @ P=900 @ M=-40 @ F=-1000 Let's turn NPV into NFV for rate problem, by time-reversal. >15 VARSWAP P,F @ M=-M @ N=-N >run 11.3570289363 36923.539379 2.35993812666 -1387.63023153 2.68581267787 -1287.38125489 6.87064131886 3585.77746844 3.79135227821 -769.04731268 4.33514429757 -379.62865086 4.86526534953 115.24756927 4.7418099072 -11.55575603 4.75306056619 -.30740914 4.75336803852 .00085219 4.75336718851 -.00000007 Very unstable with multiple overshoot. NFV (n>0) formula for rate not recommended |
|||
06-18-2024, 06:15 PM
(This post was last modified: 06-18-2024 11:47 PM by Albert Chan.)
Post: #63
|
|||
|
|||
RE: Looking for TVM contributions
Hi, robve
I was looking at your test samples pdf. #23 just quit, returned NaN Fix is simple, have Secant's initial 2 points guaranteed one-sided convergence. Bonus: this allowed for simple no solution test, just like Newton's method. 1st point = edge (X = -PV or FV) --> edge rate = PMT/X I recently showed edge rate is really result of Newton's from *extreme* rates, -1 or ∞ Turns out, whatever edge X we pick, slope (from extreme) is -X ! 2nd point = PMT/X + f(PMT/X) / X // not as good as Newton on PMT/X, but good enough Just as Newton's final half-correction, we do the same for Secants. 10 INPUT "B,N,P,M,F? ";B,N,P,M,F 20 IF B THEN P=P+M @ F=F-M ! end mode 30 IF ABS(P)>ABS(F) THEN X=F @ F=-P @ P=-X @ N=-N ! time reversed 40 DEF FNF(I) @ IF N*I*I+1-1 THEN FNF=((P+F)/EXPM1(LOGP1(I)*N)+P)*I+M @ END 50 Z=P+F @ FNF=(Z+N*M+I*((Z+N*(P-F))/2+I*Z*(N*N-1)/12))/N @ END DEF 60 X=F @ IF M/X<=-1 THEN X=-P ! guess = edge X 70 I0=M/X @ Y0=FNF(I0) @ I=I0+Y0/X @ Y=FNF(I) @ DISP 100*I0,Y0 80 DISP 100*I,Y @ Z=I-I0 @ I0=I @ I=I-Y*Z/(Y-Y0) @ Y0=Y @ Y=FNF(I) 90 IF SGN(Y)=SGN(Y0) AND ABS(Y)<ABS(Y0) THEN 80 100 DISP 100*I,Y @ IF Y-Y0 THEN J=I-Y*(I-I0)/(Y-Y0)/2 @ DISP 100*J Code use small edge (LINE 60), but we can use the other, as long as edge rate is valid. >run ! sample #23 B,N,P,M,F? 0,10,50,-30,80 -37.5 .4474481846 -36.9406897692 .0348105026 -36.8935058326 .0000999938 -36.8933699054 .0000000229 -36.8933698743 .0000000002 -36.893369874 0 -36.893369874 >X=-P @ run 70 ! small P, big edge 60 .7159170954 58.5681658092 .0493058621 58.4622602744 .0001415644 58.4619553284 .0000000289 58.4619552661 -.0000000001 58.4619552662 Although -X slope proof assumed positive N, time-symmetry make it valid for negative N too Example, if we swap (P, F), code will do time-reversal to keep size of P small. >run B,N,P,M,F? 0,10,80,-30,50 37.5 2.1052759718 34.8684050352 .291631744 34.4452478265 .0037390629 34.4397519889 .0000071623 34.4397414412 0 34.4397414412 >X=-P @ run 70 ! small P, big edge -60 .0081797505 -59.983640499 .0000312799 -59.983577699 .0000000002 -59.9835776986 0 -59.9835776986 Lets test tiny rate branch (LINE 50) >run ! sample #21 B,N,P,M,F? 0,480,100000,-208.333333,0 .208333333 121.444894064 .086888438936 46.544537395 1.14202213657E-2 5.774169845 7.319118817E-4 .366932959 6.607422444E-6 .003310945 3.19310587E-9 1.93321242436E-6 -6.652600197E-10 1.03444729167E-11 -6.65280665633E-10 -0 -6.65280665633E-10 What about no solution case? Y get worse no sign change, and I not converging. B,N,P,M,F? 0,10,1000,-287,2000 -14.35 116.137711015 -8.54311444925 61.534445887 -1.99911961932 20.995382798 1.39004791475 8.609614417 3.74593127745 3.290957549 5.20365121116 1.292347407 6.14624653622 .507826981 6.75639679154 .207532994 7.17807126641 .093719606 7.52529900771 .056815067 8.05986109467 .099136777 6.80767250381 Update: I made a stupid mistake, using X for everything. Now X refer only to edge, and I use Z for temp variable. |
|||
06-18-2024, 11:54 PM
Post: #64
|
|||
|
|||
RE: Looking for TVM contributions
Here is rate search method comparison, Secant vs Newton
Code: SECANT NEWTON |
|||
06-19-2024, 12:57 AM
(This post was last modified: 06-19-2024 02:47 AM by robve.)
Post: #65
|
|||
|
|||
RE: Looking for TVM contributions
(06-18-2024 06:15 PM)Albert Chan Wrote: I was looking at your test samples pdf. #23 just quit, returned NaN That's because guess_i() returns i%=101.94 that npmt cannot handle. If I go back to a small initial I% it works fine. I just left it in for now, knowing that iguess() should be changed later after investigating before deciding. By the way, this iguess() function is your suggested initial best guess. It is the same test as on the contributions list of benchmarks #6. - Rob EDIT: I realize it may be a bit difficult to see the TVM parameters in the PDF. They are n, i% (to solve with ?), pv, pmt, fv below (the last one is a repeat which I neglected to take out): ./tvm 40 ? 900 -40 -1000 1 ./tvm 40 ? 900 1000 -1000 1 ./tvm 40 ? 900 -400 -1000 1 ./tvm 31536000 ? 0 -0.01 331667.0067 ./tvm 525600 ? 0 -0.01 5282.36776893622391 ./tvm 525600 ? 0 -0.01 5260.38242600032663 ./tvm 32 ? -999999 0 1000000 ./tvm 360 ? 0 -1000 1000000 ./tvm 328 ? 35000 -324 0 ./tvm 58 ? -775 -49.56 4000 ./tvm 32 ? -6000 0 10000 ./tvm 48 ? 19198.60 -450 0 ./tvm 5 ? -369494.09 17500 540000 ./tvm 348 ? 243400 -1363.29 0 ./tvm 30 ? -3200 -717.44 60000 ./tvm 60 ? 243400 -1363.29 -222975.98 ./tvm 24 ? 0 -50.26 1281.34 ./tvm 6 ? -32000 0 28346.96 ./tvm 60 ? 8000 -150.97 0 ./tvm 456 ? 270000 -1215.3333333333 0 ./tvm 480 ? 100000 -208.333333333333343 0 ./tvm 10 ? 50 -30 400 ./tvm 10 ? 50 -30 80 ./tvm 10 ? -100 10 1e-10 ./tvm 32 ? -999999 0 1e6 ./tvm 525600 ? 0 -0.01 5260.38242600032663 ./tvm 40 ? 900 -400 -1000 1 EDIT 2: the nan problem with iguess() returning a rate larger than 100% can be fixed with a test such as: Code: i = iguess(); Then we get an answer: evals=7, i%=-36.8933698741777363%, FVerror=1.4e-14 But is +/-50% a reasonable new starting point to always avoid this? Don't think so. It looks like your idea to use edge is nice. "I count on old friends to remain rational" |
|||
06-19-2024, 02:01 AM
(This post was last modified: 06-19-2024 02:31 AM by robve.)
Post: #66
|
|||
|
|||
RE: Looking for TVM contributions
(06-18-2024 11:54 PM)Albert Chan Wrote: Here is rate search method comparison, Secant vs. Newton. I'm no longer just comparing Secant vs. Newton, because we know Secant takes more steps. I'm comparing Hybrid to Newton. I'm doing these important things: - optionally allow one or more retries after overshooting, this is parameter g. When g=0 we stop. When g=1 we allow one retry to run iterations again after overshooting from the current I%. - if the final iteration when we stop y=npmt() is nonzero, then we should pick the previous i%, not the last that overshot. - I'm measuring FVerror to check the TVM model's accuracy with the i% solved, not the i% rate places because some final digits simply don't matter, it's not anomalous. - I count npmt() evaluations, not steps, because Secant requires two initial i% which we count as 2 evaluations. - for termination test I use for the Secant, Newton and Hybrid implementations: Code: } while (y != 0.0 && fabs(y) < fabs(w)) My improved Newton implementation: Code: i = iguess(); As you can see, it iterates until a root was found or when overshooting. When overshooting and g=1 then we continue iterating again until a root or overshooting. After overshooting we pick the previous i% which is closer to the root. The results Newton with g=0 and g=1 versus Hybrid with g=0. Hybrid easily beats Newton: tvmperfcomp-newton-hybrid.pdf (Size: 34.65 KB / Downloads: 5) I'm curious what your implementation does differently. Or if I'm doing something wrong. Perhaps the difference is that our convergence tests aren't the same? But from the first test in your list, it looks to me that it has the same number of evaluations: 1 initial npmt and 4 steps npmt = 5 evals. These evals are all nptm + derivative, so more expensive than the Hybrid method that only uses the derivative once after the initial guess. PS. As I had mentioned before, Newton's derivate expression has subtle evaluation errors that get worse as we get closer to the root. Newton requires both npmt and derivative to be very precise (like having both a fat line to evaluate f(i%) and a sloppy slope to evaluate f'(i%)). Secant just takes the slope of two npmt points. Secant only uses npmt. In other words, it's less risky as we get closer to the root. The Newton convergence slows down anyway, no longer quadratic or better. - Rob "I count on old friends to remain rational" |
|||
06-19-2024, 12:20 PM
Post: #67
|
|||
|
|||
RE: Looking for TVM contributions
Hi, robve
Here is plot of f(x) = ((pv+fv)/((1+x)^n-1) + pv)*x + pmt, for test sample #23 I also showed asymptote line, f(x → ∞) = pv*x + pmt plot {(130/((1+x)^10-1)+50)*x-30 , 50x-30}, x = 0 .. 1 And for the other root, also with asymptote line, f(x → -1) = -fv*x + pmt plot {(130/((1+x)^10-1)+50)*x-30 , -80x-30}, x = -0.5 .. 0 Goal is to iterate rate from the outside, going in. Edge rates are where asymptote line intersect to x-axis, thus always outside. If we iterate from the inside, Newton will definitely overshoot ... perhaps by a lot. Since asymptote line slope is more extreme (in size) than at any other point, we can use it for Secant's 2nd point, and have a second guess, also from outside. (06-19-2024 02:01 AM)robve Wrote: - optionally allow one or more retries after overshooting, this is parameter g. When g=0 we stop. When g=1 we allow one retry to run iterations again after overshooting from the current I%. I assumed when you say overshoot, it means f changes sign. With correct guess for f (concave up or down), there is no need to retry after overshoot. With wrong guess, Newton's next guess should overshoot back to the outside, so g=1 It is not as simple for Secant's method. It may take a while before *both* points are outside. Quote:- if the final iteration when we stop y=npmt() is nonzero, then we should pick the previous i%, not the last that overshot. If previous i% from the outside, overshoot is not really an overshoot, we should keep it. If previous i% from the inside, we don't really know which is better. All we know is true rate is somewhere between the two. Quote:- I'm measuring FVerror to check the TVM model's accuracy with the i% solved, not the i% rate places because some final digits simply don't matter, it's not anomalous. If i% getting very accurate (error of few ULP's), FVerror probably not that useful Example, here we compare, for a given rate, calculated PMT vs FV lua> n,i,pv,pmt,fv = 10,nil,50,-30,80 -- sample #23 lua> i = tvm(n,i,pv,pmt,fv) lua> for k=0,5 do print(i, tvm(n,i,pv,nil,fv), tvm(n,i,pv,pmt,nil)); i=nextafter(i) end Code: -0.36893369874177734 -29.999999999999996 80.00000000000001 Since rate search is solving npmt=0, it look like our solved i is good, so does (i+1ULP) Using Plus42 for reference, true rate is (i+0.87ULP) = (i+1ULP) - 0.13 ULP But from FV numbers, true rate = (i+2ULP) I am not suggesting PMT_error is better test than FV_error. It is just that solved i is too accurate for these tests to work. From what I can tell, all your methods look equally good. Quote:- for termination test I use for the Secant, Newton and Hybrid implementations: From wrong guess, we don't know if y is always improving (toward 0). Unless your guesses are from the outside, (fabs(y) < fabs(w)) is probably wrong. Quote:... Newton's derivate expression has subtle evaluation errors that get worse as we get closer to the root. Since both Newton and Secant are self-correcting, we can simply look at last 2 points. With 2 points close together, Secant's slope is going to be much worse than Newton's. With both methods use the *same* f, and Newton get better f', I would think Newton is better. Of course, final f is tiny, and not very accurate. Perhaps more accurate f' make no difference. |
|||
06-19-2024, 03:40 PM
(This post was last modified: 06-19-2024 03:51 PM by Albert Chan.)
Post: #68
|
|||
|
|||
RE: Looking for TVM contributions
(06-19-2024 12:20 PM)Albert Chan Wrote: asymptote line slope is more extreme (in size) than at any other point, Here is a trick that work with any rate guess, and have one-sided convergence. lua> n,pv,pmt,fv = 10,50,-30,80 -- sample #23 lua> f = fn'x: npmt(n,x,pv,pmt,fv)' lua> i = 0.01 -- any guess OK lua> X = -pv -- go for big root lua> for k=1,5 do eps=f(i)/X; i=i+eps; print(i, eps) end 0.3514866009669545 0.3414866009669545 0.5527206785990931 0.20123407763213863 0.5821388175291544 0.029418138930061274 0.5844404930347874 0.002301675505633014 0.5846067021783057 0.0001662091435182589 We can speed up convergence, with smaller slope. What is the ideal slope? We assume constant rate of convergence. lua> r = 0.0001662091435182589 / 0.002301675505633014 lua> X = X * (1-r) lua> for k=1,5 do eps=f(i)/X; i=i+eps; print(i, eps) end 0.5846195592477864 1.2857069480758773e-05 0.5846195526588186 -6.588967862434568e-09 0.5846195526622116 3.3930050292746237e-12 0.5846195526622099 -1.6848616523122454e-15 0.5846195526622099 -0 |
|||
06-19-2024, 03:47 PM
(This post was last modified: 06-19-2024 05:27 PM by robve.)
Post: #69
|
|||
|
|||
RE: Looking for TVM contributions
I realize dumping a set of results with code isn't helping much to further this discussion. I'm happy to comment on questions and to avoid confusion.
(06-19-2024 12:20 PM)Albert Chan Wrote:(06-19-2024 02:01 AM)robve Wrote: - optionally allow one or more retries after overshooting, this is parameter g. When g=0 we stop. When g=1 we allow one retry to run iterations again after overshooting from the current I%. No. See code of the termination test. It's when the magnitude of npmt increases rather than monotonically drops in magnitude. Sign is completely ignored. Sign changes are fine and can happen as an overshoot, but that can be an overshoot that is not necessarily detrimental. It can be auto-corrected and often will. I don't understand why sign change should be treated differently. In fact, I initially tried your suggestion to take sign changes into account in the termination test. But the experimental results were worse for several tests in C double precision and on a 10 BCD calculator. The npmt sign can flip due to overshooting, but it is not necessarily bad and we should never stop right after the sign flips as was shown in the HP-71B code. It can be auto-corrected. So we want to keep iterating. This put me on the wrong path and I eventually dropped it from the termination tests. (06-19-2024 12:20 PM)Albert Chan Wrote:Quote:- if the final iteration when we stop y=npmt() is nonzero, then we should pick the previous i%, not the last that overshot. The term "overshoot" is confusing perhaps. An overshoot is not necessarily bad. I'm talking about non-monotonicity, i.e. when moving away from the root when the npmt magnitude increases. If we move away and we stop when that happens, then experiments show it is better to use the previous i% since we made a bad overshoot. A bad overshoot can be many orders of magnitude away from the root! There are plenty of examples, such as this TVM problem: n=480 pv=100000 pmt=-208.333333333333343 fv=0 evals=4, i%=-1.39404957469160446e-17%, FVerror=5.4e+05 (06-19-2024 12:20 PM)Albert Chan Wrote: If previous i% from the inside, we don't really know which is better. Yes. For example, I tested the use of a weighted average of i% after stopping with a sign change to judge where the root might be. But it didn't help to improve the result. Experimenting with this showed that taking the previous i% appears to reduce errors in i%. There is no theoretical argument why this should be bad. After all, it all is part of the solving sequence of points. But taking the last value when things go haywire is sure to be terrible. See the example above. (06-19-2024 12:20 PM)Albert Chan Wrote:Quote:- I'm measuring FVerror to check the TVM model's accuracy with the i% solved, not the i% rate places because some final digits simply don't matter, it's not anomalous. Perhaps FV error, or PV error (also when "time reversed") or PMT error are all OK. When testing dozens of TVM cases I saw that FV error is more sensitive to an i% deviation. By contrast, comparing i% digits to a higher precision i% solver is not meaningful when finding "better" values with a lower precision solver is impossible both theoretically and practically. A solver should just do its job well enough to limit the TVM model error to ensure TVM computations are reversible in most cases. Getting 1 or 2 ULP error in the other TVM parameters after solving to is attainable and should suffice to maintain TVM model equilibrium. (06-19-2024 12:20 PM)Albert Chan Wrote:Quote:- for termination test I use for the Secant, Newton and Hybrid implementations: There is no sign change test to stop at, so starting inside/outside shouldn't matter as much. We can't control the error in the slope to avoid a sign change in the first place. It will happen. The fabs(y) < fabs(w) was also in your code, so... (06-19-2024 12:20 PM)Albert Chan Wrote:Quote:... Newton's derivate expression has subtle evaluation errors that get worse as we get closer to the root. How? I don't see it in the experiments. You're assuming the two point npmt values have errors in different directions. Then it is worse. But expression evaluation errors in two close points are highly correlated, not independent. Claiming Secant is going to be much worse in general, i.e. assuming these errors are independent, is a stretch. Furthermore, if the two points are very close so that expression evaluation for the two points return the same npmt value, then we should stop because the two points are very close to the root numerically and we can pick either point. Let me also add that self-correcting can also mean over-correcting when the correction suffers from inaccuracies, which the Newton derivative is not immune to, far from it (06-19-2024 12:20 PM)Albert Chan Wrote: With both methods use the *same* f, and Newton get better f', I would think Newton is better. I never said Secant is better than Newton. All I'm saying is that the Hybrid appears to be a promising approach (see code and results in the PDF). I'm not sure why you seem so skeptical when the evidence is there using a set of TVM problems I took from the HP forums (i.e. unbiased). Try the code if you don't believe the numbers. I'm not completely happy about the iguess() (it's your guess_i() code by the way), which works fine in END mode, but is not as good in BEGIN mode. It also can return an overflow >100% causing NaN. I can replicate your symbolic derivation and understand it, but inserting a BEGIN mode adjustment that requires i% itself that we want to guess is something to figure out. EDIT: I don't use "time reversal" when testing TVM rate solving, because I want to test and compare the solvers on whatever inputs are given, not on modified input that suits the solver. After all, the TVM problems are meant to test TVM rate solving under strain. - Rob EDIT: fixed typo "I count on old friends to remain rational" |
|||
06-19-2024, 09:06 PM
(This post was last modified: 06-19-2024 10:39 PM by Albert Chan.)
Post: #70
|
|||
|
|||
RE: Looking for TVM contributions
(06-19-2024 03:47 PM)robve Wrote: n=480 pv=100000 pmt=-208.333333333333343 fv=0 (-pmt) > (pv/n), by a smudge. I would expect positive rate (0 is good too) Still, -1.4e-17% is not too bad (using fma, true rate = +1.89e-17%) i ≈ 1/p - p/n² = (n²-p²)/(p*n²) = (n+p)*(n-p) / (p*n²) -- where p=-pv/pmt lua> fma(n,pmt,-pv) * fma(n,pmt,pv) / (-pv*pmt*n*n) -- scale by pmt²/pmt² 1.8947806286936e-19 More concerning is huge FVerror, perhaps bug in FV code? n=480 pv=100000 pmt=-208.333333333333343 fv=-5.4e+5 --> solve rate = 0.4598% ? (06-19-2024 12:20 PM)Albert Chan Wrote: Since both Newton and Secant are self-correcting, we can simply look at last 2 points. robve Wrote:How? I don't see it in the experiments. You're assuming the two point npmt values have errors in different directions. Then it is worse. But expression evaluation errors in two close points are highly correlated, not independent. Claiming Secant is going to be much worse in general, i.e. assuming these errors are independent, is a stretch. I said Secant's slope is worse, not Secant's method. Here is an example, Newton's slope with 15 good digits, Secant's slope only 1 Assuming last point from Newton and Secant reach about the same place. Newton final step: x - y / y' Secant final step: x - y / ((y-y0)/(x-x0)) Also, you missed my conclusion. Bad slope might not matter. (06-19-2024 12:20 PM)Albert Chan Wrote: With both methods use the *same* f, and Newton get better f', I would think Newton is better. robve Wrote:I'm not completely happy about the iguess() (it's your guess_i() code by the way), which works fine in END mode, but is not as good in BEGIN mode. It also can return an overflow >100% causing NaN. guess_i() is retired from use. Edge rate is now preferred. Anyway, BEGIN mode {n,pv,pmt,fv} == END mode {n,pv+pmt,pmt,fv-pmt} test sample #1 Wrote:./tvm 40 ? 900 -40 -1000 1 lua> n,pv,pmt,fv = 40,900,-40,-1000 -- BEGIN mode lua> pv,fv = pv+pmt, fv-pmt -- END mode lua> n,pv,pmt,fv 40 860 -40 -960 lua> pmt/fv, pmt/-pv 0.041666666666666664 0.046511627906976744 1 sign changes --> 1 solution, either edge is good. |
|||
06-19-2024, 09:08 PM
Post: #71
|
|||
|
|||
RE: Looking for TVM contributions
robve Wrote:The npmt sign can flip due to overshooting, but it is not necessarily bad and we should never stop right after the sign flips as was shown in the HP-71B code. It can be auto-corrected. So we want to keep iterating... I think we are solving rate problem with different approach. Your code seems to treat f(x) like a black-box, and solve it with Secant/Hybrid method. Code can be easily adapted for solving other f(x)=0 problem, say, change npmt to NPV Rate guess can be changed, even user supplied. But it is not guaranteed to work. Example, test sample #23 were designed to fail Plus42 rate solver Plu42 had hard coded guess=0.0001, next iteration give an impossible rate of -200% Instead of general solver, my approach is specialized rate solver. I wanted rate solver to always work, even if more iterations required. Even harder, it had to figured out no solution case, and let user know. Before start coding, I proved npmt(x) is either concave up (or down). With this out of the way, edge guess from the outside, I get one-sided convergence. Technically this setup should never encounter overshoot (f sign flip) If we do see overshoot, it is due to rounding error (f = 0), rate is found. No more auto-correction needed. It cannot get any better. If f not improving (toward 0), and i not converging --> no solution. |
|||
06-20-2024, 02:33 AM
(This post was last modified: 06-21-2024 02:54 PM by robve.)
Post: #72
|
|||
|
|||
RE: Looking for TVM contributions
(06-19-2024 02:01 AM)robve Wrote: My improved Newton implementation: Previously in that post I showed the results for 64 bit float (double). I also have results for 128 bit floats (long double) and updated to the most recent implementations: tvmperfcomp-newton-hybrid-128bit.pdf (Size: 34.47 KB / Downloads: 3) Hybrid has lower FVerror overall. It is hard to argue that the difference in accuracy is due to roundoff alone. The implementations aren't using any tricks or special prep. They take the same initial guess, then Hybrid performs one Newton step to get the next point and iterates Secant until convergence without retrying (g=0). Two case for Newton are shown (g=0) and with one retry (g=1) after overshooting to try to find the root. - Rob "I count on old friends to remain rational" |
|||
06-20-2024, 04:03 AM
Post: #73
|
|||
|
|||
RE: Looking for TVM contributions
(06-19-2024 09:06 PM)Albert Chan Wrote:(06-19-2024 03:47 PM)robve Wrote: n=480 pv=100000 pmt=-208.333333333333343 fv=0 No. The error is in the i% result. As a consequence the TVM model's parameter space suffers large errors. With previous i% after overshooting the TVM model parameter space isn't badly affected ./tvm 480 '?' 100000 -208.333333333333343 0 1/1 i%= 1e-05 y= 0.00501045666647 2/1 i%= 7.98321085531e-11 y= 3.999917908e-08 3/1 i%= 1.03199085624e-16 y= 2.84217094304e-14 4/1 i%= 6.09287401526e-17 y= 2.84217094304e-14 4, i%=6.0928740152605195e-17% FVerror=1.5e-11 PVerr=1.5e-11 PMTerr=2.8e-14 With last i% after overshooting the TVM model parameters space error is bad: ./tvm 480 '?' 100000 -208.333333333333343 0 1/1 i%= 1e-05 y= 0.00501045666647 2/1 i%= 7.98321085531e-11 y= 3.999917908e-08 3/1 i%= 1.03199085624e-16 y= 2.84217094304e-14 4/1 i%= 6.09287401526e-17 y= 2.84217094304e-14 4, i%=-1.39404957469160446e-17% FVerr=5.4e+05 PVerr=5.4e+05 PMTerr=2.6e+02 Which result should we trust? I am inclined to accept the former over the latter. (06-19-2024 09:06 PM)Albert Chan Wrote:robve Wrote:I'm not completely happy about the iguess() (it's your guess_i() code by the way), which works fine in END mode, but is not as good in BEGIN mode. It also can return an overflow >100% causing NaN. Yes, but for iguess() adjusted for pmt this produces bad initial i% guess for some of the more extreme cases and that worries me. I don't understand why and how an adjustment can be safely made. But I digress since guess_i() is retired (it's quite good actually, except for BEGIN mode and a few other cases). For example, I noticed that adjusting pmt for BGN mode in this case n=40 pv=900 pmt=-400 fv=-1000 gives i%=371.725. Now, this is a hard example so it's not unexpected but still. (06-19-2024 09:06 PM)Albert Chan Wrote:test sample #1 Wrote:./tvm 40 ? 900 -40 -1000 1 With BEGIN mode and the Newton solver: 1/1 i%= 4.55232470519 y= -1.77265084526 2/1 i%= 4.75326326796 y=-0.000915829625612 3/1 i%= 4.75336718854 y=-2.40206077251e-10 4/1 i%= 4.75336718857 y= -7.1054273576e-15 i%=4.75336718857102181% FVerr=1.1e-13 PVerr=0 PMTerr=7.1e-15 After adjusting PV and FV for BEGIN mode there is a sign change because we start at "the wrong side" of the curve but that's no problem: 1/1 i%= 4.75977785174 y= 0.0564948432948 2/1 i%= 4.75336708491 y=-9.13549698112e-07 3/1 i%= 4.75336718857 y= 7.1054273576e-15 4/1 i%= 4.75336718857 y= -7.1054273576e-15 i%=4.75336718857102092% FVerr=2.3e-13 PVerr=0 PMTerr=7.1e-15 Both are equally good. When we have to do one more iteration to get on the right side of the curve, then that isn't a big deal. About the npmt curvature: adjusting npmt for positive f'' is just a sign change of npmt. But root finders don't need to care as we know, because they flip to the other side of the curve anyway (as shown above). Theoretically then they never need to flip back again unless f'' changes sign. For TVM f'' won't change sign I believe, but numerically there is a nonzero possibility that the sign of npmt may flip close to root due to inaccuracies, especially with lower precision solvers. That worries me. - Rob "I count on old friends to remain rational" |
|||
06-20-2024, 03:07 PM
Post: #74
|
|||
|
|||
RE: Looking for TVM contributions
(06-20-2024 04:03 AM)robve Wrote: With last i% after overshooting the TVM model parameters space error is bad: Because f(ε) was not implemented, y3 and y4 almost the same. Bad y/y' cause extrapolated i% go crazy, even its sign is wrong. f(ε) part is a 1-liner. I think it is worth adding. 40 DEF FNF(I) @ IF N*I*I+1-1 THEN FNF=((P+F)/EXPM1(LOGP1(I)*N)+P)*I+M @ END 50 Z=P+F @ FNF=(Z+N*M+I*((Z+N*(P-F))/2+I*Z*(N*N-1)/12))/N @ END DEF But bad i does not explain huge errors. How are they calculated? lua> i = -1.3940495746916044e-19 lua> NFV(480, i, 1e5, -208.333333333333343, 0) 0 lua> NPV(480, i, 1e5, -208.333333333333343, 0) 0 lua> npmt(480, i, 1e5, -208.333333333333343, 0) 0 robve Wrote:iguess() adjusted for pmt this produces bad initial i% guess for some of the more extreme cases and that worries me ... guess_i() assumed (n*i) is small, and NPMT is quadratic of rate. Above example, if we solve actual quadratic, we have imaginary numbers. Pade approx was used to return real guess, even if quadratic have no real root. BTW, why is i% > 100 a problem? I just tried 1 billion %, and it run OK (next iteration ≈ edge rate, as expected) lua> tvm_begin(40, 1e7, 900, -400, -1000, true) Code: 1e+07 4999999600 500 robve Wrote:About the npmt curvature: adjusting npmt for positive f'' is just a sign change of npmt. But root finders don't need to care as we know, because they flip to the other side of the curve anyway (as shown above). Theoretically then they never need to flip back again unless f'' changes sign. For TVM f'' won't change sign I believe, but numerically there is a nonzero possibility that the sign of npmt may flip close to root due to inaccuracies, especially with lower precision solvers. That worries me. Problem is in Secant's method. We are estimating slope with points, which may not be both on the outside. Depends on where they are, we don't know how many iterations until *both points* moved outside. Hybrid work better perhaps is due to this. It moved next point to the outside, on the first try. Switch back to Secant with both points outside, give us nice one-sided convergence. (04-09-2022 05:47 PM)Albert Chan Wrote: \(\displaystyle I ≈ \frac{1}{P} - \frac{P}{N^2}\) find_rate() thus skip over user-supplied guess, and consider next one as initial guess. Below example, the better guess is on the inside ... Newton pushed it out. lua> n,pv,pmt,fv = 365*24*60*60,0,-0.01,331667.0067 -- problem 3 lua> i = pmt/fv lua> i -- edge rate -3.015072285753529e-08 lua> find_rate(n, i-1/i/n^2, pv, pmt, fv, true) -- perhaps better guess Code: 3.1987564370323693e-09 -4.4522291350098525e-06 -160259.18297182902 |
|||
06-20-2024, 04:30 PM
(This post was last modified: 06-23-2024 01:15 PM by robve.)
Post: #75
|
|||
|
|||
RE: Looking for TVM contributions
(06-19-2024 09:08 PM)Albert Chan Wrote: Technically this setup should never encounter overshoot (f sign flip) Well, try this example with Newton. The curve is parabolic with f''>0. We stop at sign change and take the last i%: ./tvm 10 '?' 50 -12.8277219567 80 1/0 i%= 3.08778325056 y= 0.0103695628259 2/0 i%= 3.59460137697 y= 0.00259881409493 3/0 i%= 3.8488202702 y= 0.00064807442555 4/0 i%= 3.97517959151 y= 0.000159382918897 5/0 i%= 4.03630943599 y= 3.72170552208e-05 6/0 i%= 4.06308588579 y= 7.13292596899e-06 7/0 i%= 4.07140713916 y= 6.88560398032e-07 8/0 i%= 4.07240259392 y= 9.85261117137e-09 9/0 i%= 4.07241725752 y= 2.14050999148e-12 10/0 i%= 4.07241726071 y= -3.5527136788e-15 10, i%=4.07241726070281285%, FVerr=2e-10 This is not a winning strategy IMHO. Newton stopping at non-monotonicity is better with previous i% when the last step wasn't monotonically decreasing: ./tvm 10 '?' 50 -12.8277219567 80 1/0 i%= 3.08778325056 y= 0.0103695628259 2/0 i%= 3.59460137697 y= 0.00259881409493 3/0 i%= 3.8488202702 y= 0.00064807442555 4/0 i%= 3.97517959151 y= 0.000159382918897 5/0 i%= 4.03630943599 y= 3.72170552208e-05 6/0 i%= 4.06308588579 y= 7.13292596899e-06 7/0 i%= 4.07140713916 y= 6.88560398032e-07 8/0 i%= 4.07240259392 y= 9.85261117137e-09 9/0 i%= 4.07241725752 y= 2.14050999148e-12 10/0 i%= 4.07241726071 y= -3.5527136788e-15 11/0 i%= 4.0724172607 y= 1.7763568394e-15 12, i%=4.07241726070545784%, FVerr=2.8e-14 With the Hybrid method we have no sign change and we hit the root even closer: ./tvm 10 '?' 50 -12.8277219567 80 3/0 i%= 3.7640993412 y= 0.00115435116452 4/0 i%= 3.89955465008 y= 0.000413574938126 5/0 i%= 3.97517927056 y= 0.000159383755689 6/0 i%= 4.02259765825 y= 5.81463133074e-05 7/0 i%= 4.04983268476 y= 2.02404140044e-05 8/0 i%= 4.06437522885 y= 6.04424116091e-06 9/0 i%= 4.07056694296 y= 1.27674678296e-06 10/0 i%= 4.0722250993 y= 1.29426121376e-07 11/0 i%= 4.07241215141 y= 3.43175443618e-09 12/0 i%= 4.07241724621 y= 9.73088276623e-12 13/0 i%= 4.0724172607 y= 1.7763568394e-15 14/0 i%= 4.0724172607 y= 1.7763568394e-15 14, i%=4.07241726070100896%, FVerr=1.4e-14 Note how many trailing digits of i% are actually irrelevant. This is an example why comparing decimal places of i% is just wrong in general, the point I made earlier. The reason for this is the flat curvature, hence more iterations are needed than usual to get to the root for this example. It depends on the TVM problem how many places are relevant. The relationship is nonlinear. When we increase PMT a little bit then there is one root numerically (two roots very very close numerically indistinguishable) on the x-axis: ./tvm 10 '?' 50 -12.8277106125 80 For this specific case we can stop at a sign change without losing precision. IMPORTANT: all such examples are anecdotal. Anecdotal examples are fine as counter examples to prove claims are incorrect (counter to a proof), but shall never be solely used to offer a general proof. - Rob "I count on old friends to remain rational" |
|||
06-20-2024, 05:07 PM
(This post was last modified: 06-21-2024 02:36 AM by robve.)
Post: #76
|
|||
|
|||
RE: Looking for TVM contributions
(06-20-2024 03:07 PM)Albert Chan Wrote:(06-20-2024 04:03 AM)robve Wrote: ... I'm literally using the same parameters to find the root at npmt()=0 and to compute the errors: double npmt() { j = 0.01*i; k = 1.0 + j*b; l = log1p(j); r = expm1(-n*l); s = r + 1.0; return k*pmt - (pv + fv*s)*j/r; } After root finding with npmt()=0 all global parameters are set accordingly. I only need to make sure to use the previous j, r, s when I use the previous i% rate that is more precise when the last step overshot. Then fabs(fv - (k*pmt*r/j-pv)/s) is the FV error. It's just the TVM FV formula. The npmt() is zero or close of course, because we solve using npmt. Also nfv(0 and npv probably are also zero or close. But the TVM reverse computation of PV, PMT and FV should not have large errors like that. I really want to maintain TVM model equilibrium, i.e. inputs and outputs are reversible, at least with minimal drift, in the presence of roundoff. - Rob "I count on old friends to remain rational" |
|||
06-20-2024, 06:27 PM
(This post was last modified: 06-20-2024 06:49 PM by robve.)
Post: #77
|
|||
|
|||
RE: Looking for TVM contributions
(06-19-2024 03:47 PM)robve Wrote: I'm not completely happy about the iguess() (it's your guess_i() code by the way), which works fine in END mode, but is not as good in BEGIN mode. It also can return an overflow >100% causing NaN. I can replicate your symbolic derivation and understand it, but inserting a BEGIN mode adjustment that requires i% itself that we want to guess is something to figure out. After some more experimentation with TVM problems for which the initial guess isn't that good, such as n=10 pv=-100 pmt=10 fv=<small> for <small>=1e-1 to 1e-99 n=40 pv=900 pmt=-400 fv=-1000 BGN n=480 pv=100000 pmt=-208.333333333333343 fv=0 and others, the following updated version is a nice improvement: Code: double iguess() It is based on Albert's guess_i(). It may not start at a point to approach the root from a side that does not flip the npmt sign (it doesn't affect these root finders). It does appear to offer a fairly accurate starting point. In the Hybrid method the next point we pick after the guess is often quadratically closer to the root using the Newton derivative. That's all we need for some TVM problems as it hits the root exactly with only 1 to 3 npmt evaluations. Results for Hybrid with the new guess compared to the previous implementation looks good, saving 5 iteration steps total over all tests: 98 instead of 103, not counting the NaN case that is now fixed. Final accuracy is the same. tvmperfcomp-hybrid-newguess.pdf (Size: 33.22 KB / Downloads: 2) - Rob EDIT: minor edit to correct typo and I=1e-8 that works for Newton when I=1e-9 fails with NaN in Newton. "I count on old friends to remain rational" |
|||
06-20-2024, 07:37 PM
Post: #78
|
|||
|
|||
RE: Looking for TVM contributions
(06-20-2024 04:30 PM)robve Wrote: Well, try this example with Newton. The curve is parabolic with f''>0. We stop at sign change and take the last i%: Solve with mpmath, mp.dps = 34, rounded back to float rate1(%) = 4.14000005643961 -- ignored for error analysis rate2(%) = 4.0724172607043148 Newton error = 1.502e-12 % Secant error = -1.143e-12 % Hybrid error = 3.306e-12 % |
|||
06-21-2024, 09:04 PM
Post: #79
|
|||
|
|||
RE: Looking for TVM contributions
I've expanded the comparisons by including another Newton method. The following results compare Newton and Hybrid to another Newton solver that was mentioned on the HP Forums before. To ensure fairness, I used the exact same initial i% guess that performs very well thanks to Albert and I've used the same termination condition for all four methods compared. To emulate BEGIN mode I added PV+=PMT and FV-=PMT to solve rate i% with this other Newton solver (PV and FV updates are undone to compute FVerror.)
tvmperfcomp-voidware-newton-hybrid.pdf (Size: 36.22 KB / Downloads: 4) This other Newton solver performs objectively worse than the Newton and Hybrid methods used and discussed in this thread. There is one minor benefit of this method. When we disregard the problematic case that requires as many as 53 evaluations to converge (!), this Newton method requires slightly fewer evaluations on average. However, the results are less accurate and some are wrong. Perhaps interesting to note is that additional iterations (with g=1 to continue with one retry) may improve the results in some cases, but mostly harms the result. Interestingly, this is the opposite of the Newton method used and discussed in this thread. I suppose this aligns with the claims that Newton should not need continuation theoretically after the termination condition was met, but depending on the choice of f and f' expressions may benefit from additional iterations. - Rob "I count on old friends to remain rational" |
|||
06-22-2024, 08:00 PM
(This post was last modified: 06-23-2024 08:18 PM by robve.)
Post: #80
|
|||
|
|||
RE: Looking for TVM contributions
The Newton versus Hybrid method performance on a SHARP PC-1403H with 10 digits BCD. It took some effort to implement, double check and run the numbers by hand.
tvmperfcomp-pc1403h-newton-hybrid.pdf (Size: 33.56 KB / Downloads: 5) I've used g=1 for both methods to continue one more phase of iterations after one time "overshooting" (an overshoot means that the last step was too large, i.e. it is an "overstep" that is likely moving away from the root). Otherwise, FVerror will be larger for some cases and setting g=1 does improve these cases. However, I should mention that overshooting does not happen a lot. It happens in a couple of cases such as the 6th and 21st test case. But not 22nd, even though it is similar to 21st and also has a nonzero FVerror. After the first overshoot, we iterate again. Then, if an overshoot happens again, we take the previous i% and stop, because this point is closer to the root. - Hybrid evals are cheaper, i.e. no derivative to compute - Newton required 93 evals versus 103 for Hybrid - The 3rd case FVerror=100 looks really bad, but it means that we computed FV=-900 instead of FV=-1000 which was discussed in this thread before why this happens. It is very hard (impossible?) to improve this result with only 10 digits BCD precision as the least significant digit in i% causes FV to sway. - Sometimes Newton is more accurate and sometimes Hybrid is more accurate as indicated with comparatively larger FVerror shown in red. However, Newton method errors appear worse, such as in the 6th, 21st and 22nd and last TVM test cases. Hybrid method errors are not as large. My takeaway from these experiments with 10 digits BCD, IEEE 754 double and long double precision is that I personally prefer the Hybrid method, because Newton behaves erratic when rates approach zero and does not appear to maintain TVM equilibrium as well as Hybrid does (i.e. lower FV, PV and PMT errors in reversed computations). This is all experimental using unbiased test cases collected on this forum. If something changes significantly in the future when implementing and testing these methods, then I will be happy to change my mind. The TVM test cases are (I've removed the last three that were duplicates left after merging test sets): n pv pmt fv (BGN mode = 1) 40 900 -40 -1000 1 40 900 1000 -1000 1 40 900 -400 -1000 1 31536000 0 -0.01 331667.0067 525600 0 -0.01 5282.36776893622391 525600 0 -0.01 5260.38242600032663 32 -999999 0 1000000 360 0 -1000 1000000 328 35000 -324 0 58 -775 -49.56 4000 32 -6000 0 10000 48 19198.60 -450 0 5 -369494.09 17500 540000 348 243400 -1363.29 0 30 -3200 -717.44 60000 60 243400 -1363.29 -222975.98 24 0 -50.26 1281.34 6 -32000 0 28346.96 60 8000 -150.97 0 456 270000 -1215.3333333333 0 480 100000 -208.333333333333343 0 10 50 -30 400 10 50 -30 80 10 -100 10 1e-10 The PC-1403H program: Code: ' Switch begin mode on/off: DEF-B To count evals and compute the FVerror, add Z=Z+1,Q=R at the start of line 38 then set Z=0 at line 25. Change line 36 to 36 IF Y<>0 LET I=V,J=.01*I,R=Q,S=R+1 to pick the previous rate and restore the previous TVM parameters. Compute FVerror with ABS(F-(K*M*R/J-P)/S) - Rob EDIT: minor update to the PDF so all significant i% digits are now visible EDIT 2: minor update to the PDF with a minor update to the program to test P+F=-N*M to return zero rate, which does not apply to the last test case "I count on old friends to remain rational" |
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 3 Guest(s)