| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
use strict; |
|
2
|
|
|
|
|
|
|
use warnings; |
|
3
|
|
|
|
|
|
|
use Config; |
|
4
|
|
|
|
|
|
|
use PDL::Types qw(ppdefs ppdefs_complex types); |
|
5
|
|
|
|
|
|
|
require PDL::Core::Dev; |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
{ # pass info back to Makefile.PL |
|
8
|
|
|
|
|
|
|
# Files for each routine (.c assumed) |
|
9
|
|
|
|
|
|
|
my %source = qw( |
|
10
|
|
|
|
|
|
|
j0 j0 |
|
11
|
|
|
|
|
|
|
j1 j1 |
|
12
|
|
|
|
|
|
|
jn jn |
|
13
|
|
|
|
|
|
|
y0 j0 |
|
14
|
|
|
|
|
|
|
y1 j1 |
|
15
|
|
|
|
|
|
|
yn yn |
|
16
|
|
|
|
|
|
|
); |
|
17
|
|
|
|
|
|
|
my @keys = sort keys %source; |
|
18
|
|
|
|
|
|
|
my $libs = PDL::Core::Dev::get_maths_libs(); |
|
19
|
|
|
|
|
|
|
# Test for presence of besfuncs |
|
20
|
|
|
|
|
|
|
require File::Spec::Functions; |
|
21
|
|
|
|
|
|
|
my $include = qq{#include "}.File::Spec::Functions::rel2abs("$::PDLBASE/mconf.h").qq{"}; |
|
22
|
|
|
|
|
|
|
$source{$_} = 'system' for grep PDL::Core::Dev::trylink('', $include, "$_(1.);", $libs), qw(j0 j1 y0 y1); |
|
23
|
|
|
|
|
|
|
$source{$_} = 'system' for grep PDL::Core::Dev::trylink('', $include, "$_(1,1.);", $libs), qw(jn yn); |
|
24
|
|
|
|
|
|
|
my %seen; # Build object file list |
|
25
|
|
|
|
|
|
|
foreach my $func (@keys) { |
|
26
|
|
|
|
|
|
|
my $file = $source{$func}; |
|
27
|
|
|
|
|
|
|
next if $file eq 'system'; |
|
28
|
|
|
|
|
|
|
die "File for function $func not found\n" if $file eq ''; |
|
29
|
|
|
|
|
|
|
$PDL::Core::Dev::EXTRAS{$::PDLMOD}{OBJECT} .= " $::PDLBASE/$file\$(OBJ_EXT)" unless $seen{$file}++; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
# Add support routines |
|
32
|
|
|
|
|
|
|
$PDL::Core::Dev::EXTRAS{$::PDLMOD}{OBJECT} .= join '', map " $::PDLBASE/$_\$(OBJ_EXT)", qw(const mtherr polevl cpoly ndtri); |
|
33
|
|
|
|
|
|
|
$PDL::Core::Dev::EXTRAS{$::PDLMOD}{INC} .= qq{ "-I$::PDLBASE"}; |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
my $R = [ppdefs()]; |
|
37
|
|
|
|
|
|
|
my $F = [map $_->ppsym, grep $_->real && !$_->integer, types()]; |
|
38
|
|
|
|
|
|
|
my $C = [ppdefs_complex()]; |
|
39
|
|
|
|
|
|
|
my @Rtypes = grep $_->real, types(); |
|
40
|
|
|
|
|
|
|
my @Ctypes = grep !$_->real, types(); |
|
41
|
|
|
|
|
|
|
my $AF = [map $_->ppsym, grep !$_->integer, types]; |
|
42
|
|
|
|
|
|
|
$AF = [(grep $_ ne 'D', @$AF), 'D']; # so defaults to D if non-float given |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
pp_addpm({At=>'Top'},<<'EOD'); |
|
45
|
|
|
|
|
|
|
use strict; |
|
46
|
|
|
|
|
|
|
use warnings; |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
=head1 NAME |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
PDL::Math - extended mathematical operations and special functions |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
use PDL::Math; |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
use PDL::Graphics::TriD; |
|
57
|
|
|
|
|
|
|
imag3d [SURF2D,bessj0(rvals(zeroes(50,50))/2)]; |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
This module extends PDL with more advanced mathematical functions than |
|
62
|
|
|
|
|
|
|
provided by standard Perl. |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
All the functions have one input pdl, and one output, unless otherwise |
|
65
|
|
|
|
|
|
|
stated. |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
Many of the functions are linked from the system maths library or the |
|
68
|
|
|
|
|
|
|
Cephes maths library (determined when PDL is compiled); a few are implemented |
|
69
|
|
|
|
|
|
|
entirely in PDL. |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=cut |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
### Kludge for backwards compatibility with older scripts |
|
74
|
|
|
|
|
|
|
### This should be deleted at some point later than 21-Nov-2003. |
|
75
|
|
|
|
|
|
|
BEGIN {use PDL::MatrixOps;} |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
EOD |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Internal doc util |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
my %doco; |
|
82
|
|
|
|
|
|
|
sub doco { |
|
83
|
|
|
|
|
|
|
my @funcs = @_; |
|
84
|
|
|
|
|
|
|
my $doc = pop @funcs; |
|
85
|
|
|
|
|
|
|
for (@funcs) { $doco{$_} = $doc } |
|
86
|
|
|
|
|
|
|
} |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
doco (qw/acos asin atan tan/, <<'EOF'); |
|
89
|
|
|
|
|
|
|
The usual trigonometric function. |
|
90
|
|
|
|
|
|
|
EOF |
|
91
|
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
doco (qw/cosh sinh tanh acosh asinh atanh/, <<'EOF'); |
|
93
|
|
|
|
|
|
|
The standard hyperbolic function. |
|
94
|
|
|
|
|
|
|
EOF |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
doco (qw/ceil floor/, |
|
97
|
|
|
|
|
|
|
'Round to integer values in floating-point format.'); |
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
doco ('rint', |
|
100
|
|
|
|
|
|
|
q/=for ref |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
Round to integer values in floating-point format. |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
This is the C99 function; previous to 2.096, the doc referred to a |
|
105
|
|
|
|
|
|
|
bespoke function that did banker's rounding, but this was not used |
|
106
|
|
|
|
|
|
|
as a system version will have been detected and used. |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
If you are looking to round half-integers up (regardless of sign), try |
|
109
|
|
|
|
|
|
|
C. If you want to round half-integers away from zero, |
|
110
|
|
|
|
|
|
|
try C<< ceil(abs($x)+0.5)*($x<=>0) >>./); |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
doco( 'pow',"Synonym for `**'."); |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
doco ('erf',"The error function."); |
|
115
|
|
|
|
|
|
|
doco ('erfc',"The complement of the error function."); |
|
116
|
|
|
|
|
|
|
doco ('erfi',"The inverse of the error function."); |
|
117
|
|
|
|
|
|
|
doco ('ndtri', |
|
118
|
|
|
|
|
|
|
"=for ref |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
The value for which the area under the |
|
121
|
|
|
|
|
|
|
Gaussian probability density function (integrated from |
|
122
|
|
|
|
|
|
|
minus infinity) is equal to the argument (cf L)."); |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
doco(qw/bessj0 bessj1/, |
|
125
|
|
|
|
|
|
|
"The regular Bessel function of the first kind, J_n" ); |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
doco(qw/bessy0 bessy1/, |
|
128
|
|
|
|
|
|
|
"The regular Bessel function of the second kind, Y_n." ); |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
doco( qw/bessjn/, |
|
131
|
|
|
|
|
|
|
'=for ref |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
The regular Bessel function of the first kind, J_n |
|
134
|
|
|
|
|
|
|
. |
|
135
|
|
|
|
|
|
|
This takes a second int argument which gives the order |
|
136
|
|
|
|
|
|
|
of the function required. |
|
137
|
|
|
|
|
|
|
'); |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
doco( qw/bessyn/, |
|
140
|
|
|
|
|
|
|
'=for ref |
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
The regular Bessel function of the first kind, Y_n |
|
143
|
|
|
|
|
|
|
. |
|
144
|
|
|
|
|
|
|
This takes a second int argument which gives the order |
|
145
|
|
|
|
|
|
|
of the function required. |
|
146
|
|
|
|
|
|
|
'); |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
if ($^O !~ /win32/i || $Config{cc} =~ /\bgcc/i) { # doesn't seem to be in the MS VC lib |
|
149
|
|
|
|
|
|
|
doco( 'lgamma' ,<<'EOD'); |
|
150
|
|
|
|
|
|
|
=for ref |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
log gamma function |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
This returns 2 ndarrays -- the first set gives the log(gamma) values, |
|
155
|
|
|
|
|
|
|
while the second set, of integer values, gives the sign of the gamma |
|
156
|
|
|
|
|
|
|
function. This is useful for determining factorials, amongst other |
|
157
|
|
|
|
|
|
|
things. |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
EOD |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
} # if: $^O !~ win32 |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
pp_addhdr(' |
|
164
|
|
|
|
|
|
|
#include |
|
165
|
|
|
|
|
|
|
#include "protos.h" |
|
166
|
|
|
|
|
|
|
#include "cpoly.h" |
|
167
|
|
|
|
|
|
|
'); |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# Standard `-lm' |
|
170
|
|
|
|
|
|
|
my (@ufuncs1) = qw(acos asin atan cosh sinh tan tanh); # F,D only |
|
171
|
|
|
|
|
|
|
my (@ufuncs1g) = qw(ceil floor rint); # Any real type |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# Note: |
|
174
|
|
|
|
|
|
|
# ops.pd has a power() function that does the same thing |
|
175
|
|
|
|
|
|
|
# (although it has OtherPars => 'int swap;' as well) |
|
176
|
|
|
|
|
|
|
# - left this in for now. |
|
177
|
|
|
|
|
|
|
# |
|
178
|
|
|
|
|
|
|
my (@bifuncs1) = qw(pow); # Any type |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# Extended `-lm' |
|
181
|
|
|
|
|
|
|
my (@ufuncs2) = qw(acosh asinh atanh erf erfc); # F,D only |
|
182
|
|
|
|
|
|
|
my (@besufuncs) = qw(j0 j1 y0 y1); # " |
|
183
|
|
|
|
|
|
|
my (@besbifuncs) = qw(jn yn); # " |
|
184
|
|
|
|
|
|
|
# Need igamma, ibeta, and a fall-back implementation of the above |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub code_ufunc { |
|
187
|
|
|
|
|
|
|
<
|
|
188
|
|
|
|
|
|
|
PDL_IF_BAD(if ( \$ISBAD(a()) ) { \$SETBAD(b()); } else,) |
|
189
|
|
|
|
|
|
|
\$b() = $_[0](\$a()); |
|
190
|
|
|
|
|
|
|
EOF |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub code_bifunc { |
|
194
|
|
|
|
|
|
|
my $name = $_[0]; |
|
195
|
|
|
|
|
|
|
my $x = $_[1] || 'a'; my $y = $_[2] || 'b'; my $c = $_[3] || 'c'; |
|
196
|
|
|
|
|
|
|
<
|
|
197
|
|
|
|
|
|
|
PDL_IF_BAD(if ( \$ISBAD($x()) || \$ISBAD($y()) ) { \$SETBAD($c()); } else,) |
|
198
|
|
|
|
|
|
|
\$$c() = $name(\$$x(),\$$y()); |
|
199
|
|
|
|
|
|
|
EOF |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
foreach my $func (@ufuncs1) { |
|
203
|
|
|
|
|
|
|
my $got_complex = PDL::Core::Dev::got_complex_version($func, 1); |
|
204
|
|
|
|
|
|
|
pp_def($func, |
|
205
|
|
|
|
|
|
|
HandleBad => 1, |
|
206
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
207
|
|
|
|
|
|
|
GenericTypes => [($got_complex ? @$C : ()), @$F], |
|
208
|
|
|
|
|
|
|
Pars => 'a(); [o]b();', |
|
209
|
|
|
|
|
|
|
Inplace => 1, |
|
210
|
|
|
|
|
|
|
Doc => $doco{$func}, |
|
211
|
|
|
|
|
|
|
Code => code_ufunc($func), |
|
212
|
|
|
|
|
|
|
); |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
# real types |
|
215
|
|
|
|
|
|
|
foreach my $func (@ufuncs1g) { |
|
216
|
|
|
|
|
|
|
pp_def($func, |
|
217
|
|
|
|
|
|
|
HandleBad => 1, |
|
218
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
219
|
|
|
|
|
|
|
Pars => 'a(); [o]b();', |
|
220
|
|
|
|
|
|
|
Inplace => 1, |
|
221
|
|
|
|
|
|
|
Doc => $doco{$func}, |
|
222
|
|
|
|
|
|
|
Code => code_ufunc($func), |
|
223
|
|
|
|
|
|
|
); |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
foreach my $func (@bifuncs1) { |
|
227
|
|
|
|
|
|
|
my $got_complex = PDL::Core::Dev::got_complex_version($func, 2); |
|
228
|
|
|
|
|
|
|
pp_def($func, |
|
229
|
|
|
|
|
|
|
HandleBad => 1, |
|
230
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
231
|
|
|
|
|
|
|
Pars => 'a(); b(); [o]c();', |
|
232
|
|
|
|
|
|
|
Inplace => [ 'a' ], |
|
233
|
|
|
|
|
|
|
GenericTypes => [($got_complex ? @$C : ()), @$R], |
|
234
|
|
|
|
|
|
|
Doc => $doco{$func}, |
|
235
|
|
|
|
|
|
|
Code => code_bifunc($func), |
|
236
|
|
|
|
|
|
|
); |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
# Functions provided by extended -lm |
|
240
|
|
|
|
|
|
|
foreach my $func (@ufuncs2) { |
|
241
|
|
|
|
|
|
|
pp_def($func, |
|
242
|
|
|
|
|
|
|
HandleBad => 1, |
|
243
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
244
|
|
|
|
|
|
|
GenericTypes => $F, |
|
245
|
|
|
|
|
|
|
Pars => 'a(); [o]b();', |
|
246
|
|
|
|
|
|
|
Inplace => 1, |
|
247
|
|
|
|
|
|
|
Doc => $doco{$func}, |
|
248
|
|
|
|
|
|
|
Code => code_ufunc($func), |
|
249
|
|
|
|
|
|
|
); |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
foreach my $func (@besufuncs) { |
|
253
|
|
|
|
|
|
|
my $fname = "bess$func"; |
|
254
|
|
|
|
|
|
|
pp_def($fname, |
|
255
|
|
|
|
|
|
|
HandleBad => 1, |
|
256
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
257
|
|
|
|
|
|
|
GenericTypes => $F, |
|
258
|
|
|
|
|
|
|
Pars => 'a(); [o]b();', |
|
259
|
|
|
|
|
|
|
Inplace => 1, |
|
260
|
|
|
|
|
|
|
Doc => $doco{$fname}, |
|
261
|
|
|
|
|
|
|
Code => code_ufunc($func), |
|
262
|
|
|
|
|
|
|
); |
|
263
|
|
|
|
|
|
|
} |
|
264
|
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
foreach my $func (@besbifuncs) { |
|
266
|
|
|
|
|
|
|
my $fname = "bess$func"; |
|
267
|
|
|
|
|
|
|
pp_def($fname, |
|
268
|
|
|
|
|
|
|
HandleBad => 1, |
|
269
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
270
|
|
|
|
|
|
|
GenericTypes => $F, |
|
271
|
|
|
|
|
|
|
Pars => 'a(); int n(); [o]b();', |
|
272
|
|
|
|
|
|
|
Inplace => [ 'a' ], |
|
273
|
|
|
|
|
|
|
Doc => $doco{$fname}, |
|
274
|
|
|
|
|
|
|
Code => code_bifunc($func,'n','a','b'), |
|
275
|
|
|
|
|
|
|
); |
|
276
|
|
|
|
|
|
|
} |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
if ($^O !~ /win32/i) { |
|
279
|
|
|
|
|
|
|
pp_def("lgamma", |
|
280
|
|
|
|
|
|
|
HandleBad => 1, |
|
281
|
|
|
|
|
|
|
Pars => 'a(); [o]b(); int[o]s()', |
|
282
|
|
|
|
|
|
|
Doc => $doco{"lgamma"}, |
|
283
|
|
|
|
|
|
|
Code => ' |
|
284
|
|
|
|
|
|
|
extern int signgam; |
|
285
|
|
|
|
|
|
|
PDL_IF_BAD(if ( $ISBAD(a()) ) { $SETBAD(b()); $SETBAD(s()); } else,) { |
|
286
|
|
|
|
|
|
|
$b() = lgamma($a()); |
|
287
|
|
|
|
|
|
|
$s() = signgam; |
|
288
|
|
|
|
|
|
|
} |
|
289
|
|
|
|
|
|
|
', # what happens to signgam if $a() is bad? |
|
290
|
|
|
|
|
|
|
); |
|
291
|
|
|
|
|
|
|
} # if: os !~ win32 |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
elsif ($Config{cc} =~ /\bgcc/i) { |
|
294
|
|
|
|
|
|
|
pp_def("lgamma", |
|
295
|
|
|
|
|
|
|
HandleBad => 1, |
|
296
|
|
|
|
|
|
|
Pars => 'a(); [o]b(); int[o]s()', |
|
297
|
|
|
|
|
|
|
Doc => $doco{"lgamma"}, |
|
298
|
|
|
|
|
|
|
Code => ' |
|
299
|
|
|
|
|
|
|
PDL_IF_BAD(if ( $ISBAD(a()) ) { $SETBAD(b()); $SETBAD(s()); } else,) { |
|
300
|
|
|
|
|
|
|
$b() = lgamma($a()); |
|
301
|
|
|
|
|
|
|
$s() = tgamma($a()) < 0 ? -1 : 1; |
|
302
|
|
|
|
|
|
|
} |
|
303
|
|
|
|
|
|
|
', # what happens to signgam if $a() is bad? |
|
304
|
|
|
|
|
|
|
); |
|
305
|
|
|
|
|
|
|
} # elsif: cc =~ /\bgcc/i |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
pp_def('isfinite', |
|
308
|
|
|
|
|
|
|
Pars => 'a(); int [o]mask();', |
|
309
|
|
|
|
|
|
|
HandleBad => 1, |
|
310
|
|
|
|
|
|
|
Code => <<'EOF', |
|
311
|
|
|
|
|
|
|
broadcastloop %{ |
|
312
|
|
|
|
|
|
|
$mask() = isfinite((double) $a()) != 0 PDL_IF_BAD(&& $ISGOOD($a()),); |
|
313
|
|
|
|
|
|
|
%} |
|
314
|
|
|
|
|
|
|
$PDLSTATESETGOOD(mask); |
|
315
|
|
|
|
|
|
|
EOF |
|
316
|
|
|
|
|
|
|
Doc => |
|
317
|
|
|
|
|
|
|
'Sets C<$mask> true if C<$a> is not a C or C (either positive or negative).', |
|
318
|
|
|
|
|
|
|
BadDoc => |
|
319
|
|
|
|
|
|
|
'Bad values are treated as C or C.', |
|
320
|
|
|
|
|
|
|
); |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
# Extra functions from cephes |
|
323
|
|
|
|
|
|
|
pp_def("erfi", |
|
324
|
|
|
|
|
|
|
HandleBad => 1, |
|
325
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
326
|
|
|
|
|
|
|
GenericTypes => $F, |
|
327
|
|
|
|
|
|
|
Pars => 'a(); [o]b()', |
|
328
|
|
|
|
|
|
|
Inplace => 1, |
|
329
|
|
|
|
|
|
|
Doc => "erfi", |
|
330
|
|
|
|
|
|
|
Code => |
|
331
|
|
|
|
|
|
|
'extern double SQRTH; |
|
332
|
|
|
|
|
|
|
PDL_IF_BAD(if ( $ISBAD(a()) ) { $SETBAD(b()); } |
|
333
|
|
|
|
|
|
|
else,) { $b() = SQRTH*ndtri((1+(double)$a())/2); }', |
|
334
|
|
|
|
|
|
|
); |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
pp_def("ndtri", |
|
337
|
|
|
|
|
|
|
HandleBad => 1, |
|
338
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
339
|
|
|
|
|
|
|
GenericTypes => $F, |
|
340
|
|
|
|
|
|
|
Pars => 'a(); [o]b()', |
|
341
|
|
|
|
|
|
|
Inplace => 1, |
|
342
|
|
|
|
|
|
|
Doc => "ndtri", |
|
343
|
|
|
|
|
|
|
Code => |
|
344
|
|
|
|
|
|
|
'PDL_IF_BAD(if ( $ISBAD(a()) ) { $SETBAD(b()); } |
|
345
|
|
|
|
|
|
|
else,) { $b() = ndtri((double)$a()); }', |
|
346
|
|
|
|
|
|
|
); |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
pp_def("polyroots", |
|
349
|
|
|
|
|
|
|
Pars => 'cr(n); ci(n); [o]rr(m=CALC($SIZE(n)-1)); [o]ri(m);', |
|
350
|
|
|
|
|
|
|
GenericTypes => ['D'], |
|
351
|
|
|
|
|
|
|
Code => <<'EOF', |
|
352
|
|
|
|
|
|
|
char *fail = cpoly($P(cr), $P(ci), $SIZE(m), $P(rr), $P(ri)); |
|
353
|
|
|
|
|
|
|
if (fail) |
|
354
|
|
|
|
|
|
|
$CROAK("cpoly: %s", fail); |
|
355
|
|
|
|
|
|
|
EOF |
|
356
|
|
|
|
|
|
|
PMCode => pp_line_numbers(__LINE__, <<'EOF'), |
|
357
|
|
|
|
|
|
|
sub PDL::polyroots { |
|
358
|
|
|
|
|
|
|
my @args = map PDL->topdl($_), @_; |
|
359
|
|
|
|
|
|
|
my $natcplx = !$args[0]->type->real; |
|
360
|
|
|
|
|
|
|
barf "need array context if give real data and no outputs" |
|
361
|
|
|
|
|
|
|
if !$natcplx and @_ < 3 and !(wantarray//1); |
|
362
|
|
|
|
|
|
|
splice @args, 0, 1, map $args[0]->$_, qw(re im) if $natcplx; |
|
363
|
|
|
|
|
|
|
my @ins = splice @args, 0, 2; |
|
364
|
|
|
|
|
|
|
my $explicit_out = my @outs = @args; |
|
365
|
|
|
|
|
|
|
if ($natcplx) { |
|
366
|
|
|
|
|
|
|
$_ //= PDL->null for $outs[0]; |
|
367
|
|
|
|
|
|
|
} else { |
|
368
|
|
|
|
|
|
|
$_ //= PDL->null for @outs[0,1]; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
my @args_out = $natcplx ? (map PDL->null, 1..2) : @outs; # opposite from polyfromroots |
|
371
|
|
|
|
|
|
|
PDL::_polyroots_int(@ins, @args_out); |
|
372
|
|
|
|
|
|
|
return @args_out if !$natcplx; |
|
373
|
|
|
|
|
|
|
$outs[0] .= PDL::czip(@args_out[0,1]); |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
EOF |
|
376
|
|
|
|
|
|
|
Doc => ' |
|
377
|
|
|
|
|
|
|
=for ref |
|
378
|
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
Complex roots of a complex polynomial, given coefficients in order |
|
380
|
|
|
|
|
|
|
of decreasing powers. Only works for degree >= 1. |
|
381
|
|
|
|
|
|
|
Uses the Jenkins-Traub algorithm (see |
|
382
|
|
|
|
|
|
|
L). |
|
383
|
|
|
|
|
|
|
As of 2.086, works with native-complex data. |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
=for usage |
|
386
|
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
$roots = polyroots($coeffs); # native complex |
|
388
|
|
|
|
|
|
|
polyroots($coeffs, $roots=null); # native complex |
|
389
|
|
|
|
|
|
|
($rr, $ri) = polyroots($cr, $ci); |
|
390
|
|
|
|
|
|
|
polyroots($cr, $ci, $rr, $ri); |
|
391
|
|
|
|
|
|
|
',); |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
pp_def("polyfromroots", |
|
394
|
|
|
|
|
|
|
Pars => 'r(m); [o]c(n=CALC($SIZE(m)+1));', |
|
395
|
|
|
|
|
|
|
GenericTypes => ['CD'], |
|
396
|
|
|
|
|
|
|
Code => <<'EOF', |
|
397
|
|
|
|
|
|
|
$c(n=>0) = 1.0; |
|
398
|
|
|
|
|
|
|
loop(m) %{ $c(n=>m+1) = 0.0; %} |
|
399
|
|
|
|
|
|
|
PDL_Indx k; |
|
400
|
|
|
|
|
|
|
loop(m) %{ |
|
401
|
|
|
|
|
|
|
for (k = m; k >= 0; k--) /* count down to use data before we mutate */ |
|
402
|
|
|
|
|
|
|
$c(n=>k+1) -= $r() * $c(n=>k); |
|
403
|
|
|
|
|
|
|
%} |
|
404
|
|
|
|
|
|
|
EOF |
|
405
|
|
|
|
|
|
|
PMCode => pp_line_numbers(__LINE__, <<'EOF'), |
|
406
|
|
|
|
|
|
|
sub PDL::polyfromroots { |
|
407
|
|
|
|
|
|
|
my @args = map PDL->topdl($_), @_; |
|
408
|
|
|
|
|
|
|
my $natcplx = !$args[0]->type->real; |
|
409
|
|
|
|
|
|
|
barf "need array context" if !$natcplx and !(wantarray//1); |
|
410
|
|
|
|
|
|
|
if (!$natcplx) { |
|
411
|
|
|
|
|
|
|
splice @args, 0, 2, $args[0]->czip($args[1]); # r |
|
412
|
|
|
|
|
|
|
} |
|
413
|
|
|
|
|
|
|
my @ins = splice @args, 0, 1; |
|
414
|
|
|
|
|
|
|
my $explicit_out = my @outs = @args; |
|
415
|
|
|
|
|
|
|
if ($natcplx) { |
|
416
|
|
|
|
|
|
|
$_ //= PDL->null for $outs[0]; |
|
417
|
|
|
|
|
|
|
} else { |
|
418
|
|
|
|
|
|
|
$_ //= PDL->null for @outs[0,1]; |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
my @args_out = $natcplx ? @outs : PDL->null; |
|
421
|
|
|
|
|
|
|
PDL::_polyfromroots_int(@ins, @args_out); |
|
422
|
|
|
|
|
|
|
if (!$natcplx) { |
|
423
|
|
|
|
|
|
|
$outs[0] .= $args_out[0]->re; |
|
424
|
|
|
|
|
|
|
$outs[1] .= $args_out[0]->im; |
|
425
|
|
|
|
|
|
|
} |
|
426
|
|
|
|
|
|
|
$natcplx ? $outs[0] : @outs; |
|
427
|
|
|
|
|
|
|
} |
|
428
|
|
|
|
|
|
|
EOF |
|
429
|
|
|
|
|
|
|
Doc => ' |
|
430
|
|
|
|
|
|
|
=for ref |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
Calculates the complex coefficients of a polynomial from its complex |
|
433
|
|
|
|
|
|
|
roots, in order of decreasing powers. Added in 2.086, works with |
|
434
|
|
|
|
|
|
|
native-complex data. |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
Algorithm is from Octave poly.m, O(n^2), per |
|
437
|
|
|
|
|
|
|
L; |
|
438
|
|
|
|
|
|
|
using an FFT would allow O(n*log(n)^2). |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=for usage |
|
441
|
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
$coeffs = polyfromroots($roots); # native complex |
|
443
|
|
|
|
|
|
|
($cr, $ci) = polyfromroots($rr, $ri); |
|
444
|
|
|
|
|
|
|
',); |
|
445
|
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
pp_def("polyval", |
|
447
|
|
|
|
|
|
|
Pars => 'c(n); x(); [o]y();', |
|
448
|
|
|
|
|
|
|
GenericTypes => ['CD'], |
|
449
|
|
|
|
|
|
|
Code => <<'EOF', |
|
450
|
|
|
|
|
|
|
$GENERIC(y) vc = $c(n=>0), sc = $x(); |
|
451
|
|
|
|
|
|
|
loop(n=1) %{ vc = vc*sc + $c(); %} |
|
452
|
|
|
|
|
|
|
$y() = vc; |
|
453
|
|
|
|
|
|
|
EOF |
|
454
|
|
|
|
|
|
|
PMCode => pp_line_numbers(__LINE__, <<'EOF'), |
|
455
|
|
|
|
|
|
|
sub PDL::polyval { |
|
456
|
|
|
|
|
|
|
my @args = map PDL->topdl($_), @_; |
|
457
|
|
|
|
|
|
|
my $natcplx = !$args[0]->type->real; |
|
458
|
|
|
|
|
|
|
barf "need array context" if !$natcplx and !(wantarray//1); |
|
459
|
|
|
|
|
|
|
if (!$natcplx) { |
|
460
|
|
|
|
|
|
|
splice @args, 0, 2, $args[0]->czip($args[1]); # c |
|
461
|
|
|
|
|
|
|
splice @args, 1, 2, $args[1]->czip($args[2]); # x |
|
462
|
|
|
|
|
|
|
} |
|
463
|
|
|
|
|
|
|
my @ins = splice @args, 0, 2; |
|
464
|
|
|
|
|
|
|
my $explicit_out = my @outs = @args; |
|
465
|
|
|
|
|
|
|
if ($natcplx) { |
|
466
|
|
|
|
|
|
|
$_ //= PDL->null for $outs[0]; |
|
467
|
|
|
|
|
|
|
} else { |
|
468
|
|
|
|
|
|
|
$_ //= PDL->null for @outs[0,1]; |
|
469
|
|
|
|
|
|
|
} |
|
470
|
|
|
|
|
|
|
my @args_out = $natcplx ? @outs : PDL->null; |
|
471
|
|
|
|
|
|
|
PDL::_polyval_int(@ins, @args_out); |
|
472
|
|
|
|
|
|
|
if (!$natcplx) { |
|
473
|
|
|
|
|
|
|
$outs[0] .= $args_out[0]->re; |
|
474
|
|
|
|
|
|
|
$outs[1] .= $args_out[0]->im; |
|
475
|
|
|
|
|
|
|
} |
|
476
|
|
|
|
|
|
|
$natcplx ? $outs[0] : @outs; |
|
477
|
|
|
|
|
|
|
} |
|
478
|
|
|
|
|
|
|
EOF |
|
479
|
|
|
|
|
|
|
Doc => ' |
|
480
|
|
|
|
|
|
|
=for ref |
|
481
|
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Complex value of a complex polynomial at given point, given coefficients |
|
483
|
|
|
|
|
|
|
in order of decreasing powers. Uses Horner recurrence. Added in 2.086, |
|
484
|
|
|
|
|
|
|
works with native-complex data. |
|
485
|
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=for usage |
|
487
|
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
$y = polyval($coeffs, $x); # native complex |
|
489
|
|
|
|
|
|
|
($yr, $yi) = polyval($cr, $ci, $xr, $xi); |
|
490
|
|
|
|
|
|
|
',); |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub cequiv { |
|
493
|
|
|
|
|
|
|
my ($func, $ref) = @_; |
|
494
|
|
|
|
|
|
|
return if !PDL::Core::Dev::got_complex_version($func, 1); |
|
495
|
|
|
|
|
|
|
pp_def("c$func", |
|
496
|
|
|
|
|
|
|
GenericTypes => $AF, |
|
497
|
|
|
|
|
|
|
Pars => 'i(); complex [o] o()', |
|
498
|
|
|
|
|
|
|
Doc => <
|
|
499
|
|
|
|
|
|
|
=for ref\n |
|
500
|
|
|
|
|
|
|
Takes real or complex data, returns the complex C<$func>.\n |
|
501
|
|
|
|
|
|
|
Added in 2.099. |
|
502
|
|
|
|
|
|
|
EOF |
|
503
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <
|
|
504
|
|
|
|
|
|
|
\$TFDEGCH(PDL_CFloat,PDL_CDouble,PDL_CLDouble,PDL_CFloat,PDL_CDouble,PDL_CLDouble) tmp = \$i(); |
|
505
|
|
|
|
|
|
|
tmp = c$func(tmp); |
|
506
|
|
|
|
|
|
|
\$o() = tmp; |
|
507
|
|
|
|
|
|
|
EOF |
|
508
|
|
|
|
|
|
|
); |
|
509
|
|
|
|
|
|
|
} |
|
510
|
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
cequiv($_) for qw(sqrt log acos asin acosh atanh); |
|
512
|
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
pp_def('csqrt_up', |
|
514
|
|
|
|
|
|
|
GenericTypes => $AF, |
|
515
|
|
|
|
|
|
|
Pars => 'i(); complex [o] o()', |
|
516
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
517
|
|
|
|
|
|
|
Take the complex square root of a number choosing that whose imaginary |
|
518
|
|
|
|
|
|
|
part is not negative, i.e., it is a square root with a branch cut |
|
519
|
|
|
|
|
|
|
'infinitesimally' below the positive real axis. |
|
520
|
|
|
|
|
|
|
EOF |
|
521
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <<'EOF'), |
|
522
|
136
|
|
|
|
|
625
|
$TFDEGCH(PDL_CFloat,PDL_CDouble,PDL_CLDouble,PDL_CFloat,PDL_CDouble,PDL_CLDouble) tmp = $i(); |
|
523
|
136
|
|
|
|
|
123
|
tmp = csqrt(tmp); |
|
524
|
136
|
50
|
|
|
|
2622
|
if (cimag(tmp)<0) |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
525
|
74
|
|
|
|
|
312
|
tmp = -tmp; |
|
526
|
136
|
|
|
|
|
112
|
$o() = tmp; |
|
527
|
|
|
|
|
|
|
EOF |
|
528
|
|
|
|
|
|
|
); |
|
529
|
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
pp_addpm({At=>'Bot'},<<'EOD'); |
|
531
|
|
|
|
|
|
|
=head1 AUTHOR |
|
532
|
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
Copyright (C) R.J.R. Williams 1997 (rjrw@ast.leeds.ac.uk), Karl Glazebrook |
|
534
|
|
|
|
|
|
|
(kgb@aaoepp.aao.gov.au) and Tuomas J. Lukka (Tuomas.Lukka@helsinki.fi). |
|
535
|
|
|
|
|
|
|
Portions (C) Craig DeForest 2002 (deforest@boulder.swri.edu). |
|
536
|
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
All rights reserved. There is no warranty. You are allowed |
|
538
|
|
|
|
|
|
|
to redistribute this software / documentation under certain |
|
539
|
|
|
|
|
|
|
conditions. For details, see the file COPYING in the PDL |
|
540
|
|
|
|
|
|
|
distribution. If this file is separated from the PDL distribution, |
|
541
|
|
|
|
|
|
|
the PDL copyright notice should be included in the file. |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=cut |
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
EOD |
|
546
|
|
|
|
|
|
|
pp_done(); |