-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathpowerseries.c
executable file
·133 lines (121 loc) · 3.76 KB
/
powerseries.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* powerseries.c */
/* S. Engblom 2007-08-17 (Minor revision) */
/* S. Engblom 2007-06-13 (Minor revision) */
/* S. Engblom 2007-01-22 */
#include <math.h>
#include "mex.h"
#include "matrix.h"
/* forward declaration */
void powerseries(double *yr,double *yi,
const double *cr,const double *ci,int Nc,
const double *xr,const double *xi,int Nx,
double tol);
#define ISDOUBLEMATRIX(A) (mxIsDouble(A) && !mxIsSparse(A) && \
mxGetNumberOfDimensions(A) == 2)
#define ISREALSCALAR(A) (!mxIsCell(A) && !mxIsStruct(A) && \
!mxIsComplex(A) && mxGetNumberOfElements(A) == 1)
/*------------------------------------------------------------------------*/
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
if (1 < nlhs || nrhs != 3)
mexErrMsgTxt("Expecting one output and 3 inputs.");
/* inputs C and X */
if (!ISDOUBLEMATRIX(prhs[0]) || !ISDOUBLEMATRIX(prhs[1]))
mexErrMsgTxt("First two arguments must be double matrices.");
/* input tol */
if (!ISREALSCALAR(prhs[2]))
mexErrMsgTxt("Expecting a real scalar tolerance.");
/* create output */
plhs[0] = mxCreateDoubleMatrix(mxGetM(prhs[1]),
mxGetN(prhs[1]),
mxIsComplex(prhs[0]) ||
mxIsComplex(prhs[1]) ? mxCOMPLEX : mxREAL);
/* evaluate the result */
powerseries(mxGetPr(plhs[0]),mxGetPi(plhs[0]),
mxGetPr(prhs[0]),mxGetPi(prhs[0]),
mxGetNumberOfElements(prhs[0]),
mxGetPr(prhs[1]),mxGetPi(prhs[1]),
mxGetNumberOfElements(prhs[1]),
*mxGetPr(prhs[2]));
}
/*------------------------------------------------------------------------*/
void powerseries(double *yr,double *yi,
const double *cr,const double *ci,int Nc,
const double *xr,const double *xi,int Nx,
double tol)
/* Summation of power series. Computes y = sum_(k >= 0) c[k]*x^k where
y = (yr,yi), c = (cr,ci) and x = (xr,xi) and where any of the
imaginary parts may be NULL. The coefficient vector has length Nc
and the coordinate vector length Nx. It is required that y be
allocated and cleared before the call.*/
{
bool warn = false;
if (yi == NULL)
for (int i = 0; i < Nx; i++) {
int j;
double powr = 1.0;
for (j = 0; j < Nc; j++) {
double termr = cr[j]*powr;
yr[i] += termr;
if (fabs(termr) < fabs(yr[i])*tol) break;
powr *= xr[i];
}
warn = warn || j == Nc;
}
else if (ci == NULL)
for (int i = 0; i < Nx; i++) {
int j;
double powr = 1.0,powi = 0.0;
for (j = 0; j < Nc; j++) {
double termr = cr[j]*powr;
double termi = cr[j]*powi;
yr[i] += termr;
yi[i] += termi;
if (fabs(termr)+fabs(termi) < (fabs(yr[i])+fabs(yi[i]))*tol)
break;
double powr_ = powr*xr[i]-powi*xi[i];
double powi_ = powr*xi[i]+powi*xr[i];
powr = powr_;
powi = powi_;
}
warn = warn || j == Nc;
}
else if (xi == NULL)
for (int i = 0; i < Nx; i++) {
int j;
double powr = 1.0;
for (j = 0; j < Nc; j++) {
double termr = cr[j]*powr;
double termi = ci[j]*powr;
yr[i] += termr;
yi[i] += termi;
if (fabs(termr)+fabs(termi) < (fabs(yr[i])+fabs(yi[i]))*tol)
break;
powr *= xr[i];
}
warn = warn || j == Nc;
}
else
for (int i = 0; i < Nx; i++) {
int j;
double powr = 1.0,powi = 0.0;
for (j = 0; j < Nc; j++) {
double termr = cr[j]*powr-ci[j]*powi;
double termi = cr[j]*powi+ci[j]*powr;
yr[i] += termr;
yi[i] += termi;
if (fabs(termr)+fabs(termi) < (fabs(yr[i])+fabs(yi[i]))*tol)
break;
double powr_ = powr*xr[i]-powi*xi[i];
double powi_ = powr*xi[i]+powi*xr[i];
powr = powr_;
powi = powi_;
}
warn = warn || j == Nc;
}
if (warn)
mexWarnMsgIdAndTxt("powerseries:w1",
"Series did not converge to the prescribed "
"accuracy for all arguments.");
}
/*------------------------------------------------------------------------*/