| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
use strict; |
|
2
|
|
|
|
|
|
|
use warnings; |
|
3
|
|
|
|
|
|
|
use PDL::Types qw(types ppdefs ppdefs_all ppdefs_complex); |
|
4
|
|
|
|
|
|
|
require PDL::Core::Dev; |
|
5
|
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
my $A = [ppdefs_all]; |
|
7
|
|
|
|
|
|
|
my $C = [ppdefs_complex]; |
|
8
|
|
|
|
|
|
|
my $F = [map $_->ppsym, grep $_->real && !$_->integer, types]; |
|
9
|
|
|
|
|
|
|
$F = [(grep $_ ne 'D', @$F), 'D']; # so defaults to D if non-float given |
|
10
|
|
|
|
|
|
|
my $AF = [map $_->ppsym, grep !$_->integer, types]; |
|
11
|
|
|
|
|
|
|
$AF = [(grep $_ ne 'D', @$AF), 'D']; # so defaults to D if non-float given |
|
12
|
|
|
|
|
|
|
my $T = [map $_->ppsym, grep $_->integer, types]; |
|
13
|
|
|
|
|
|
|
my $U = [map $_->ppsym, grep $_->unsigned, types]; |
|
14
|
|
|
|
|
|
|
my $S = [map $_->ppsym, grep $_->real && !$_->unsigned, types]; |
|
15
|
|
|
|
|
|
|
my %is_real; @is_real{ppdefs()} = (); |
|
16
|
|
|
|
|
|
|
my @Rtypes = grep $_->real, types(); |
|
17
|
|
|
|
|
|
|
my @Ctypes = grep !$_->real, types(); |
|
18
|
|
|
|
|
|
|
my @Ftypes = grep !$_->integer, types(); |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
pp_addpm({At=>'Top'},<<'EOD'); |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
use strict; |
|
23
|
|
|
|
|
|
|
use warnings; |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head1 NAME |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
PDL::Ops - Fundamental mathematical operators |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
This module provides the functions used by PDL to |
|
32
|
|
|
|
|
|
|
overload the basic mathematical operators (C<+ - / *> |
|
33
|
|
|
|
|
|
|
etc.) and functions (C etc.) |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
It also includes the function C, which should |
|
36
|
|
|
|
|
|
|
be a perl function so that we can overload it! |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
Matrix multiplication (the operator C) is handled |
|
39
|
|
|
|
|
|
|
by the module L. |
|
40
|
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
none |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
=cut |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
EOD |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
pp_addpm({At=>'Bot'},<<'EOPM'); |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=head1 AUTHOR |
|
52
|
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
Tuomas J. Lukka (lukka@fas.harvard.edu), |
|
54
|
|
|
|
|
|
|
Karl Glazebrook (kgb@aaoepp.aao.gov.au), |
|
55
|
|
|
|
|
|
|
Doug Hunt (dhunt@ucar.edu), |
|
56
|
|
|
|
|
|
|
Christian Soeller (c.soeller@auckland.ac.nz), |
|
57
|
|
|
|
|
|
|
Doug Burke (burke@ifa.hawaii.edu), |
|
58
|
|
|
|
|
|
|
and Craig DeForest (deforest@boulder.swri.edu). |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=cut |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
EOPM |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
pp_addhdr(' |
|
65
|
|
|
|
|
|
|
#include |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
#define MOD(X,N) (((N) == 0) ? 0 : ( (X) - (PDL_ABS(N)) * ((long long)((X)/(PDL_ABS(N))) + ( ( ((N) * ((long long)((X)/(N)))) != (X) ) ? ( ( ((N)<0) ? 1 : 0 ) + ( (((X)<0) ? -1 : 0))) : 0 )))) |
|
68
|
|
|
|
|
|
|
#define BU_MOD(X,N)(((N) == 0) ? 0 : ( (X)-(N)*((uint64_t)((X)/(N))) )) |
|
69
|
|
|
|
|
|
|
#define SPACE(A,B) ( ((A)<(B)) ? -1 : ((A)!=(B)) ) |
|
70
|
|
|
|
|
|
|
'); |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
my %char2escape = ('>'=>'E','<'=>'E'); |
|
73
|
|
|
|
|
|
|
my $chars = '(['.join('', map quotemeta, sort keys %char2escape).'])'; |
|
74
|
|
|
|
|
|
|
sub protect_chars { |
|
75
|
|
|
|
|
|
|
my ($txt) = @_; |
|
76
|
|
|
|
|
|
|
$txt =~ s/$chars/$char2escape{$1}/g; |
|
77
|
|
|
|
|
|
|
return $txt; |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
# simple binary operators |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
pp_addhdr(pp_line_numbers(__LINE__, <<'EOF')); |
|
83
|
|
|
|
|
|
|
#define PDL_BADVAL_WARN_X(datatype, ctype, ppsym, ...) \ |
|
84
|
|
|
|
|
|
|
bad_anyval.type = datatype; bad_anyval.value.ppsym = PDL->bvals.ppsym; |
|
85
|
|
|
|
|
|
|
#define PDL_BADVAL_WARN(var) \ |
|
86
|
|
|
|
|
|
|
{ \ |
|
87
|
|
|
|
|
|
|
PDL_Anyval bad_anyval = { PDL_INVALID, {0} }; \ |
|
88
|
|
|
|
|
|
|
if (!(var->has_badvalue && var->badvalue.type != var->datatype)) { \ |
|
89
|
|
|
|
|
|
|
if (var->has_badvalue) \ |
|
90
|
|
|
|
|
|
|
bad_anyval = var->badvalue; \ |
|
91
|
|
|
|
|
|
|
else { \ |
|
92
|
|
|
|
|
|
|
PDL_GENERICSWITCH(PDL_TYPELIST_ALL, var->datatype, PDL_BADVAL_WARN_X, ) \ |
|
93
|
|
|
|
|
|
|
} \ |
|
94
|
|
|
|
|
|
|
} \ |
|
95
|
|
|
|
|
|
|
if (bad_anyval.type < 0) \ |
|
96
|
|
|
|
|
|
|
barf("Error getting badvalue, type=%d", bad_anyval.type); \ |
|
97
|
|
|
|
|
|
|
complex double bad_c; \ |
|
98
|
|
|
|
|
|
|
ANYVAL_TO_CTYPE(bad_c, complex double, bad_anyval); \ |
|
99
|
|
|
|
|
|
|
if( bad_c == 0 || bad_c == 1 ) \ |
|
100
|
|
|
|
|
|
|
warn(#var " badvalue is set to 0 or 1. This will cause data loss when using badvalues for comparison operators."); \ |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
EOF |
|
103
|
|
|
|
|
|
|
sub biop { |
|
104
|
|
|
|
|
|
|
my ($name,$op,$mutator,$doc,%extra) = @_; |
|
105
|
|
|
|
|
|
|
my $optxt = protect_chars ref $op eq 'ARRAY' ? $op->[1] : $op; |
|
106
|
|
|
|
|
|
|
$op = $op->[0] if ref $op eq 'ARRAY'; |
|
107
|
|
|
|
|
|
|
$extra{HdrCode} = << 'EOH'; |
|
108
|
|
|
|
|
|
|
if (swap) { |
|
109
|
|
|
|
|
|
|
pdl *tmp = a; |
|
110
|
|
|
|
|
|
|
a = b; |
|
111
|
|
|
|
|
|
|
b = tmp; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
|
|
|
|
|
|
EOH |
|
114
|
|
|
|
|
|
|
# handle exceptions |
|
115
|
|
|
|
|
|
|
if ( exists $extra{Exception} ) { |
|
116
|
|
|
|
|
|
|
# NOTE This option is unused. |
|
117
|
|
|
|
|
|
|
# See also `ufunc()`. |
|
118
|
|
|
|
|
|
|
delete $extra{Exception}; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
if ($extra{Comparison}) { |
|
121
|
|
|
|
|
|
|
my $first_complex = $Ctypes[0]->sym; |
|
122
|
|
|
|
|
|
|
$extra{HdrCode} .= < 1; |
|
123
|
|
|
|
|
|
|
if ((a->datatype >= $first_complex) || (b->datatype >= $first_complex)) |
|
124
|
|
|
|
|
|
|
barf("Can't compare complex numbers"); |
|
125
|
|
|
|
|
|
|
EOF |
|
126
|
|
|
|
|
|
|
$extra{HdrCode} .= " PDL_BADVAL_WARN(a)\n PDL_BADVAL_WARN(b)\n"; |
|
127
|
|
|
|
|
|
|
delete $extra{Comparison}; |
|
128
|
|
|
|
|
|
|
} |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
my $bitwise = delete $extra{Bitwise}; |
|
131
|
|
|
|
|
|
|
pp_def($name, |
|
132
|
|
|
|
|
|
|
Pars => 'a(); b(); [o]c();', |
|
133
|
|
|
|
|
|
|
OtherPars => 'int $swap', |
|
134
|
|
|
|
|
|
|
OtherParsDefaults => { swap => 0 }, |
|
135
|
|
|
|
|
|
|
HandleBad => 1, |
|
136
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
137
|
|
|
|
|
|
|
Inplace => [ 'a' ], |
|
138
|
|
|
|
|
|
|
Overload => [$op, $mutator, $bitwise], |
|
139
|
|
|
|
|
|
|
NoExport => 1, |
|
140
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <
|
|
141
|
|
|
|
|
|
|
PDL_IF_BAD(char anybad = 0;,) |
|
142
|
|
|
|
|
|
|
broadcastloop %{ |
|
143
|
|
|
|
|
|
|
PDL_IF_BAD(if ( ( \$PDLSTATEISBAD(a) && \$ISBAD(a()) ) |
|
144
|
|
|
|
|
|
|
|| ( \$PDLSTATEISBAD(b) && \$ISBAD(b()) )) { \$SETBAD(c()); anybad = 1; } else,) |
|
145
|
|
|
|
|
|
|
\$c() = \$a() $op \$b(); |
|
146
|
|
|
|
|
|
|
%} |
|
147
|
|
|
|
|
|
|
PDL_IF_BAD(if (anybad) \$PDLSTATESETBAD(c);,) |
|
148
|
|
|
|
|
|
|
EOF |
|
149
|
|
|
|
|
|
|
%extra, |
|
150
|
|
|
|
|
|
|
Doc => $doc, |
|
151
|
|
|
|
|
|
|
); |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
#simple binary functions |
|
155
|
|
|
|
|
|
|
sub bifunc { |
|
156
|
|
|
|
|
|
|
my ($name,$func,$mutator,$doc,%extra) = @_; |
|
157
|
|
|
|
|
|
|
my $funcov = ref $func eq 'ARRAY' ? $func->[1] : $func; |
|
158
|
|
|
|
|
|
|
my $isop = $funcov =~ s/^op//; |
|
159
|
|
|
|
|
|
|
my $funcovp = protect_chars $funcov; |
|
160
|
|
|
|
|
|
|
$func = $func->[0] if ref $func eq 'ARRAY'; |
|
161
|
|
|
|
|
|
|
my $got_complex = PDL::Core::Dev::got_complex_version($func, 2); |
|
162
|
|
|
|
|
|
|
$extra{GenericTypes} = [ grep exists $is_real{$_}, @{$extra{GenericTypes}} ] |
|
163
|
|
|
|
|
|
|
if !$got_complex and $extra{GenericTypes}; |
|
164
|
|
|
|
|
|
|
$extra{HdrCode} .= << 'EOH'; |
|
165
|
|
|
|
|
|
|
if (swap) { |
|
166
|
|
|
|
|
|
|
pdl *tmp = a; |
|
167
|
|
|
|
|
|
|
a = b; |
|
168
|
|
|
|
|
|
|
b = tmp; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
EOH |
|
171
|
|
|
|
|
|
|
# is this one to be used as a function or operator ? |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
my $codestr; |
|
174
|
|
|
|
|
|
|
if ($extra{unsigned}){ |
|
175
|
|
|
|
|
|
|
#a little dance to avoid the MOD macro warnings for byte & ushort datatypes |
|
176
|
|
|
|
|
|
|
my $t = join '', map $_->ppsym, grep $_->real, types(); |
|
177
|
|
|
|
|
|
|
my $v = join ',', map |
|
178
|
|
|
|
|
|
|
$_->unsigned ? 'BU_' : '', |
|
179
|
|
|
|
|
|
|
grep $_->real, types(); |
|
180
|
|
|
|
|
|
|
$codestr = << "ENDCODE"; |
|
181
|
|
|
|
|
|
|
\$c() = (\$GENERIC(c))\$T$t($v)$func(\$a(),\$b()); |
|
182
|
|
|
|
|
|
|
ENDCODE |
|
183
|
|
|
|
|
|
|
#end dance |
|
184
|
|
|
|
|
|
|
} else { |
|
185
|
|
|
|
|
|
|
$codestr = '$c() = ($GENERIC(c))'.$func.'($a(),$b());'; |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
delete $extra{unsigned}; #remove the key so it doesn't get added in pp_def. |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
pp_def($name, |
|
190
|
|
|
|
|
|
|
HandleBad => 1, |
|
191
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
192
|
|
|
|
|
|
|
Pars => 'a(); b(); [o]c();', |
|
193
|
|
|
|
|
|
|
OtherPars => 'int $swap', |
|
194
|
|
|
|
|
|
|
OtherParsDefaults => { swap => 0 }, |
|
195
|
|
|
|
|
|
|
Inplace => [ 'a' ], |
|
196
|
|
|
|
|
|
|
Overload => [$funcov, $mutator], |
|
197
|
|
|
|
|
|
|
NoExport => 1, |
|
198
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <
|
|
199
|
|
|
|
|
|
|
PDL_IF_BAD(char anybad = 0;,) |
|
200
|
|
|
|
|
|
|
broadcastloop %{ |
|
201
|
|
|
|
|
|
|
PDL_IF_BAD(if ( \$ISBAD(a()) || \$ISBAD(b()) ) { anybad = 1; \$SETBAD(c()); } else ,) { |
|
202
|
|
|
|
|
|
|
$codestr |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
%} |
|
205
|
|
|
|
|
|
|
PDL_IF_BAD(if (anybad) \$PDLSTATESETBAD(c);,) |
|
206
|
|
|
|
|
|
|
EOF |
|
207
|
|
|
|
|
|
|
%extra, |
|
208
|
|
|
|
|
|
|
Doc => $doc, |
|
209
|
|
|
|
|
|
|
); |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# simple unary functions and operators |
|
213
|
|
|
|
|
|
|
sub ufunc { |
|
214
|
|
|
|
|
|
|
my ($name,$func,$overload,$doc,%extra) = @_; |
|
215
|
|
|
|
|
|
|
my $funcov = ref $func eq 'ARRAY' ? $func->[1] : $func; |
|
216
|
|
|
|
|
|
|
my $funcovp = protect_chars $funcov; |
|
217
|
|
|
|
|
|
|
$func = $func->[0] if ref $func eq 'ARRAY'; |
|
218
|
|
|
|
|
|
|
my $got_complex = PDL::Core::Dev::got_complex_version($func, 1); |
|
219
|
|
|
|
|
|
|
$extra{GenericTypes} = [ grep exists $is_real{$_}, @{$extra{GenericTypes}} ] |
|
220
|
|
|
|
|
|
|
if !$got_complex and $extra{GenericTypes}; |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# handle exceptions |
|
223
|
|
|
|
|
|
|
if ( exists $extra{Exception} ) { |
|
224
|
|
|
|
|
|
|
# print "Warning: ignored exception for $name\n"; |
|
225
|
|
|
|
|
|
|
# NOTE This option is unused. |
|
226
|
|
|
|
|
|
|
# See also `biop()`. |
|
227
|
|
|
|
|
|
|
delete $extra{Exception}; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
my $codestr = '$b() = ($GENERIC(b))'.$func.'($a());'; |
|
230
|
|
|
|
|
|
|
if (delete $extra{NoTgmath} and $got_complex) { |
|
231
|
|
|
|
|
|
|
# don't bother if not got complex version |
|
232
|
|
|
|
|
|
|
$codestr = join "\n", |
|
233
|
|
|
|
|
|
|
'types('.join('', map $_->ppsym, @Rtypes).') %{'.$codestr.'%}', |
|
234
|
|
|
|
|
|
|
(map 'types('.$_->ppsym.') %{$b() = c'.$func.$_->floatsuffix.'($a());%}', @Ctypes), |
|
235
|
|
|
|
|
|
|
; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
# do not have to worry about propagation of the badflag when |
|
238
|
|
|
|
|
|
|
# inplace since only input ndarray is a, hence its badflag |
|
239
|
|
|
|
|
|
|
# won't change |
|
240
|
|
|
|
|
|
|
# UNLESS an exception occurs... |
|
241
|
|
|
|
|
|
|
pp_def($name, |
|
242
|
|
|
|
|
|
|
Pars => 'a(); [o]b()', |
|
243
|
|
|
|
|
|
|
HandleBad => 1, |
|
244
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
245
|
|
|
|
|
|
|
Inplace => 1, |
|
246
|
|
|
|
|
|
|
!$overload ? () : (Overload => $funcov), |
|
247
|
|
|
|
|
|
|
NoExport => 1, |
|
248
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__, <
|
|
249
|
|
|
|
|
|
|
PDL_IF_BAD(if ( \$ISBAD(a()) ) \$SETBAD(b()); else {,) |
|
250
|
|
|
|
|
|
|
$codestr |
|
251
|
|
|
|
|
|
|
PDL_IF_BAD(},) |
|
252
|
|
|
|
|
|
|
EOF |
|
253
|
|
|
|
|
|
|
%extra, |
|
254
|
|
|
|
|
|
|
Doc => $doc, |
|
255
|
|
|
|
|
|
|
); |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
###################################################################### |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# we trap some illegal operations here -- see the Exception option |
|
261
|
|
|
|
|
|
|
# note, for the ufunc()'s, the checks do not work too well |
|
262
|
|
|
|
|
|
|
# for unsigned integer types (ie < 0) |
|
263
|
|
|
|
|
|
|
# |
|
264
|
|
|
|
|
|
|
# XXX needs thinking about |
|
265
|
|
|
|
|
|
|
# - have to integrate into Code section as well (so |
|
266
|
|
|
|
|
|
|
# 12/pdl(2,4,0,3) is trapped and flagged bad) |
|
267
|
|
|
|
|
|
|
# --> complicated |
|
268
|
|
|
|
|
|
|
# - perhaps could use type %{ %} ? |
|
269
|
|
|
|
|
|
|
# |
|
270
|
|
|
|
|
|
|
# ==> currently have commented out the exception code, since |
|
271
|
|
|
|
|
|
|
# want to see if can use NaN/Inf for bad values |
|
272
|
|
|
|
|
|
|
# (would solve many problems for F,D types) |
|
273
|
|
|
|
|
|
|
# |
|
274
|
|
|
|
|
|
|
# there is an issue over how we handle comparison operators |
|
275
|
|
|
|
|
|
|
# - see Primitive/primitive.pd/zcover() for more discussion |
|
276
|
|
|
|
|
|
|
# |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
## arithmetic ops |
|
279
|
|
|
|
|
|
|
biop('plus','+',1,'add two ndarrays',GenericTypes => $A); |
|
280
|
|
|
|
|
|
|
biop('mult','*',1,'multiply two ndarrays',GenericTypes => $A); |
|
281
|
|
|
|
|
|
|
biop('minus','-',1,'subtract two ndarrays',GenericTypes => $A); |
|
282
|
|
|
|
|
|
|
biop('divide','/',1,'divide two ndarrays', Exception => '$b() == 0', GenericTypes => $A); |
|
283
|
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
## note: divide should perhaps trap division by zero as well |
|
285
|
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
## comparison ops |
|
287
|
|
|
|
|
|
|
# not defined for complex numbers |
|
288
|
|
|
|
|
|
|
biop('gt','>',0,'the binary E (greater than) operation', Comparison => 2); |
|
289
|
|
|
|
|
|
|
biop('lt','<',0,'the binary E (less than) operation', Comparison => 2); |
|
290
|
|
|
|
|
|
|
biop('le','<=',0,'the binary E= (less equal) operation', Comparison => 2); |
|
291
|
|
|
|
|
|
|
biop('ge','>=',0,'the binary E= (greater equal) operation', Comparison => 2); |
|
292
|
|
|
|
|
|
|
biop('eq','==',0,'binary I operation (C<==>)', Comparison => 1, GenericTypes => $A); |
|
293
|
|
|
|
|
|
|
biop('ne','!=',0,'binary I operation (C)', Comparison => 1, GenericTypes => $A); |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
## bit ops |
|
296
|
|
|
|
|
|
|
# those need to be limited to the right types |
|
297
|
|
|
|
|
|
|
biop('shiftleft','<<',1,'bitwise leftshift C<$a> by C<$b>',GenericTypes => $T); |
|
298
|
|
|
|
|
|
|
biop('shiftright','>>',1,'bitwise rightshift C<$a> by C<$b>',GenericTypes => $T); |
|
299
|
|
|
|
|
|
|
biop('or2','|',1,'bitwise I of two ndarrays',GenericTypes => $T, |
|
300
|
|
|
|
|
|
|
Bitwise => 1); |
|
301
|
|
|
|
|
|
|
biop('and2','&',1,'bitwise I of two ndarrays',GenericTypes => $T, |
|
302
|
|
|
|
|
|
|
Bitwise => 1); |
|
303
|
|
|
|
|
|
|
biop('xor','^',1,'bitwise I of two ndarrays',GenericTypes => $T, |
|
304
|
|
|
|
|
|
|
Bitwise => 1); |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
pp_addpm( |
|
307
|
|
|
|
|
|
|
"=head2 xor2\n\n=for ref\n\nSynonym for L.\n\n=cut\n |
|
308
|
|
|
|
|
|
|
*PDL::xor2 = *xor2 = \\&PDL::xor;" |
|
309
|
|
|
|
|
|
|
); |
|
310
|
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# some standard binary functions |
|
312
|
|
|
|
|
|
|
bifunc('power',['pow','op**'],1,'raise ndarray C<$a> to the power C<$b>',GenericTypes => [@$C, @$F]); |
|
313
|
|
|
|
|
|
|
bifunc('atan2','atan2',0,'elementwise C of two ndarrays',GenericTypes => $F); |
|
314
|
|
|
|
|
|
|
bifunc('modulo',['MOD','op%'],1,'elementwise C operation',unsigned=>1); |
|
315
|
|
|
|
|
|
|
bifunc('spaceship',['SPACE','op<=>'],0,'elementwise "<=>" operation'); |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
# some standard unary functions |
|
318
|
|
|
|
|
|
|
ufunc('bitnot','~',1,'unary bitwise negation',GenericTypes => $T); |
|
319
|
|
|
|
|
|
|
ufunc('sqrt','sqrt',1,'elementwise square root', GenericTypes => $A); # Exception => '$a() < 0'); |
|
320
|
|
|
|
|
|
|
ufunc('sin','sin',1,'the sin function', GenericTypes => $A); |
|
321
|
|
|
|
|
|
|
ufunc('cos','cos',1,'the cos function', GenericTypes => $A); |
|
322
|
|
|
|
|
|
|
ufunc('not','!',1,'the elementwise I operation'); |
|
323
|
|
|
|
|
|
|
ufunc('exp','exp',1,'the exponential function',GenericTypes => [@$C, @$F]); |
|
324
|
|
|
|
|
|
|
ufunc('log','log',1,'the natural logarithm',GenericTypes => [@$C, @$F], Exception => '$a() <= 0'); |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# no export these because clash with Test::Deep (re) or internal (_*abs) |
|
327
|
|
|
|
|
|
|
cfunc('re', 'creal', 1, 0, 'Returns the real part of a complex number.', |
|
328
|
|
|
|
|
|
|
'$complexv() = $b() + I * cimag($complexv());' |
|
329
|
|
|
|
|
|
|
); |
|
330
|
|
|
|
|
|
|
cfunc('im', 'cimag', 1, 0, 'Returns the imaginary part of a complex number.', |
|
331
|
|
|
|
|
|
|
'$complexv() = creal($complexv()) + I * $b();' |
|
332
|
|
|
|
|
|
|
); |
|
333
|
|
|
|
|
|
|
cfunc('_cabs', 'fabs', 1, 0, 'Returns the absolute (length) of a complex number.', undef, |
|
334
|
|
|
|
|
|
|
PMFunc=>'', |
|
335
|
|
|
|
|
|
|
); |
|
336
|
|
|
|
|
|
|
my $rabs_code = ' |
|
337
|
|
|
|
|
|
|
types('.join('', @$U).') %{ $b()=$a(); %} |
|
338
|
|
|
|
|
|
|
types('.join('', @$S).') %{ $b()=PDL_ABS($a()); %} |
|
339
|
|
|
|
|
|
|
'; |
|
340
|
|
|
|
|
|
|
pp_def ( '_rabs', |
|
341
|
|
|
|
|
|
|
Pars=>'a(); [o]b()', |
|
342
|
|
|
|
|
|
|
HandleBad => 1, |
|
343
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
344
|
|
|
|
|
|
|
Inplace => 1, |
|
345
|
|
|
|
|
|
|
NoExport => 1, |
|
346
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__-1, qq{ |
|
347
|
|
|
|
|
|
|
PDL_IF_BAD(if ( \$ISBAD(a()) ) \$SETBAD(b()); else,) |
|
348
|
|
|
|
|
|
|
$rabs_code |
|
349
|
|
|
|
|
|
|
}), |
|
350
|
|
|
|
|
|
|
Doc=>undef, |
|
351
|
|
|
|
|
|
|
PMFunc=>'', |
|
352
|
|
|
|
|
|
|
); |
|
353
|
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# make log10() work on scalars (returning scalars) |
|
355
|
|
|
|
|
|
|
# as well as ndarrays |
|
356
|
|
|
|
|
|
|
ufunc('log10','log10',0,'the base 10 logarithm', GenericTypes => $A, |
|
357
|
|
|
|
|
|
|
Exception => '$a() <= 0', |
|
358
|
|
|
|
|
|
|
NoTgmath => 1, # glibc for at least GCC 8.3.0 won't tgmath log10 though 7.1.0 did |
|
359
|
|
|
|
|
|
|
NoExport => 0, |
|
360
|
|
|
|
|
|
|
PMCode => <<'EOF', |
|
361
|
|
|
|
|
|
|
sub PDL::log10 { |
|
362
|
|
|
|
|
|
|
my ($x, $y) = @_; |
|
363
|
|
|
|
|
|
|
return log($x) / log(10) if !UNIVERSAL::isa($x,"PDL"); |
|
364
|
|
|
|
|
|
|
barf "inplace but output given" if $x->is_inplace and defined $y; |
|
365
|
|
|
|
|
|
|
if ($x->is_inplace) { $x->set_inplace(0); $y = $x; } |
|
366
|
|
|
|
|
|
|
elsif (!defined $y) { $y = $x->initialize; } |
|
367
|
|
|
|
|
|
|
&PDL::_log10_int( $x, $y ); |
|
368
|
|
|
|
|
|
|
$y; |
|
369
|
|
|
|
|
|
|
}; |
|
370
|
|
|
|
|
|
|
EOF |
|
371
|
|
|
|
|
|
|
); |
|
372
|
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
pp_def( |
|
374
|
|
|
|
|
|
|
'assgn', |
|
375
|
|
|
|
|
|
|
HandleBad => 1, |
|
376
|
|
|
|
|
|
|
GenericTypes => $A, |
|
377
|
|
|
|
|
|
|
Pars => 'a(); [o]b();', |
|
378
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__-1, q{ |
|
379
|
|
|
|
|
|
|
PDL_IF_BAD(char anybad = 0;,) |
|
380
|
|
|
|
|
|
|
broadcastloop %{ |
|
381
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a())) { anybad = 1; $SETBAD(b()); continue; },) |
|
382
|
|
|
|
|
|
|
$b() = $a(); |
|
383
|
|
|
|
|
|
|
%} |
|
384
|
|
|
|
|
|
|
PDL_IF_BAD(if (anybad) $PDLSTATESETBAD(b);,) |
|
385
|
|
|
|
|
|
|
}), |
|
386
|
|
|
|
|
|
|
Doc => |
|
387
|
|
|
|
|
|
|
'Plain numerical assignment. This is used to implement the ".=" operator', |
|
388
|
|
|
|
|
|
|
); |
|
389
|
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# special functions for complex data types that don't work well with |
|
391
|
|
|
|
|
|
|
# the ufunc/bifunc logic |
|
392
|
|
|
|
|
|
|
sub cfunc { |
|
393
|
|
|
|
|
|
|
my ($name, $func, $make_real, $force_complex, $doc, $backcode, %extra) = @_; |
|
394
|
|
|
|
|
|
|
my $codestr = pp_line_numbers(__LINE__-1,"\$b() = $func(\$complexv());"); |
|
395
|
|
|
|
|
|
|
pp_def($name, |
|
396
|
|
|
|
|
|
|
GenericTypes=>$C, |
|
397
|
|
|
|
|
|
|
Pars => ($force_complex ? '!real ' : '').'complexv(); '.($make_real ? 'real' : '').' [o]b()', |
|
398
|
|
|
|
|
|
|
HandleBad => 1, |
|
399
|
|
|
|
|
|
|
NoBadifNaN => 1, |
|
400
|
|
|
|
|
|
|
(($make_real || $force_complex) ? () : (Inplace => 1)), |
|
401
|
|
|
|
|
|
|
NoExport => 1, |
|
402
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__-1, qq{ |
|
403
|
|
|
|
|
|
|
PDL_IF_BAD(if ( \$ISBAD(complexv()) ) \$SETBAD(b()); else,) |
|
404
|
|
|
|
|
|
|
$codestr |
|
405
|
|
|
|
|
|
|
}), |
|
406
|
|
|
|
|
|
|
!$backcode ? () : ( |
|
407
|
|
|
|
|
|
|
DefaultFlow => 1, |
|
408
|
|
|
|
|
|
|
TwoWay => 1, |
|
409
|
|
|
|
|
|
|
BackCode => pp_line_numbers(__LINE__-1, qq{ |
|
410
|
|
|
|
|
|
|
PDL_IF_BAD(if ( \$ISBAD(b()) ) \$SETBAD(complexv()); else {,) |
|
411
|
|
|
|
|
|
|
$backcode |
|
412
|
|
|
|
|
|
|
PDL_IF_BAD(},) |
|
413
|
|
|
|
|
|
|
}), |
|
414
|
|
|
|
|
|
|
), |
|
415
|
|
|
|
|
|
|
%extra, |
|
416
|
|
|
|
|
|
|
Doc => $doc . (!$backcode ? '' : ' Flows data back & forth.'), |
|
417
|
|
|
|
|
|
|
); |
|
418
|
|
|
|
|
|
|
} |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
cfunc('carg', 'carg', 1, 1, 'Returns the polar angle of a complex number.', undef, NoExport => 0); |
|
421
|
|
|
|
|
|
|
cfunc('conj', 'conj', 0, 0, 'complex conjugate.', undef, NoExport => 0); |
|
422
|
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
pp_def('czip', |
|
424
|
|
|
|
|
|
|
Pars => '!complex r(); !complex i(); complex [o]c()', |
|
425
|
|
|
|
|
|
|
Doc => <<'EOF', |
|
426
|
|
|
|
|
|
|
convert real, imaginary to native complex, (sort of) like LISP zip |
|
427
|
|
|
|
|
|
|
function. Will add the C ndarray to "i" times the C ndarray. Only |
|
428
|
|
|
|
|
|
|
takes real ndarrays as input. |
|
429
|
|
|
|
|
|
|
EOF |
|
430
|
|
|
|
|
|
|
Code => '$c() = $r() + $i() * I;' |
|
431
|
|
|
|
|
|
|
); |
|
432
|
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
pp_def('ipow', |
|
434
|
|
|
|
|
|
|
Inplace => [qw(a ans)], |
|
435
|
|
|
|
|
|
|
Doc => qq{ |
|
436
|
|
|
|
|
|
|
=for ref |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
raise ndarray C<\$a> to integer power C<\$b> |
|
439
|
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
Algorithm from L |
|
441
|
|
|
|
|
|
|
}, |
|
442
|
|
|
|
|
|
|
Pars => 'a(); longlong b(); [o] ans()', |
|
443
|
|
|
|
|
|
|
GenericTypes => [qw(P Q), @$AF], |
|
444
|
|
|
|
|
|
|
Code => pp_line_numbers(__LINE__-1, q{ |
|
445
|
3294
|
|
|
|
|
30674
|
$GENERIC(b) n = $b(); |
|
446
|
3294
|
50
|
|
|
|
132
|
if (n == 0) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
447
|
1480
|
|
|
|
|
2966
|
$ans() = 1; |
|
448
|
1480
|
|
|
|
|
381
|
continue; |
|
449
|
|
|
|
|
|
|
} |
|
450
|
1884
|
|
|
|
|
138
|
$GENERIC() y = 1; |
|
451
|
1884
|
|
|
|
|
111894
|
$GENERIC() x = $a(); |
|
452
|
1884
|
0
|
|
|
|
597
|
if (n < 0) { |
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
453
|
70
|
|
|
|
|
143
|
x = 1 / x; |
|
454
|
70
|
|
|
|
|
346
|
n = -n; |
|
455
|
|
|
|
|
|
|
} |
|
456
|
8310
|
0
|
|
|
|
32273
|
while (n > 1) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
457
|
6496
|
0
|
|
|
|
556653
|
if (n % 2) { |
|
|
|
100
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
458
|
5833
|
|
|
|
|
24162
|
y *= x; |
|
459
|
426
|
|
|
|
|
328
|
n -= 1; |
|
460
|
|
|
|
|
|
|
} |
|
461
|
1070
|
|
|
|
|
7780
|
x *= x; |
|
462
|
968
|
|
|
|
|
0
|
n /= 2; |
|
463
|
|
|
|
|
|
|
} |
|
464
|
2082
|
|
|
|
|
1464
|
$ans() = x * y; |
|
465
|
|
|
|
|
|
|
}) |
|
466
|
|
|
|
|
|
|
); |
|
467
|
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
pp_addpm(<<'EOPM'); |
|
469
|
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=head2 abs |
|
471
|
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=for ref |
|
473
|
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
Returns the absolute value of a number. |
|
475
|
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
=cut |
|
477
|
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
sub PDL::abs { $_[0]->type->real ? goto &PDL::_rabs : goto &PDL::_cabs } |
|
479
|
|
|
|
|
|
|
EOPM |
|
480
|
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
pp_def('abs2', |
|
482
|
|
|
|
|
|
|
GenericTypes=>$A, |
|
483
|
|
|
|
|
|
|
HandleBad => 1, |
|
484
|
|
|
|
|
|
|
Pars => 'a(); real [o]b()', |
|
485
|
|
|
|
|
|
|
Doc => 'Returns the square of the absolute value of a number.', |
|
486
|
|
|
|
|
|
|
Code => <<'EOF', |
|
487
|
|
|
|
|
|
|
PDL_IF_BAD(if ($ISBAD(a())) { $SETBAD(b()); continue; },) |
|
488
|
|
|
|
|
|
|
$b() = PDL_IF_GENTYPE_REAL( |
|
489
|
|
|
|
|
|
|
$a()*$a(), |
|
490
|
|
|
|
|
|
|
creall($a())*creall($a()) + cimagl($a())*cimagl($a()) |
|
491
|
|
|
|
|
|
|
); |
|
492
|
|
|
|
|
|
|
EOF |
|
493
|
|
|
|
|
|
|
); |
|
494
|
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
pp_def('r2C', |
|
496
|
|
|
|
|
|
|
GenericTypes=>$AF, |
|
497
|
|
|
|
|
|
|
Pars => 'r(); complex [o]c()', |
|
498
|
|
|
|
|
|
|
Doc => 'convert real to native complex, with an imaginary part of zero', |
|
499
|
|
|
|
|
|
|
PMCode => << 'EOF', |
|
500
|
|
|
|
|
|
|
sub PDL::r2C ($) { |
|
501
|
|
|
|
|
|
|
return $_[0] if UNIVERSAL::isa($_[0], 'PDL') and !$_[0]->type->real; |
|
502
|
|
|
|
|
|
|
my $r = $_[1] // PDL->nullcreate($_[0]); |
|
503
|
|
|
|
|
|
|
PDL::_r2C_int($_[0], $r); |
|
504
|
|
|
|
|
|
|
$r; |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
EOF |
|
507
|
|
|
|
|
|
|
Code => '$c() = $r();' |
|
508
|
|
|
|
|
|
|
); |
|
509
|
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
pp_def('i2C', |
|
511
|
|
|
|
|
|
|
GenericTypes=>$AF, |
|
512
|
|
|
|
|
|
|
Pars => 'i(); complex [o]c()', |
|
513
|
|
|
|
|
|
|
Doc => 'convert imaginary to native complex, with a real part of zero', |
|
514
|
|
|
|
|
|
|
PMCode => << 'EOF', |
|
515
|
|
|
|
|
|
|
sub PDL::i2C ($) { |
|
516
|
|
|
|
|
|
|
return $_[0] if UNIVERSAL::isa($_[0], 'PDL') and !$_[0]->type->real; |
|
517
|
|
|
|
|
|
|
my $r = $_[1] // PDL->nullcreate($_[0]); |
|
518
|
|
|
|
|
|
|
PDL::_i2C_int($_[0], $r); |
|
519
|
|
|
|
|
|
|
$r; |
|
520
|
|
|
|
|
|
|
} |
|
521
|
|
|
|
|
|
|
EOF |
|
522
|
|
|
|
|
|
|
Code => '$c() = $i() * I;' |
|
523
|
|
|
|
|
|
|
); |
|
524
|
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
pp_addpm(<<'EOF'); |
|
526
|
|
|
|
|
|
|
# This is to used warn if an operand is non-numeric or non-PDL. |
|
527
|
|
|
|
|
|
|
sub warn_non_numeric_op_wrapper { |
|
528
|
|
|
|
|
|
|
require Scalar::Util; |
|
529
|
|
|
|
|
|
|
my ($cb, $op_name) = @_; |
|
530
|
|
|
|
|
|
|
return sub { |
|
531
|
|
|
|
|
|
|
my ($op1, $op2) = @_; |
|
532
|
|
|
|
|
|
|
warn "'$op2' is not numeric nor a PDL in operator $op_name" |
|
533
|
|
|
|
|
|
|
unless Scalar::Util::looks_like_number($op2) |
|
534
|
|
|
|
|
|
|
|| ( Scalar::Util::blessed($op2) && $op2->isa('PDL') ); |
|
535
|
|
|
|
|
|
|
$cb->(@_); |
|
536
|
|
|
|
|
|
|
} |
|
537
|
|
|
|
|
|
|
} |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
{ package # hide from MetaCPAN |
|
540
|
|
|
|
|
|
|
PDL; |
|
541
|
|
|
|
|
|
|
use overload |
|
542
|
|
|
|
|
|
|
"eq" => PDL::Ops::warn_non_numeric_op_wrapper(\&PDL::eq, 'eq'), |
|
543
|
|
|
|
|
|
|
".=" => sub { |
|
544
|
|
|
|
|
|
|
my @args = !$_[2] ? @_[1,0] : @_[0,1]; |
|
545
|
|
|
|
|
|
|
PDL::Ops::assgn(@args); |
|
546
|
|
|
|
|
|
|
return $args[1]; |
|
547
|
|
|
|
|
|
|
}, |
|
548
|
|
|
|
|
|
|
'abs' => sub { PDL::abs($_[0]) }, |
|
549
|
|
|
|
|
|
|
'++' => sub { $_[0] += ($PDL::Core::pdl_ones[$_[0]->get_datatype]//barf "Couldn't find 'one' for type ", $_[0]->get_datatype) }, |
|
550
|
|
|
|
|
|
|
'--' => sub { $_[0] -= ($PDL::Core::pdl_ones[$_[0]->get_datatype]//barf "Couldn't find 'one' for type ", $_[0]->get_datatype) }, |
|
551
|
|
|
|
|
|
|
; |
|
552
|
|
|
|
|
|
|
} |
|
553
|
|
|
|
|
|
|
EOF |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
pp_done(); |