Mercurial > hg > octave-nkf
comparison libinterp/corefcn/ellipj.cc @ 17502:578805a293e5
ellipj: Move numerical code into liboctave
* lo-specfun.cc, lo-specfun.h (ellipj): New functions, adapted from
Fellipj.
* ellipj.cc (Fellipj): Call ellipj. (do_ellipj): Delete.
author | Mike Miller <mtmiller@ieee.org> |
---|---|
date | Thu, 26 Sep 2013 21:34:26 -0400 |
parents | 991c7c812e38 |
children | 5b916efea542 |
comparison
equal
deleted
inserted
replaced
17501:55680de6a897 | 17502:578805a293e5 |
---|---|
24 #include <config.h> | 24 #include <config.h> |
25 #endif | 25 #endif |
26 | 26 |
27 #include "defun.h" | 27 #include "defun.h" |
28 #include "error.h" | 28 #include "error.h" |
29 #include "lo-ieee.h" | 29 #include "lo-specfun.h" |
30 | 30 |
31 static void | 31 static void |
32 gripe_ellipj_arg (const char *arg) | 32 gripe_ellipj_arg (const char *arg) |
33 { | 33 { |
34 error ("ellipj: expecting scalar or matrix as %s argument", arg); | 34 error ("ellipj: expecting scalar or matrix as %s argument", arg); |
35 } | |
36 | |
37 static void | |
38 do_ellipj (const double u, const double m, double& sn, double& cn, double& dn, double& err) | |
39 { | |
40 static const int Nmax = 16; | |
41 double m1, t=0, si_u, co_u, se_u, ta_u, b, c[Nmax], a[Nmax], phi; | |
42 int n, Nn, ii; | |
43 | |
44 if (m < 0 || m > 1) | |
45 { | |
46 warning ("ellipj: expecting 0 <= M <= 1"); // -lc- | |
47 sn = cn = dn = lo_ieee_nan_value (); | |
48 return; | |
49 } | |
50 | |
51 double sqrt_eps = sqrt (std::numeric_limits<double>::epsilon ()); | |
52 if (m < sqrt_eps) | |
53 { | |
54 // For small m, ( Abramowitz and Stegun, Section 16.13 ) | |
55 si_u = sin (u); | |
56 co_u = cos (u); | |
57 t = 0.25*m*(u - si_u*co_u); | |
58 sn = si_u - t * co_u; | |
59 cn = co_u + t * si_u; | |
60 dn = 1 - 0.5*m*si_u*si_u; | |
61 } | |
62 else if ((1 - m) < sqrt_eps) | |
63 { | |
64 // For m1 = (1-m) small ( Abramowitz and Stegun, Section 16.15 ) | |
65 m1 = 1 - m; | |
66 si_u = sinh (u); | |
67 co_u = cosh (u); | |
68 ta_u = tanh (u); | |
69 se_u = 1/co_u; | |
70 sn = ta_u + 0.25*m1*(si_u*co_u - u)*se_u*se_u; | |
71 cn = se_u - 0.25*m1*(si_u*co_u - u)*ta_u*se_u; | |
72 dn = se_u + 0.25*m1*(si_u*co_u + u)*ta_u*se_u; | |
73 } | |
74 else | |
75 { | |
76 /* | |
77 // Arithmetic-Geometric Mean (AGM) algorithm | |
78 // ( Abramowitz and Stegun, Section 16.4 ) | |
79 */ | |
80 | |
81 a[0] = 1; | |
82 b = sqrt (1 - m); | |
83 c[0] = sqrt (m); | |
84 for (n = 1; n < Nmax; ++n) | |
85 { | |
86 a[n] = (a[n - 1] + b)/2; | |
87 c[n] = (a[n - 1] - b)/2; | |
88 b = sqrt (a[n - 1]*b); | |
89 if (c[n]/a[n] < std::numeric_limits<double>::epsilon ()) break; | |
90 } | |
91 if (n >= Nmax - 1) | |
92 { | |
93 err = 1; | |
94 return; | |
95 } | |
96 Nn = n; | |
97 for (ii = 1; n > 0; ii = ii*2, --n) ; // ii = pow(2,Nn) | |
98 phi = ii*a[Nn]*u; | |
99 for (n = Nn; n > 0; --n) | |
100 { | |
101 t = phi; | |
102 phi = (asin ((c[n]/a[n])* sin (phi)) + phi)/2; | |
103 } | |
104 sn = sin (phi); | |
105 cn = cos (phi); | |
106 dn = cn/cos (t - phi); | |
107 } | |
108 } | |
109 | |
110 static void | |
111 do_ellipj (const Complex& u, const double m, Complex& sn, Complex& cn, Complex& dn, | |
112 double& err) | |
113 { | |
114 double m1 = 1 - m, ss1, cc1, dd1; | |
115 | |
116 do_ellipj (imag (u), m1, ss1, cc1, dd1, err); | |
117 if (real (u) == 0) | |
118 { | |
119 // u is pure imag: Jacoby imag. transf. | |
120 sn = Complex (0, ss1/cc1); | |
121 cn = 1/cc1; // cn.imag = 0; | |
122 dn = dd1/cc1; // dn.imag = 0; | |
123 } | |
124 else | |
125 { | |
126 // u is generic complex | |
127 double ss, cc, dd, ddd; | |
128 | |
129 do_ellipj (real (u), m, ss, cc, dd, err); | |
130 ddd = cc1*cc1 + m*ss*ss*ss1*ss1; | |
131 sn = Complex (ss*dd1/ddd, cc*dd*ss1*cc1/ddd); | |
132 cn = Complex (cc*cc1/ddd, -ss*dd*ss1*dd1/ddd); | |
133 dn = Complex (dd*cc1*dd1/ddd, -m*ss*cc*ss1/ddd); | |
134 } | |
135 } | 35 } |
136 | 36 |
137 DEFUN (ellipj, args, nargout, | 37 DEFUN (ellipj, args, nargout, |
138 "-*- texinfo -*-\n\ | 38 "-*- texinfo -*-\n\ |
139 @deftypefn {Built-in Function} {[@var{sn}, @var{cn}, @var{dn}, @var{err}] =} ellipj (@var{u}, @var{m})\n\ | 39 @deftypefn {Built-in Function} {[@var{sn}, @var{cn}, @var{dn}, @var{err}] =} ellipj (@var{u}, @var{m})\n\ |
210 } | 110 } |
211 | 111 |
212 double sn, cn, dn; | 112 double sn, cn, dn; |
213 double err = 0; | 113 double err = 0; |
214 | 114 |
215 do_ellipj (u, m, sn, cn, dn, err); | 115 ellipj (u, m, sn, cn, dn, err); |
216 | 116 |
217 if (nargout > 3) | 117 if (nargout > 3) |
218 retval(3) = err; | 118 retval(3) = err; |
219 retval(2) = dn; | 119 retval(2) = dn; |
220 retval(1) = cn; | 120 retval(1) = cn; |
231 } | 131 } |
232 | 132 |
233 Complex sn, cn, dn; | 133 Complex sn, cn, dn; |
234 double err = 0; | 134 double err = 0; |
235 | 135 |
236 do_ellipj (u, m, sn, cn, dn, err); | 136 ellipj (u, m, sn, cn, dn, err); |
237 | 137 |
238 if (nargout > 3) | 138 if (nargout > 3) |
239 retval(3) = err; | 139 retval(3) = err; |
240 retval(2) = dn; | 140 retval(2) = dn; |
241 retval(1) = cn; | 141 retval(1) = cn; |
263 Complex *pdn = dn.fortran_vec (); | 163 Complex *pdn = dn.fortran_vec (); |
264 double *perr = err.fortran_vec (); | 164 double *perr = err.fortran_vec (); |
265 octave_idx_type nel = u.numel (); | 165 octave_idx_type nel = u.numel (); |
266 | 166 |
267 for (octave_idx_type i = 0; i < nel; i++) | 167 for (octave_idx_type i = 0; i < nel; i++) |
268 do_ellipj (pu[i], m, psn[i], pcn[i], pdn[i], perr[i]); | 168 ellipj (pu[i], m, psn[i], pcn[i], pdn[i], perr[i]); |
269 | 169 |
270 if (nargout > 3) | 170 if (nargout > 3) |
271 retval(3) = err; | 171 retval(3) = err; |
272 retval(2) = dn; | 172 retval(2) = dn; |
273 retval(1) = cn; | 173 retval(1) = cn; |
307 double *pdn = dn.fortran_vec (); | 207 double *pdn = dn.fortran_vec (); |
308 double *perr = err.fortran_vec (); | 208 double *perr = err.fortran_vec (); |
309 octave_idx_type nel = m.numel (); | 209 octave_idx_type nel = m.numel (); |
310 | 210 |
311 for (octave_idx_type i = 0; i < nel; i++) | 211 for (octave_idx_type i = 0; i < nel; i++) |
312 do_ellipj (u, pm[i], psn[i], pcn[i], pdn[i], perr[i]); | 212 ellipj (u, pm[i], psn[i], pcn[i], pdn[i], perr[i]); |
313 | 213 |
314 if (nargout > 3) | 214 if (nargout > 3) |
315 retval(3) = err; | 215 retval(3) = err; |
316 retval(2) = dn; | 216 retval(2) = dn; |
317 retval(1) = cn; | 217 retval(1) = cn; |
336 Complex *pdn = dn.fortran_vec (); | 236 Complex *pdn = dn.fortran_vec (); |
337 double *perr = err.fortran_vec (); | 237 double *perr = err.fortran_vec (); |
338 octave_idx_type nel = m.numel (); | 238 octave_idx_type nel = m.numel (); |
339 | 239 |
340 for (octave_idx_type i = 0; i < nel; i++) | 240 for (octave_idx_type i = 0; i < nel; i++) |
341 do_ellipj (u, pm[i], psn[i], pcn[i], pdn[i], perr[i]); | 241 ellipj (u, pm[i], psn[i], pcn[i], pdn[i], perr[i]); |
342 | 242 |
343 if (nargout > 3) | 243 if (nargout > 3) |
344 retval(3) = err; | 244 retval(3) = err; |
345 retval(2) = dn; | 245 retval(2) = dn; |
346 retval(1) = cn; | 246 retval(1) = cn; |
374 const double *pu = u.data (); | 274 const double *pu = u.data (); |
375 const double *pm = m.data (); | 275 const double *pm = m.data (); |
376 | 276 |
377 for (octave_idx_type j = 0; j < mc; j++) | 277 for (octave_idx_type j = 0; j < mc; j++) |
378 for (octave_idx_type i = 0; i < ur; i++) | 278 for (octave_idx_type i = 0; i < ur; i++) |
379 do_ellipj (pu[i], pm[j], sn(i,j), cn(i,j), dn(i,j), err(i,j)); | 279 ellipj (pu[i], pm[j], sn(i,j), cn(i,j), dn(i,j), err(i,j)); |
380 | 280 |
381 if (nargout > 3) | 281 if (nargout > 3) |
382 retval(3) = err; | 282 retval(3) = err; |
383 retval(2) = dn; | 283 retval(2) = dn; |
384 retval(1) = cn; | 284 retval(1) = cn; |
396 double *pdn = dn.fortran_vec (); | 296 double *pdn = dn.fortran_vec (); |
397 double *perr = err.fortran_vec (); | 297 double *perr = err.fortran_vec (); |
398 octave_idx_type nel = m.numel (); | 298 octave_idx_type nel = m.numel (); |
399 | 299 |
400 for (octave_idx_type i = 0; i < nel; i++) | 300 for (octave_idx_type i = 0; i < nel; i++) |
401 do_ellipj (pu[i], pm[i], psn[i], pcn[i], pdn[i], perr[i]); | 301 ellipj (pu[i], pm[i], psn[i], pcn[i], pdn[i], perr[i]); |
402 | 302 |
403 if (nargout > 3) | 303 if (nargout > 3) |
404 retval(3) = err; | 304 retval(3) = err; |
405 retval(2) = dn; | 305 retval(2) = dn; |
406 retval(1) = cn; | 306 retval(1) = cn; |
434 const Complex *pu = u.data (); | 334 const Complex *pu = u.data (); |
435 const double *pm = m.data (); | 335 const double *pm = m.data (); |
436 | 336 |
437 for (octave_idx_type j = 0; j < mc; j++) | 337 for (octave_idx_type j = 0; j < mc; j++) |
438 for (octave_idx_type i = 0; i < ur; i++) | 338 for (octave_idx_type i = 0; i < ur; i++) |
439 do_ellipj (pu[i], pm[j], sn(i,j), cn(i,j), dn(i,j), err(i,j)); | 339 ellipj (pu[i], pm[j], sn(i,j), cn(i,j), dn(i,j), err(i,j)); |
440 | 340 |
441 if (nargout > 3) | 341 if (nargout > 3) |
442 retval(3) = err; | 342 retval(3) = err; |
443 retval(2) = dn; | 343 retval(2) = dn; |
444 retval(1) = cn; | 344 retval(1) = cn; |
456 Complex *pdn = dn.fortran_vec (); | 356 Complex *pdn = dn.fortran_vec (); |
457 double *perr = err.fortran_vec (); | 357 double *perr = err.fortran_vec (); |
458 octave_idx_type nel = m.numel (); | 358 octave_idx_type nel = m.numel (); |
459 | 359 |
460 for (octave_idx_type i = 0; i < nel; i++) | 360 for (octave_idx_type i = 0; i < nel; i++) |
461 do_ellipj (pu[i], pm[i], psn[i], pcn[i], pdn[i], perr[i]); | 361 ellipj (pu[i], pm[i], psn[i], pcn[i], pdn[i], perr[i]); |
462 | 362 |
463 if (nargout > 3) | 363 if (nargout > 3) |
464 retval(3) = err; | 364 retval(3) = err; |
465 retval(2) = dn; | 365 retval(2) = dn; |
466 retval(1) = cn; | 366 retval(1) = cn; |