home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
EFFO
/
pd8.lzh
/
SRC
/
srch.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-13
|
8KB
|
337 lines
/* this file contains functions to support iterative ephem searches.
* we support several kinds of searching and solving algorithms.
* values used in the evaluations come from the field logging flog.c system.
* the expressions being evaluated are compiled and executed from compiler.c.
*/
#include <stdio.h>
#include <math.h>
#include "screen.h"
extern char *strcpy();
static int (*srch_f)();
static int srch_tmscalled;
static char expbuf[NC]; /* [0] == '\0' when expression is invalid */
static double tmlimit = 1./60.; /* search accuracy, in hrs; def is one minute */
srch_setup()
{
int srch_minmax(), srch_solve0(), srch_binary();
static char *chcs[] = {
"Find extreme", "Find 0", "Binary", "New function", "Accuracy",
"Stop"
};
int fn;
/* let op select algorithm, edit, set accuracy
* or stop if currently searching
* algorithms require a function.
*/
fn = 0;
ask:
switch (popup(chcs, fn, srch_f ? 6 : 5)) {
case 0: if (expbuf[0] == '\0')
set_function();
srch_f = expbuf[0] ? srch_minmax : 0;
break;
case 1: if (expbuf[0] == '\0')
set_function();
srch_f = expbuf[0] ? srch_solve0 : 0;
break;
case 2: if (expbuf[0] == '\0')
set_function();
srch_f = expbuf[0] ? srch_binary : 0;
break;
case 3: srch_f = 0; set_function(); fn = 3; goto ask;
case 4: srch_f = 0; set_accuracy(); fn = 4; goto ask;
case 5: srch_f = 0; srch_prstate(0); return;
default: return;
}
/* new search */
srch_tmscalled = 0;
srch_prstate (0);
}
/* if searching is in effect call the search type function.
* it might modify *tmincp according to where it next wants to eval.
* (remember tminc is in hours, not days).
* if searching ends for any reason it is also turned off.
* also, flog the new value.
* return 0 if caller can continue or -1 if it is time to stop.
*/
srch_eval(mjd, tmincp)
double mjd;
double *tmincp;
{
char errbuf[128];
int s;
double v;
if (!srch_f)
return (0);
if (execute_expr (&v, errbuf) < 0) {
srch_f = 0;
f_msg (errbuf);
} else {
s = (*srch_f)(mjd, v, tmincp);
if (s < 0)
srch_f = 0;
(void) flog_log (R_SRCH, C_SRCH, v);
srch_tmscalled++;
}
srch_prstate (0);
return (s);
}
/* print state of searching. */
srch_prstate (force)
int force;
{
int srch_minmax(), srch_solve0(), srch_binary();
static (*last)();
if (force || srch_f != last) {
f_string (R_SRCH, C_SRCHV,
srch_f == srch_minmax ? "Extrema" :
srch_f == srch_solve0 ? " Find 0" :
srch_f == srch_binary ? " Binary" :
" off");
last = srch_f;
}
}
srch_ison()
{
return (srch_f != 0);
}
/* display current expression. then if type in at least one char make it the
* current expression IF it compiles ok.
* TODO: editing?
*/
static
set_function()
{
static char prompt[] = "Function: ";
char newexp[NC];
int s;
f_prompt (prompt);
fputs (expbuf, stdout);
c_pos (R_PROMPT, sizeof(prompt));
s = read_line (newexp, PW-sizeof(prompt));
if (s >= 0) {
char errbuf[NC];
if (s > 0 && compile_expr (newexp, errbuf) < 0)
f_msg (errbuf);
else
strcpy (expbuf, newexp);
}
}
static
set_accuracy()
{
static char p[] = "Desired accuracy ( hrs): ";
int hrs, mins, secs;
char buf[NC];
f_prompt (p);
f_time (R_PROMPT, C_PROMPT+18, tmlimit); /* place in blank spot */
c_pos (R_PROMPT, sizeof(p));
if (read_line (buf, PW-sizeof(p)) > 0) {
f_dec_sexsign (tmlimit, &hrs, &mins, &secs);
f_sscansex (buf, &hrs, &mins, &secs);
sex_dec (hrs, mins, secs, &tmlimit);
}
}
/* use successive paraboloidal fits to find when expression is at a
* local minimum or maximum.
*/
static
srch_minmax(mjd, v, tmincp)
double mjd;
double v;
double *tmincp;
{
static double base; /* for better stability */
static double x1, x2, x3; /* keep in increasing order */
static double y1, y2, y3;
double xm, a, b;
if (srch_tmscalled == 0) {
base = mjd;
x1 = 0.0;
y1 = v;
return (0);
}
mjd -= base;
if (srch_tmscalled == 1) {
/* put in one of first two slots */
if (mjd < x1) {
x2 = x1; y2 = y1;
x1 = mjd; y1 = v;
} else {
x2 = mjd; y2 = v;
}
return (0);
}
if (srch_tmscalled == 2 || fabs(mjd - x1) < fabs(mjd - x3)) {
/* closer to x1 so discard x3.
* or if it's our third value we know to "discard" x3.
*/
if (mjd > x2) {
x3 = mjd; y3 = v;
} else {
x3 = x2; y3 = y2;
if (mjd > x1) {
x2 = mjd; y2 = v;
} else {
x2 = x1; y2 = y1;
x1 = mjd; y1 = v;
}
}
if (srch_tmscalled == 2)
return (0);
} else {
/* closer to x3 so discard x1 */
if (mjd < x2) {
x1 = mjd; y1 = v;
} else {
x1 = x2; y1 = y2;
if (mjd < x3) {
x2 = mjd; y2 = v;
} else {
x2 = x3; y2 = y3;
x3 = mjd; y3 = v;
}
}
}
#ifdef TRACEMM
{ char buf[NC];
sprintf (buf, "x1=%g y1=%g x2=%g y2=%g x3=%g y3=%g",
x1, y1, x2, y2, x3, y3);
f_msg (buf);
}
#endif
a = y1*(x2-x3) - y2*(x1-x3) + y3*(x1-x2);
if (fabs(a) < 1e-10) {
/* near-0 zero denominator, ie, curve is pretty flat here,
* so assume we are done enough.
* signal this by forcing a 0 tminc.
*/
*tmincp = 0.0;
return (-1);
}
b = (x1*x1)*(y2-y3) - (x2*x2)*(y1-y3) + (x3*x3)*(y1-y2);
xm = -b/(2.0*a);
*tmincp = (xm - mjd)*24.0;
return (fabs (*tmincp) < tmlimit ? -1 : 0);
}
/* use secant method to solve for time when expression passes through 0.
*/
static
srch_solve0(mjd, v, tmincp)
double mjd;
double v;
double *tmincp;
{
static double x0, x1; /* x(n-1) and x(n) */
static double y0, y1; /* y(n-1) and y(n) */
double x2; /* x(n+1) */
double df; /* y(n) - y(n-1) */
switch (srch_tmscalled) {
case 0: x0 = mjd; y0 = v; return(0);
case 1: x1 = mjd; y1 = v; break;
default: x0 = x1; y0 = y1; x1 = mjd; y1 = v; break;
}
df = y1 - y0;
if (fabs(df) < 1e-10) {
/* near-0 zero denominator, ie, curve is pretty flat here,
* so assume we are done enough.
* signal this by forcing a 0 tminc.
*/
*tmincp = 0.0;
return (-1);
}
x2 = x1 - y1*(x1-x0)/df;
*tmincp = (x2 - mjd)*24.0;
return (fabs (*tmincp) < tmlimit ? -1 : 0);
}
/* binary search for time when expression changes from its initial state.
* if the change is outside the initial tminc range, then keep searching in that
* direction by tminc first before starting to divide down.
*/
static
srch_binary(mjd, v, tmincp)
double mjd;
double v;
double *tmincp;
{
static double lb, ub; /* lower and upper bound */
static int initial_state;
int this_state = v >= 0.5;
#define FLUNDEF -9e10
if (srch_tmscalled == 0) {
if (*tmincp >= 0.0) {
/* going forwards in time so first mjd is lb and no ub yet */
lb = mjd;
ub = FLUNDEF;
} else {
/* going backwards in time so first mjd is ub and no lb yet */
ub = mjd;
lb = FLUNDEF;
}
initial_state = this_state;
return (0);
}
if (ub != FLUNDEF && lb != FLUNDEF) {
if (this_state == initial_state)
lb = mjd;
else
ub = mjd;
*tmincp = ((lb + ub)/2.0 - mjd)*24.0;
#ifdef TRACEBIN
{ char buf[NC];
sprintf (buf, "lb=%g ub=%g tminc=%g mjd=%g is=%d ts=%d",
lb, ub, *tmincp, mjd, initial_state, this_state);
f_msg (buf);
}
#endif
/* signal to stop if asking for time change less than TMLIMIT */
return (fabs (*tmincp) < tmlimit ? -1 : 0);
} else if (this_state != initial_state) {
/* gone past; turn around half way */
if (*tmincp >= 0.0)
ub = mjd;
else
lb = mjd;
*tmincp /= -2.0;
return (0);
} else {
/* just keep going, looking for first state change but we keep
* learning the lower (or upper, if going backwards) bound.
*/
if (*tmincp >= 0.0)
lb = mjd;
else
ub = mjd;
return (0);
}
}