[comp.lang.c] evaluating math w/o recompile

zador-anthony@CS.YALE.EDU (anthony zador) (09/15/89)

 
I have functions of the form

double f(V,t) 
  double V,t;
{
  return (some math function involving about a 
       line of exp, division, mult and add
       on V, t)
}

I use these functions to construct a table:

Table(f, table_array)
   ptr_to_fun f;
   double_array table_array;
{
  construct table_array by evaluating f[n]
}
I would like to be able to specify the form of the function f
at *run time* (no recompiles). That is, i would like 
to place a line of math
in some file and have the program read it in and evaluate it.

For example, my fnct could be
    1.6/(1+exp(-0.072*(V-5.0)))
or 
   0.02*(V+8.69)/(exp((V+8.69)/5.36)-1)         



I have played around with "hoc", the high order calculator
described in the Unix Programming Environment by K&P, but that seems
like overkill for this task. Is there a simpler way?


I'd appreciate any ideas.

--Tony Zador
zador@yale-sun3-nebula.arpa 
zador@nebula.sun3.cs.yale.edu 

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/15/89)

In article <72603@yale-celray.yale.UUCP> zador-anthony@CS.YALE.EDU (anthony zador) writes:
>I would like to be able to specify the form of the function f
>at *run time* (no recompiles). That is, i would like 
>to place a line of math
>in some file and have the program read it in and evaluate it.
>I have played around with "hoc", the high order calculator
>described in the Unix Programming Environment by K&P, but that seems
>like overkill for this task. Is there a simpler way?

Because C expressions have to be compiled (in most C environments, anyway),
there's no way to input C language pieces at run time.  You could however
construct a source file, invoke the compiler on it, and execute it to
get the results (into a file or via IPC), assuming a decent operating
system environment.  The portable way to do this is to build a language
translator/interpretor into your application, much along the lines of
the code used in "hoc".

henry@utzoo.uucp (Henry Spencer) (09/15/89)

In article <72603@yale-celray.yale.UUCP> zador-anthony@CS.YALE.EDU (anthony zador) writes:
>I would like to be able to specify the form of the function f
>at *run time* (no recompiles). That is, i would like 
>to place a line of math
>in some file and have the program read it in and evaluate it.

You can't.  There is no way that line of math can be *executed* without
compiling it (in a very broad sense of the word), so trying to do it with
no recompiles is futile.  Either you invoke the C compiler, or you write
a mini-compiler as part of your program.  *Something* has to turn the math
notation into an executable/interpretable representation of some kind.
-- 
V7 /bin/mail source: 554 lines.|     Henry Spencer at U of Toronto Zoology
1989 X.400 specs: 2200+ pages. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

mcdonald@uxe.cso.uiuc.edu (09/16/89)

In article <72603@yale-celray.yale.UUCP> zador-anthony@CS.YALE.EDU (anthony zador) writes:
>I would like to be able to specify the form of the function f
>at *run time* (no recompiles). That is, i would like 
>to place a line of math
>in some file and have the program read it in and evaluate it.

Henry Spencer replies:

>You can't.  There is no way that line of math can be *executed* without
>compiling it (in a very broad sense of the word), so trying to do it with
>no recompiles is futile.  Either you invoke the C compiler, or you write
>a mini-compiler as part of your program.  *Something* has to turn the math
>notation into an executable/interpretable representation of some kind.

Or, if you need to do it once or only a couple of times, write
an interpreter. An interpreter can be written in portable C. 
A compiler, of course, can't. You have to know the machine code.
But the situation concerning mini-compilers is even worse than
non-portability. It is certainly guaranteed possible to write
to an array the bits which constitute the necessary code. BUT -- BUT--
due apparently to X3J11 bowing to the concerns of manufacturers
of brain-dead computers and operating systems, there is absolutely
no guarantee that you can EXECUTE that code. 

Actually the situation is not too bad on most computers - for
example, on MS-DOS or VMS there is no problem at all. There you
can just cast a pointer to the data array to a code pointer and
go to town. On OS/2 you can't do that - but there is a trivial
OS call that will do it for you. There appear to be, however,
Unixes that really make it impossible. 

I am very sensitive to this sort of thing, as my spiffiest programs
all depend on in-situ compilation of expressions (though, thank God,
not control constructs).

Doug McDonald
 

mccaugh@s.cs.uiuc.edu (09/17/89)

