double tangent_h(double x, double h, double& y, double yguess) { y = find_y_at_h(x, h,yguess); double dx = dfx(x,y); double dy = dfx(y,x); assert(dy != 0); return -dx/dy; }
double find_y_at_h(double x, double h, double yguess) { double y = yguess; assert(0.000001*(x*x+y*y)-0.0015*(x+y)+0.7 > 0); double fy = f(x, yguess); while(fabs(fy-h)>tol){ double slope = dfx(yguess, x); double deltay = (fy-h) /slope; if(fabs(deltay) > 50) deltay= deltay >0?50:-50; yguess -= deltay; fy = f(x, yguess); } return yguess; }
static VALUE method_newton(VALUE self, VALUE pmts, VALUE exps, VALUE guess, VALUE tolerance, VALUE max_iter) { long len = RARRAY_LEN(pmts); long max_i = NUM2INT(max_iter); long double x0 = NUM2DBL(guess); long double x1 = 0.0; long double tol = NUM2DBL(tolerance); long double err = 1e100; VALUE *pmt_p = RARRAY_PTR(pmts); VALUE *exp_p = RARRAY_PTR(exps); long iter = 0; while (err > tol && iter++ < max_i) { x1 = x0 - (fx(x0, pmt_p, exp_p, len) / dfx(x0, pmt_p, exp_p, len)); err = fabs(x1 - x0); x0 = MAX(x1, lower_bound); } return (err > tol) ? Qnil : rb_float_new(x0); }
//assumption only one maximum, giving two ends, find max void binary_search(double x1, double y1, double x2, double y2, double& retx, double& rety) { double dydx=(y2-y1)/(x2-x1); double df1 = dfx(x1,y1) + dydx * dfx(y1,x1); double df2 = dfx(x2, y2)+ dydx * dfx(y2, x2); assert(df1 * df2 < 0); double xmid = 0, ymid=0; while(fabs(x2-x1)> 1e-12){ xmid = (x1+x2)/2.0; ymid = (y1+y2)/2.0; double df3 = dfx(xmid, ymid)+dydx*dfx(ymid,xmid); if(df3 * df1 > 0){ x1 = xmid; y1 = ymid; }else{ x2 = xmid; y2 = ymid; } } retx = (x1+x2)/2; rety = (y1+y2)/2; }
int main() { /* { double xstart = 1400, ystart = 1400; double xfinal = 1561.907083805850789, yfinal = 672.892772938465328; int nseg = 1000; double retx, rety; double dx = (xfinal- xstart)/nseg; double dy = (yfinal- ystart)/nseg; for(int i = 0; i <= nseg; ++i){ //binary_search(1400, 1400, 1600, ystart+i*dy, retx, rety); printf("%d %30.15f\n", i, f(xstart+dx*i, ystart+i*dy)); } binary_search(xstart, ystart, xfinal, yfinal, retx, rety); printf("%30.15f\n", f(retx, rety)); exit(1); } */ double PI = 4.0*atan(1.0); double ret1, ret2; double radius = sqrt(17.0/40)*1000; //first find the fmin, minimum height binary_search(0,0, 1600, 0, ret1, ret2 ); double barrierx = ret1; double maxh = f(ret1, 0); printf("%30.15f, %30.15f %30.15f\n", ret1, f(ret1, 0), dfx(ret1, 0)); //second, find the path to the barrier //double y200 = 0; //double x200 = find_tangent(maxh, 300, barrierx, -100,y200 ); double x200, y200, x1400, y1400, tp; find_barrier_200(barrierx, maxh, x200, y200); printf("data 200| %30.15f %30.15f %30.15f\n", x200, y200, f(x200, y200)-maxh); printf("part2 %30.15f %30.15f %30.15f\n", f(x200, y200)-maxh, tangent_h(x200, maxh, tp, y200), (y200-200)/(x200-200) ); find_barrier_1400(700, maxh, x1400,y1400); // x1400 = find_barrier_eq_h(1410, 1600, maxh, ret1); // y1400 = find_y_at_h(x1400, maxh, 1600); printf("data 1400 %30.15f %30.15f %30.15f\n", x1400, y1400, f(x1400, y1400)-maxh); printf("part 2 %30.15f %30.15f %30.15f\n", f(x1400, y1400)-maxh, tangent_h(x1400, maxh,tp, y1400), (y1400-1400)/(x1400-1400) ); int nseg = 1000000; double y0 = y200; double total = sqrt((x200-200)*(x200-200)+(y200-200)*(y200-200)); total += sqrt((x1400-1400)*(x1400-1400)+(y1400-1400)*(y1400-1400)); //{ // double xstart = 1600, ystart = 900; // double xfinal = 1400, yfinal = 1400; // int nseg = 1000; // double dx = (xfinal- xstart)/nseg; // double dy = (yfinal- ystart)/nseg; // for(int i = 0; i <= nseg; ++i){ // printf("%d %30.15f\n", i, f(xstart+i*dx, ystart+i*dy)); // } // exit(1); //} //total += sqrt((x200-barrierx)*(x200-barrierx)+y200*y200); double dx = (1561.907083805850789 -x200)/nseg; for(unsigned int i=1; i<=nseg;++i){ double y1 = find_y_at_h(x200+i*dx, maxh, y0); //printf("%30.15f %30.15f %30.15f\n", x200+i*dx, y1, f(x200+i*dx, y1)); double ds = dx*dx+ (y1-y0)*(y1-y0); ds= sqrt(ds); total += ds; y0= y1; } //printf("------------------"); nseg = 1000000; double x4 = 1561.907083805850789; dx = (x4 - x1400)/nseg; y0 = find_y_at_h(x1400, maxh, y1400); for(unsigned int i=1; i<= nseg;++i){ double y1 = find_y_at_h(x1400+i*dx, maxh, y0); //printf("%30.15f %30.15f %30.15f\n", x4+i*dx, y1, f(x4+i*dx, y1)); double ds = dx*dx+ (y1-y0)*(y1-y0); ds= sqrt(ds); total += ds; y0= y1; } printf("%30.15f\n", total); }