2x sin(x)2 1 - ex 2x2 + 3x + cos(ex)
Furthermore, the user will enter an arbitrary domain [a,b] for x, and an
arbitrary number n of evaluation points in that domain. Finally,
your program will compute the average value of the function
evaluated at n evenly spaced points from a
to b. Here's an example problem your
program would solve:
Compute the average value of f(x) = 2x, evaluated at 8 points evenly spaced from 0 to 4.Arbitrary function? Arbitrary domain? Arbitrary number of evaluation points? This sounds like a lot of capability to have to program for, but we're going to take advantage of pipes to offload nearly ALL of the work to a child process.
Here's what a correct solution looks like when executed.
bash$ fna ← Program "fna" (function average) 2*x ← The function to be evaluated 0 4 8 ← Domain is [0 4], 8 evaluation points 4.000000 ← Answer x^2+5*x-10 ← Another function 1 8 8 ← Domain is [1 8], 8 evaluation points 38.000000 ← Answer s(x) ← Another function: sine(x) 0 3.14 30 ← Domain is [0 pi], 30 evaluation points 0.615136 ← Answer ^D ← ^D terminates your programfna assumes input is in the following form: f(x) lo hi npts, where
The UNIX utility we'll use to do most of the work is named bc: it will take care of parsing and evaluating arithmetic expressions. Here's how it would be used to calculate the value of the function y = x2 at x = 3 :
bash$ bc -l x=3 x^2 9Note how it works: you give a value for x and an expression in x to evaluate, and bc gives you the answer. Note also that we run bc using its -l option. This allows us to use these functions (see man bc):
s(x): sine
c(x): cosine
e(x): exponential, i.e. ex
l(x): natural log, i.e. ln(x)
For example:
bash$ bc -l x=3.14159/2 c(x) .99999999999911980765How can we use bc to do what we want? Suppose your program sends to bc (through a pipe) an expression in x and some values for x. It then lets bc do the stuff its designed to do, getting answers back though another pipe. In this way your program offloads the hard part of calculating the value of an expression to another program that already knows how to do such things!
1. What are the two reasons the system call "pipe" might fail? Hint: RTFMP! 2. Consider the following chunk of code: int p[2]; pipe(p); At any point after these two lines, why would the call write(p[0],"Hello!",6) be invalid? 3. Consider the following chunk of code: int p[2]; pipe(p); At any point after these two lines, why would the call fdopen(p[0],"w") be invalid? 3. Consider the following chunk of code: int p[2]; pipe(p); int i = fork(); A read from p[0] will result in EOF (the end of file character) only if all file descriptors referencing the write end of the pipe (i.e. p[1]) have been closed. After the above chunk of code, how many file descriptors reference the write end of the pipe? Explain your answer!
bash$ fna x^2 1 3 5 1.00000000000000000000 2.25000000000000000000 4.00000000000000000000 6.25000000000000000000 9.00000000000000000000Some or all of the following functions / system calls may be useful:
pipe, close, fdopen, setbuf, fflush, dup2, fork, execRemember that, if you use C I/O, you need to concern yourself with buffering modes (or at least remember to call
fflush to "flush the buffer". In
particular, FILE* objects referring to pipes will be
fully-buffered by default. Also, remember
to man fdopen ... you'll really want that one! It will allow
you to use fprintf and fscanf on pipes!
You may find this diagram & algorithm helpful.