GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
filter.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2017 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 // Based on Tony Richardson's filter.m.
24 //
25 // Originally translated to C++ by KH (Kurt.Hornik@wu-wien.ac.at)
26 // with help from Fritz Leisch and Andreas Weingessel on Oct 20, 1994.
27 //
28 // Rewritten to use templates to handle both real and complex cases by
29 // jwe, Wed Nov 1 19:15:29 1995.
30 
31 #if defined (HAVE_CONFIG_H)
32 # include "config.h"
33 #endif
34 
35 #include "quit.h"
36 
37 #include "defun.h"
38 #include "error.h"
39 #include "ovl.h"
40 
41 template <typename T>
44  int dim = 0)
45 {
46  MArray<T> y;
47 
48  octave_idx_type a_len = a.numel ();
49  octave_idx_type b_len = b.numel ();
50 
51  octave_idx_type ab_len = a_len > b_len ? a_len : b_len;
52 
53  // FIXME: The two lines below should be unecessary because
54  // this template is called with a and b as column vectors
55  // already. However the a.resize line is currently (2011/04/26)
56  // necessary to stop bug #33164.
57  b.resize (dim_vector (ab_len, 1), 0.0);
58  if (a_len > 1)
59  a.resize (dim_vector (ab_len, 1), 0.0);
60 
61  T norm = a (0);
62 
63  if (norm == static_cast<T> (0.0))
64  error ("filter: the first element of A must be nonzero");
65 
66  dim_vector x_dims = x.dims ();
67  if (dim < 0 || dim > x_dims.ndims ())
68  error ("filter: DIM must be a valid dimension");
69 
70  octave_idx_type x_len = x_dims(dim);
71 
72  dim_vector si_dims = si.dims ();
73  octave_idx_type si_len = si_dims(0);
74 
75  if (si_len != ab_len - 1)
76  error ("filter: first dimension of SI must be of length max (length (a), length (b)) - 1");
77 
78  if (si_dims.ndims () != x_dims.ndims ())
79  error ("filter: dimensionality of SI and X must agree");
80 
81  for (octave_idx_type i = 1; i < dim; i++)
82  {
83  if (si_dims(i) != x_dims(i-1))
84  error ("filter: dimensionality of SI and X must agree");
85  }
86  for (octave_idx_type i = dim+1; i < x_dims.ndims (); i++)
87  {
88  if (si_dims(i) != x_dims(i))
89  error ("filter: dimensionality of SI and X must agree");
90  }
91 
92  if (x_len == 0)
93  return x;
94 
95  if (norm != static_cast<T> (1.0))
96  {
97  a /= norm;
98  b /= norm;
99  }
100 
101  if (a_len <= 1 && si_len <= 0)
102  return b(0) * x;
103 
104  y.resize (x_dims, 0.0);
105 
106  octave_idx_type x_stride = 1;
107  for (int i = 0; i < dim; i++)
108  x_stride *= x_dims(i);
109 
110  octave_idx_type x_num = x_dims.numel () / x_len;
111  for (octave_idx_type num = 0; num < x_num; num++)
112  {
113  octave_idx_type x_offset;
114  if (x_stride == 1)
115  x_offset = num * x_len;
116  else
117  {
118  octave_idx_type x_offset2 = 0;
119  x_offset = num;
120  while (x_offset >= x_stride)
121  {
122  x_offset -= x_stride;
123  x_offset2++;
124  }
125  x_offset += x_offset2 * x_stride * x_len;
126  }
127  octave_idx_type si_offset = num * si_len;
128 
129  if (a_len > 1)
130  {
131  T *py = y.fortran_vec ();
132  T *psi = si.fortran_vec ();
133 
134  const T *pa = a.data ();
135  const T *pb = b.data ();
136  const T *px = x.data ();
137 
138  psi += si_offset;
139 
140  for (octave_idx_type i = 0, idx = x_offset;
141  i < x_len;
142  i++, idx += x_stride)
143  {
144  py[idx] = psi[0] + pb[0] * px[idx];
145 
146  if (si_len > 0)
147  {
148  for (octave_idx_type j = 0; j < si_len - 1; j++)
149  {
150  OCTAVE_QUIT;
151 
152  psi[j] = psi[j+1] - pa[j+1] * py[idx] + pb[j+1] * px[idx];
153  }
154 
155  psi[si_len-1] = pb[si_len] * px[idx] - pa[si_len] * py[idx];
156  }
157  else
158  {
159  OCTAVE_QUIT;
160 
161  psi[0] = pb[si_len] * px[idx] - pa[si_len] * py[idx];
162  }
163  }
164  }
165  else if (si_len > 0)
166  {
167  T *py = y.fortran_vec ();
168  T *psi = si.fortran_vec ();
169 
170  const T *pb = b.data ();
171  const T *px = x.data ();
172 
173  psi += si_offset;
174 
175  for (octave_idx_type i = 0, idx = x_offset;
176  i < x_len;
177  i++, idx += x_stride)
178  {
179  py[idx] = psi[0] + pb[0] * px[idx];
180 
181  if (si_len > 1)
182  {
183  for (octave_idx_type j = 0; j < si_len - 1; j++)
184  {
185  OCTAVE_QUIT;
186 
187  psi[j] = psi[j+1] + pb[j+1] * px[idx];
188  }
189 
190  psi[si_len-1] = pb[si_len] * px[idx];
191  }
192  else
193  {
194  OCTAVE_QUIT;
195 
196  psi[0] = pb[1] * px[idx];
197  }
198  }
199  }
200  }
201 
202  return y;
203 }
204 
205 template <typename T>
206 MArray<T>
207 filter (MArray<T>& b, MArray<T>& a, MArray<T>& x, int dim = -1)
208 {
209  dim_vector x_dims = x.dims ();
210 
211  if (dim < 0)
212  dim = x_dims.first_non_singleton ();
213  else if (dim > x_dims.ndims ())
214  error ("filter: DIM must be a valid dimension");
215 
216  octave_idx_type a_len = a.numel ();
217  octave_idx_type b_len = b.numel ();
218 
219  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
220  dim_vector si_dims = x.dims ();
221  for (int i = dim; i > 0; i--)
222  si_dims(i) = si_dims(i-1);
223  si_dims(0) = si_len;
224 
225  MArray<T> si (si_dims, T (0.0));
226 
227  return filter (b, a, x, si, dim);
228 }
229 
230 DEFUN (filter, args, ,
231  doc: /* -*- texinfo -*-
232 @deftypefn {} {@var{y} =} filter (@var{b}, @var{a}, @var{x})
233 @deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, @var{si})
234 @deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, [], @var{dim})
235 @deftypefnx {} {[@var{y}, @var{sf}] =} filter (@var{b}, @var{a}, @var{x}, @var{si}, @var{dim})
236 Apply a 1-D digital filter to the data @var{x}.
237 
238 @code{filter} returns the solution to the following linear, time-invariant
239 difference equation:
240 @tex
241 $$
242 \sum_{k=0}^N a_{k+1} y_{n-k} = \sum_{k=0}^M b_{k+1} x_{n-k}, \qquad
243  1 \le n \le P
244 $$
245 @end tex
246 @ifnottex
247 @c Set example in small font to prevent overfull line
248 
249 @smallexample
250 @group
251  N M
252 SUM a(k+1) y(n-k) = SUM b(k+1) x(n-k) for 1<=n<=length(x)
253 k=0 k=0
254 @end group
255 @end smallexample
256 
257 @end ifnottex
258 
259 @noindent
260 where
261 @ifnottex
262 N=length(a)-1 and M=length(b)-1.
263 @end ifnottex
264 @tex
265 $a \in \Re^{N-1}$, $b \in \Re^{M-1}$, and $x \in \Re^P$.
266 @end tex
267 The result is calculated over the first non-singleton dimension of @var{x}
268 or over @var{dim} if supplied.
269 
270 An equivalent form of the equation is:
271 @tex
272 $$
273 y_n = -\sum_{k=1}^N c_{k+1} y_{n-k} + \sum_{k=0}^M d_{k+1} x_{n-k}, \qquad
274  1 \le n \le P
275 $$
276 @end tex
277 @ifnottex
278 @c Set example in small font to prevent overfull line
279 
280 @smallexample
281 @group
282  N M
283 y(n) = - SUM c(k+1) y(n-k) + SUM d(k+1) x(n-k) for 1<=n<=length(x)
284  k=1 k=0
285 @end group
286 @end smallexample
287 
288 @end ifnottex
289 
290 @noindent
291 where
292 @ifnottex
293  c = a/a(1) and d = b/a(1).
294 @end ifnottex
295 @tex
296 $c = a/a_1$ and $d = b/a_1$.
297 @end tex
298 
299 If the fourth argument @var{si} is provided, it is taken as the
300 initial state of the system and the final state is returned as
301 @var{sf}. The state vector is a column vector whose length is
302 equal to the length of the longest coefficient vector minus one.
303 If @var{si} is not supplied, the initial state vector is set to all
304 zeros.
305 
306 In terms of the Z Transform, @var{y} is the result of passing the
307 discrete-time signal @var{x} through a system characterized by the following
308 rational system function:
309 @tex
310 $$
311 H(z) = {\displaystyle\sum_{k=0}^M d_{k+1} z^{-k}
312  \over 1 + \displaystyle\sum_{k+1}^N c_{k+1} z^{-k}}
313 $$
314 @end tex
315 @ifnottex
316 
317 @example
318 @group
319  M
320  SUM d(k+1) z^(-k)
321  k=0
322 H(z) = ---------------------
323  N
324  1 + SUM c(k+1) z^(-k)
325  k=1
326 @end group
327 @end example
328 
329 @end ifnottex
330 @seealso{filter2, fftfilt, freqz}
331 @end deftypefn */)
332 {
333  int nargin = args.length ();
334 
335  if (nargin < 3 || nargin > 5)
336  print_usage ();
337 
338  int dim;
339  dim_vector x_dims = args(2).dims ();
340 
341  if (nargin == 5)
342  {
343  dim = args(4).nint_value () - 1;
344  if (dim < 0 || dim >= x_dims.ndims ())
345  error ("filter: DIM must be a valid dimension");
346  }
347  else
348  dim = x_dims.first_non_singleton ();
349 
351 
352  const char *a_b_errmsg = "filter: A and B must be vectors";
353  const char *x_si_errmsg = "filter: X and SI must be arrays";
354 
355  bool isfloat = (args(0).is_single_type ()
356  || args(1).is_single_type ()
357  || args(2).is_single_type ()
358  || (nargin >= 4 && args(3).is_single_type ()));
359 
360  if (args(0).is_complex_type ()
361  || args(1).is_complex_type ()
362  || args(2).is_complex_type ()
363  || (nargin >= 4 && args(3).is_complex_type ()))
364  {
365  if (isfloat)
366  {
367  FloatComplexColumnVector b = args(0).xfloat_complex_vector_value (a_b_errmsg);
368  FloatComplexColumnVector a = args(1).xfloat_complex_vector_value (a_b_errmsg);
369  FloatComplexNDArray x = args(2).xfloat_complex_array_value (x_si_errmsg);
370 
372 
373  if (nargin == 3 || args(3).is_empty ())
374  {
375  octave_idx_type a_len = a.numel ();
376  octave_idx_type b_len = b.numel ();
377 
378  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
379 
380  dim_vector si_dims = x.dims ();
381  for (int i = dim; i > 0; i--)
382  si_dims(i) = si_dims(i-1);
383  si_dims(0) = si_len;
384 
385  si.resize (si_dims, 0.0);
386  }
387  else
388  {
389  si = args(3).xfloat_complex_array_value (x_si_errmsg);
390 
391  if (si.is_vector () && x.is_vector ())
392  si = si.reshape (dim_vector (si.numel (), 1));
393  }
394 
395  FloatComplexNDArray y (filter (b, a, x, si, dim));
396 
397  retval = ovl (y, si);
398  }
399  else
400  {
401  ComplexColumnVector b = args(0).xcomplex_vector_value (a_b_errmsg);
402  ComplexColumnVector a = args(1).xcomplex_vector_value (a_b_errmsg);
403 
404  ComplexNDArray x = args(2).xcomplex_array_value (x_si_errmsg);
405 
406  ComplexNDArray si;
407 
408  if (nargin == 3 || args(3).is_empty ())
409  {
410  octave_idx_type a_len = a.numel ();
411  octave_idx_type b_len = b.numel ();
412 
413  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
414 
415  dim_vector si_dims = x.dims ();
416  for (int i = dim; i > 0; i--)
417  si_dims(i) = si_dims(i-1);
418  si_dims(0) = si_len;
419 
420  si.resize (si_dims, 0.0);
421  }
422  else
423  {
424  si = args(3).xcomplex_array_value (x_si_errmsg);
425 
426  if (si.is_vector () && x.is_vector ())
427  si = si.reshape (dim_vector (si.numel (), 1));
428  }
429 
430  ComplexNDArray y (filter (b, a, x, si, dim));
431 
432  retval = ovl (y, si);
433  }
434  }
435  else
436  {
437  if (isfloat)
438  {
439  FloatColumnVector b = args(0).xfloat_vector_value (a_b_errmsg);
440  FloatColumnVector a = args(1).xfloat_vector_value (a_b_errmsg);
441 
442  FloatNDArray x = args(2).xfloat_array_value (x_si_errmsg);
443 
444  FloatNDArray si;
445 
446  if (nargin == 3 || args(3).is_empty ())
447  {
448  octave_idx_type a_len = a.numel ();
449  octave_idx_type b_len = b.numel ();
450 
451  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
452 
453  dim_vector si_dims = x.dims ();
454  for (int i = dim; i > 0; i--)
455  si_dims(i) = si_dims(i-1);
456  si_dims(0) = si_len;
457 
458  si.resize (si_dims, 0.0);
459  }
460  else
461  {
462  si = args(3).xfloat_array_value (x_si_errmsg);
463 
464  if (si.is_vector () && x.is_vector ())
465  si = si.reshape (dim_vector (si.numel (), 1));
466  }
467 
468  FloatNDArray y (filter (b, a, x, si, dim));
469 
470  retval = ovl (y, si);
471  }
472  else
473  {
474  ColumnVector b = args(0).xvector_value (a_b_errmsg);
475  ColumnVector a = args(1).xvector_value (a_b_errmsg);
476 
477  NDArray x = args(2).xarray_value (x_si_errmsg);
478 
479  NDArray si;
480 
481  if (nargin == 3 || args(3).is_empty ())
482  {
483  octave_idx_type a_len = a.numel ();
484  octave_idx_type b_len = b.numel ();
485 
486  octave_idx_type si_len = (a_len > b_len ? a_len : b_len) - 1;
487 
488  dim_vector si_dims = x.dims ();
489  for (int i = dim; i > 0; i--)
490  si_dims(i) = si_dims(i-1);
491  si_dims(0) = si_len;
492 
493  si.resize (si_dims, 0.0);
494  }
495  else
496  {
497  si = args(3).xarray_value (x_si_errmsg);
498 
499  if (si.is_vector () && x.is_vector ())
500  si = si.reshape (dim_vector (si.numel (), 1));
501  }
502 
503  NDArray y (filter (b, a, x, si, dim));
504 
505  retval = ovl (y, si);
506  }
507  }
508 
509  return retval;
510 }
511 
512 template MArray<double>
514  MArray<double>&, int dim);
515 
516 template MArray<double>
518 
519 template MArray<Complex>
521  MArray<Complex>&, int dim);
522 
523 template MArray<Complex>
525 
526 template MArray<float>
528  MArray<float>&, int dim);
529 
530 template MArray<float>
532 
533 template MArray<FloatComplex>
535  MArray<FloatComplex>&, int dim);
536 
537 template MArray<FloatComplex>
539  int dim);
540 
541 /*
542 %!shared a, b, x, r
543 %!test
544 %! a = [1 1];
545 %! b = [1 1];
546 %! x = zeros (1,10); x(1) = 1;
547 %! assert (filter (b, [1], x ), [1 1 0 0 0 0 0 0 0 0]);
548 %! assert (filter (b, [1], x.'), [1 1 0 0 0 0 0 0 0 0].');
549 %! assert (filter (b.', [1], x ), [1 1 0 0 0 0 0 0 0 0] );
550 %! assert (filter (b.', [1], x.'), [1 1 0 0 0 0 0 0 0 0].');
551 %! assert (filter ([1], a, x ), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1] );
552 %! assert (filter ([1], a, x.'), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1].');
553 %! assert (filter ([1], a.', x ), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1] );
554 %! assert (filter ([1], a.', x.'), [+1 -1 +1 -1 +1 -1 +1 -1 +1 -1].');
555 %! assert (filter (b, a, x ), [1 0 0 0 0 0 0 0 0 0] );
556 %! assert (filter (b.', a, x ), [1 0 0 0 0 0 0 0 0 0] );
557 %! assert (filter (b, a.', x ), [1 0 0 0 0 0 0 0 0 0] );
558 %! assert (filter (b.', a, x ), [1 0 0 0 0 0 0 0 0 0] );
559 %! assert (filter (b, a, x.'), [1 0 0 0 0 0 0 0 0 0].');
560 %! assert (filter (b.', a, x.'), [1 0 0 0 0 0 0 0 0 0].');
561 %! assert (filter (b, a.', x.'), [1 0 0 0 0 0 0 0 0 0].');
562 %! assert (filter (b.', a, x.'), [1 0 0 0 0 0 0 0 0 0].');
563 
564 %!test
565 %! r = sqrt (1/2) * (1+i);
566 %! a = a*r;
567 %! b = b*r;
568 %! assert (filter (b, [1], x ), r*[1 1 0 0 0 0 0 0 0 0] );
569 %! assert (filter (b, [1], r*x ), r*r*[1 1 0 0 0 0 0 0 0 0] );
570 %! assert (filter (b, [1], x.' ), r*[1 1 0 0 0 0 0 0 0 0].' );
571 %! assert (filter (b, a, x ), [1 0 0 0 0 0 0 0 0 0] );
572 %! assert (filter (b, a, r*x ), r*[1 0 0 0 0 0 0 0 0 0] );
573 
574 %!shared a, b, x, y, so
575 %!test
576 %! a = [1,1];
577 %! b = [1,1];
578 %! x = zeros (1,10); x(1) = 1;
579 %! [y, so] = filter (b, [1], x, [-1]);
580 %! assert (y, [0 1 0 0 0 0 0 0 0 0]);
581 %! assert (so, 0);
582 
583 %!test
584 %! x = zeros (10,3); x(1,1) = -1; x(1,2) = 1;
585 %! y0 = zeros (10,3); y0(1:2,1) = -1; y0(1:2,2) = 1;
586 %! y = filter (b, [1], x);
587 %! assert (y, y0);
588 
589 %!test
590 %! a = [1,1];
591 %! b=[1,1];
592 %! x = zeros (4,4,2); x(1,1:4,1) = +1; x(1,1:4,2) = -1;
593 %! y0 = zeros (4,4,2); y0(1:2,1:4,1) = +1; y0(1:2,1:4,2) = -1;
594 %! y = filter (b, [1], x);
595 %! assert (y, y0);
596 
597 %!assert (filter (1, ones (10,1) / 10, []), [])
598 %!assert (filter (1, ones (10,1) / 10, zeros (0,10)), zeros (0,10))
599 %!assert (filter (1, ones (10,1) / 10, single (1:5)), repmat (single (10), 1, 5))
600 
601 %% Test using initial conditions
602 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]), [2 2])
603 %!assert (filter ([1, 1, 1], [1, 1], [1 2], [1, 1]'), [2 2])
604 %!assert (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]), [5 7; 6 10; 14 18])
605 %!error (filter ([1, 3], [1], [1 2; 3 4; 5 6], [4, 5]'))
606 %!assert (filter ([1, 3, 2], [1], [1 2; 3 4; 5 6], [1 0 0; 1 0 0], 2), [2 6; 3 13; 5 21])
607 
608 ## Test of DIM parameter
609 %!test
610 %! x = ones (2, 1, 3, 4);
611 %! x(1,1,:,:) = [1 2 3 4; 5 6 7 8; 9 10 11 12];
612 %! y0 = [1 1 6 2 15 3 2 1 8 2 18 3 3 1 10 2 21 3 4 1 12 2 24 3];
613 %! y0 = reshape (y0, size (x));
614 %! y = filter ([1 1 1], 1, x, [], 3);
615 %! assert (y, y0);
616 */
double psi(double z)
Definition: lo-specfun.cc:3714
OCTAVE_EXPORT octave_value_list isa nd deftypefn *return ovl(args(0).is_integer_type())
OCTINTERP_API void print_usage(void)
Definition: defun.cc:52
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
#define DEFUN(name, args_name, nargout_name, doc)
Definition: defun.h:46
void error(const char *fmt,...)
Definition: error.cc:570
Template for N-dimensional array classes with like-type math operators.
Definition: MArray.h:32
int first_non_singleton(int def=0) const
Definition: dim-vector.h:463
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:389
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:398
JNIEnv void * args
Definition: ov-java.cc:67
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:439
OCTAVE_EXPORT octave_value_list isfloat
Definition: data.cc:3327
bool is_vector(void) const
Definition: Array.h:577
int nargin
Definition: graphics.cc:10115
const T * data(void) const
Definition: Array.h:582
double norm(const ColumnVector &v)
Definition: graphics.cc:5197
void resize(const dim_vector &dv, const T &rfv)
Definition: Array.cc:1028
octave_value retval
Definition: data.cc:6294
MArray< T > filter(MArray< T > &b, MArray< T > &a, MArray< T > &x, MArray< T > &si, int dim=0)
Definition: filter.cc:43
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:301
the element is set to zero In other the statement xample y
Definition: data.cc:5342
b
Definition: cellfun.cc:398
const T * fortran_vec(void) const
Definition: Array.h:584
MArray< T > reshape(const dim_vector &new_dims) const
Definition: MArray.h:91
#define OCTAVE_QUIT
Definition: quit.h:212
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x