In article <72603@yale-celray.yale.UUCP> zador-anthony@CS.YALE.EDU 
(Anthony Zador) writes:
> I would like to be able to specify the form of the function f
> at *run time* (no recompiles). That is, i would like 
> to place a line of math
> in some file and have the program read it in and evaluate it.
> .....

As rightly noted by the preceding respondents, the function definition would
have to be parsed into some internal form suitable for digestion by an inter-
preter. But with a utility as nice as BC (the arbitrary-precision desk calcu-
lator), it may not be necessary to "re-invent the wheel" writing your own.
Suppose file 'f1' contained your function definitions, say:

define u(x) { /* signum function */
       if(x<0) return(-1)
       if(x>0) return(1)
       return(0)
}

define t(x) { /* tangent function */
       auto z
       if(x==90) return(572957.8)
       if(x==270) return(572957.8)
       /* else convert degrees to radians */
       z = 0.0174532*x  /* and return tan(x) */
       return(s(z)/c(z))
}

and your calls to these functions were included in another file, 'f2':

/* some sample values */
f(-13.57)  /* s/b: -1 */
t(45)      /* s/b: +1 */
quit


Then your C program could issue the system call:

          system("cat f1 f2 | bc -l > f3");

and you have your results in file 'f3':

-1
.99999167323977094494


This is certainly not an elegant solution, but it does appear feasible 
and takes advantage of BC's arbitrary-precision capability to boot 
(and hence is slooow). But it would appear to spare one the need to tool 
their own interpreter along the lines of 'hoc' (I recall the source 
for 'hoc' runs to 13 pages in Kernighan & Pike).

Scott McCaughrin
Dept. of Computer Science
University of Illinois

gwyn@smoke.BRL.MIL (Doug Gwyn) (09/17/89)

In article <225800223@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes:
-due apparently to X3J11 bowing to the concerns of manufacturers
-of brain-dead computers and operating systems, there is absolutely
-no guarantee that you can EXECUTE that code. 

I consider that an implementation that lets you set the PC to
data space is brain dead.

-Actually the situation is not too bad on most computers - for
-example, on MS-DOS or VMS there is no problem at all. There you
-can just cast a pointer to the data array to a code pointer and
-go to town.

My opinion of VMS just dropped another notch.  The VAX architecture
permits enforcement of code/data separation, and one would think it
would be used for tasks resulting from compilation of C source code.

Certainly there are uses for the facility of executing instructions
out of data space.  The bit-blit code for some of the Blit family
of terminals works like that, for example.  But for most applications,
the added safety check is much more useful than the ability to execute
out of data space.  And as we've pointed out before, some environments
require the separation.

henry@utzoo.uucp (Henry Spencer) (09/17/89)

In article <225800223@uxe.cso.uiuc.edu> mcdonald@uxe.cso.uiuc.edu writes:
>>You can't.  There is no way that line of math can be *executed* without
>>compiling it (in a very broad sense of the word), so trying to do it with
>>no recompiles is futile.  Either you invoke the C compiler, or you write
>>a mini-compiler as part of your program...
>
>Or, if you need to do it once or only a couple of times, write
>an interpreter. An interpreter can be written in portable C. 
>A compiler, of course, can't. You have to know the machine code.

You are assuming a very narrow definition of "compiler".  Note the phrase
"in a very broad sense of the word".  Not all translators referred to
as "compilers" generate machine code.
-- 
"Where is D.D. Harriman now,   |     Henry Spencer at U of Toronto Zoology
when we really *need* him?"    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

jeenglis@nunki.usc.edu (Joe English) (09/17/89)

zador-anthony@CS.YALE.EDU (anthony zador) writes:
>I would like to be able to specify the form of the function f
>at *run time* (no recompiles). That is, i would like 
>to place a line of math
>in some file and have the program read it in and evaluate it.

How about writing a set of math interface 
functions that take, instead of a fixed set of parameters,
an argv/argc pair?  I'm doing something like that right
now in a report generator I'm writing:

enum valuetype {  vInt, vFloat, vString ... };

typedef struct {
   enum valuetype tag;
   union {
      int ival;
      double fval;
      char *sval;
      ...
   } datum;
} value;


Then for the interface function:

value somefunc(int argc,value *argv)

{
    /* use argc parameters from the argv array.  Type-checking
       of arguments is done by the parser & function
       lookup table.
    */
}

If you don't need full generality, you can use
'double *argv'.


--Joe English

  jeenglis@nunki.usc.edu