File Coverage

lib/PDL/Bad.pd
Criterion Covered Total %
statement 41 46 89.1
branch 6 14 42.8
condition 7 9 77.7
subroutine 10 10 100.0
pod 0 6 0.0
total 64 85 75.2


line stmt bran cond sub pod time code
1             use strict;
2             use warnings;
3              
4             use PDL::Types qw(ppdefs_all types);
5             my $A = [ppdefs_all()];
6             my $AF = [map $_->ppsym, grep !$_->integer, types()]; # all including complex
7             $AF = [(grep $_ ne 'D', @$AF), 'D']; # so defaults to D if non-float given
8              
9             #########################################################
10              
11             pp_addhdr('
12             #include
13             ');
14              
15             pp_add_exported( '',
16             'badflag check_badflag badvalue orig_badvalue nbad nbadover ngood ngoodover ' .
17             'setbadat ' );
18              
19             ## Header
20             pp_addpm({At=>'Top'},<<'!NO!SUBS!');
21              
22             =head1 NAME
23              
24             PDL::Bad - PDL always processes bad values
25              
26             =head1 DESCRIPTION
27              
28             This module is loaded when you do C,
29             C or C.
30              
31             Implementation details are given in
32             L.
33              
34             =head1 SYNOPSIS
35              
36             use PDL::Bad;
37             print "\nBad value per PDL support in PDL is turned " .
38             $PDL::Bad::PerPdl ? "on" : "off" . ".\n";
39              
40             =head1 VARIABLES
41              
42             =over 4
43              
44             =item $PDL::Bad::UseNaN
45              
46             Set to 0 as of PDL 2.040, as no longer available, though NaN can be used
47             as a badvalue for a given PDL object.
48              
49             =item $PDL::Bad::PerPdl
50              
51             Set to 1 as of PDL 2.040 as always available.
52              
53             =item $PDL::Bad::Status
54              
55             Set to 1 as of PDL 2.035 as always available.
56              
57             =back
58              
59             =cut
60              
61             !NO!SUBS!
62              
63             pp_addpm(<<'!NO!SUBS!');
64              
65             $PDL::Bad::Status = 1;
66             $PDL::Bad::UseNaN = 0;
67             $PDL::Bad::PerPdl = 1;
68 70     70   591  
  70         144  
  70         2708  
69             use strict;
70 70     70   363  
  70         102  
  70         12059  
71 70     70   478 use PDL::Types;
  70         166  
  70         677  
72             use PDL::Primitive;
73              
74             ############################################################
75             ############################################################
76              
77             !NO!SUBS!
78              
79             pp_addpm(<<'!NO!SUBS!');
80             ############################################################
81             ############################################################
82              
83             *badflag = \&PDL::badflag;
84             *badvalue = \&PDL::badvalue;
85             *orig_badvalue = \&PDL::orig_badvalue;
86              
87             ############################################################
88             ############################################################
89              
90             =head2 badflag
91              
92             =for ref
93              
94             getter/setter for the bad data flag
95              
96             =for example
97              
98             if ( $x->badflag() ) {
99             print "Data may contain bad values.\n";
100             }
101             $x->badflag(1); # set bad data flag
102             $x->badflag(0); # unset bad data flag
103              
104             When called as a setter, this modifies the ndarray on which
105             it is called. This always returns a Perl scalar with the
106             final value of the bad flag.
107              
108             A return value of 1 does not guarantee the presence of
109             bad data in an ndarray; all it does is say that we need to
110             I for the presence of such beasties. To actually
111             find out if there are any bad values present in an ndarray,
112             use the L method.
113              
114             =for bad
115              
116             This function works with ndarrays that have bad values. It
117             always returns a Perl scalar, so it never returns bad values.
118              
119             =head2 badvalue
120              
121             =for ref
122              
123             returns (or sets) the value used to indicate a missing (or bad) element
124             for the given ndarray type. You can give it an ndarray,
125             a PDL::Type object, or one of C<$PDL_B>, C<$PDL_S>, etc.
126              
127             =for example
128              
129             $badval = badvalue( float );
130             $x = ones(ushort,10);
131             print "The bad data value for ushort is: ",
132             $x->badvalue(), "\n";
133              
134             This can act as a setter (e.g. C<< $x->badvalue(23) >>),
135             including with the value C for floating-point types.
136             Note that this B for
137             floating-point-typed ndarrays.
138             That is, if C<$x> already has bad values, they will not
139             be changed to use the given number and if any elements of
140             C<$x> have that value, they will unceremoniously be marked
141             as bad data. See L, L, and
142             L for ways to actually modify the data in ndarrays
143              
144             It I change data for integer-typed arrays, changing values that
145             had the old bad value to have the new one.
146              
147             It is possible to change the bad value on a per-ndarray basis, so
148              
149             $x = sequence (10);
150             $x->badvalue (3); $x->badflag (1);
151             $y = sequence (10);
152             $y->badvalue (4); $y->badflag (1);
153              
154             will set $x to be C<[0 1 2 BAD 4 5 6 7 8 9]> and $y to be
155             C<[0 1 2 3 BAD 5 6 7 8 9]>.
156              
157             =for bad
158              
159             This method does not care if you call it on an input ndarray
160             that has bad values. It always returns an ndarray
161             with the current or new bad value.
162              
163             =cut
164              
165 107     107 0 32842 sub PDL::badvalue {
166 107         359 my ( $self, $val ) = @_;
167 107 50       452 my $num;
    0          
168 107         302 if ( UNIVERSAL::isa($self,"PDL") ) {
169 107 100 100     450 $num = $self->get_datatype;
      100        
170 5         206 if ( $num < $PDL_F && defined($val) && $self->badflag ) {
171 5         24 $self->inplace->setbadtoval( $val );
172             $self->badflag(1);
173 107         2351 }
174             return PDL::Bad::_badvalue_per_pdl_int($self, $val, $num);
175 0         0 } elsif ( UNIVERSAL::isa($self,"PDL::Type") ) {
176             $num = $self->enum;
177             } else {
178 0         0 # assume it's a number
179             $num = $self;
180 0         0 }
181             PDL::Bad::_badvalue_int( $val, $num );
182             }
183              
184             =head2 orig_badvalue
185              
186             =for ref
187              
188             returns the original value used to represent bad values for
189             a given type.
190              
191             This routine operates the same as L,
192             except you can not change the values.
193              
194             It also has an I name.
195              
196             =for example
197              
198             $orig_badval = orig_badvalue( float );
199             $x = ones(ushort,10);
200             print "The original bad data value for ushort is: ",
201             $x->orig_badvalue(), "\n";
202              
203             =for bad
204              
205             This method does not care if you call it on an input ndarray
206             that has bad values. It always returns an ndarray
207             with the original bad value for the associated type.
208              
209             =cut
210              
211 70     70   569 sub PDL::orig_badvalue {
  70         153  
  70         56030  
212 28     28 0 76 no strict 'refs';
213 28         34 my $self = shift;
214 28 50       102 my $num;
    0          
215 28         77 if ( UNIVERSAL::isa($self,"PDL") ) {
216             $num = $self->get_datatype;
217 0         0 } elsif ( UNIVERSAL::isa($self,"PDL::Type") ) {
218             $num = $self->enum;
219             } else {
220 0         0 # assume it's a number
221             $num = $self;
222 28         403 }
223             PDL::Bad::_default_badvalue_int($num);
224             }
225              
226             =head2 check_badflag
227              
228             =for ref
229              
230             Clear the badflag of an ndarray if it does not
231             contain any bad values
232              
233             Given an ndarray whose bad flag is set, check whether it
234             actually contains any bad values and, if not, clear the flag.
235             It returns the final state of the badflag.
236              
237             =for example
238              
239             print "State of bad flag == ", $pdl->check_badflag;
240              
241             =for bad
242              
243             This method accepts ndarrays with or without bad values. It
244             returns an ndarray with the final badflag.
245              
246             =cut
247              
248             *check_badflag = \&PDL::check_badflag;
249              
250 1     1 0 12 sub PDL::check_badflag {
251 1 50 33     10 my $pdl = shift;
252 1         16 $pdl->badflag(0) if $pdl->badflag and $pdl->nbad == 0;
253             return $pdl->badflag;
254             } # sub: check_badflag()
255              
256             !NO!SUBS!
257              
258             pp_addxs(<<'EOF');
259             pdl *
260             _badvalue_int(val, type)
261             PDL_Anyval val
262             int type
263             CODE:
264             if ( val.type != -1 ) {
265             #define X_OUTER(datatype, ctype, ppsym, ...) \
266             ctype cnewval = val.value.ppsym;
267             #define X_INNER(datatype, ctype, ppsym, ...) \
268             PDL->bvals.ppsym = cnewval;
269             PDL_GENERICSWITCH2(
270             PDL_TYPELIST_ALL, val.type, X_OUTER, croak("Not a known data type code=%d", val.type),
271             PDL_TYPELIST_ALL_, type, X_INNER, croak("Not a known data type code=%d", type))
272             #undef X_OUTER
273             #undef X_INNER
274             }
275             PDL_Anyval newval = {type, {0}};
276             pdl* p = PDL->scalar(newval);
277             if (!p) PDL->pdl_barf("Error making new pdl");
278             #define X(datatype, ctype, ppsym, ...) \
279             *((ctype *)p->data) = PDL->bvals.ppsym;
280             PDL_GENERICSWITCH(PDL_TYPELIST_ALL, type, X, croak("Not a known data type code=%d", type))
281             #undef X
282             RETVAL = p;
283             OUTPUT:
284             RETVAL
285              
286             pdl *
287             _badvalue_per_pdl_int(pdl_val, val, type)
288             pdl* pdl_val
289             PDL_Anyval val
290             int type
291             CODE:
292             if ( val.type != -1) {
293             PDL_Anyval typedval;
294             ANYVAL_TO_ANYVAL_NEWTYPE(val, typedval, pdl_val->datatype);
295             if (typedval.type < 0) PDL->pdl_barf("Error making typedval");
296             #define X(datatype, ctype, ppsym, ...) \
297             pdl_val->badvalue.type = typedval.type; \
298             pdl_val->badvalue.value.ppsym = typedval.value.ppsym;
299             PDL_GENERICSWITCH(PDL_TYPELIST_ALL, pdl_val->datatype, X, croak("Not a known data type code=%d", type))
300             #undef X
301             pdl_val->has_badvalue = 1;
302             PDL->propagate_badvalue( pdl_val );
303             }
304             PDL_Anyval newval = {type, {0}};
305             pdl* p = PDL->scalar(newval);
306             if (!p) PDL->pdl_barf("Error making new pdl");
307             if (pdl_val->has_badvalue == 0) {
308             #define X(datatype, ctype, ppsym, ...) \
309             *((ctype *)p->data) = PDL->bvals.ppsym;
310             PDL_GENERICSWITCH(PDL_TYPELIST_ALL, type, X, croak("Not a known data type code=%d", type))
311             #undef X
312             } else {
313             #define X_OUTER(datatype, ctype, ...) \
314             ctype *coutvalp = p->data;
315             #define X_INNER(datatype, ctype, ppsym, ...) \
316             *coutvalp = pdl_val->badvalue.value.ppsym;
317             PDL_GENERICSWITCH2(
318             PDL_TYPELIST_ALL, type, X_OUTER, croak("Not a known data type code=%d", type),
319             PDL_TYPELIST_ALL_, pdl_val->badvalue.type, X_INNER, croak("Not a known data type code=%d", pdl_val->badvalue.type))
320             #undef X_OUTER
321             #undef X_INNER
322             }
323             RETVAL = p;
324             OUTPUT:
325             RETVAL
326              
327             pdl *
328             _default_badvalue_int(type)
329             int type
330             CODE:
331             PDL_Anyval val = {type, {0}};
332             pdl* p = PDL->scalar(val);
333             if (!p) PDL->pdl_barf("Error making new pdl");
334             #define X(datatype, ctype, ppsym, shortctype, defbval, ...) \
335             *((ctype *)p->data) = defbval;
336             PDL_GENERICSWITCH(PDL_TYPELIST_ALL, type, X, croak("Not a known data type code=%d", type))
337             #undef X
338             RETVAL = p;
339             OUTPUT:
340             RETVAL
341             EOF
342              
343             pp_def('isbad',
344             Pars => q(a(); int [o]b()),
345             Doc => <<'EOF',
346             =for ref
347              
348             Returns a binary mask indicating which values of
349             the input are bad values
350              
351             Returns a 1 if the value is bad, 0 otherwise.
352             Similar to L.
353              
354             =for example
355              
356             $x = pdl(1,2,3);
357             $x->badflag(1);
358             set($x,1,$x->badvalue);
359             $y = isbad($x);
360             print $y, "\n";
361             [0 1 0]
362             EOF
363             BadDoc => <<'EOF',
364             This method works with input ndarrays that are bad. The output ndarray
365             will never contain bad values, but its bad value flag will be the
366             same as the input ndarray's flag.
367             EOF
368             HandleBad => 1,
369             Code => '$b() = PDL_IF_BAD($ISBAD(a()),0);',
370             GenericTypes => $A,
371             );
372              
373             pp_def('isgood',
374             Pars => q(a(); int [o]b()),
375             Doc => <<'EOF',
376             =for ref
377              
378             Is a value good?
379              
380             Returns a 1 if the value is good, 0 otherwise.
381             Also see L.
382              
383             =for example
384              
385             $x = pdl(1,2,3);
386             $x->badflag(1);
387             set($x,1,$x->badvalue);
388             $y = isgood($x);
389             print $y, "\n";
390             [1 0 1]
391             EOF
392             BadDoc => <<'EOF',
393             This method works with input ndarrays that are bad. The output ndarray
394             will never contain bad values, but its bad value flag will be the
395             same as the input ndarray's flag.
396             EOF
397             HandleBad => 1,
398             Code => '$b() = PDL_IF_BAD($ISGOOD(a()),1);',
399             GenericTypes => $A,
400             );
401              
402             # perhaps these should have pm code which returns the
403             # answer if the bad flag is not set
404             pp_def('nbadover',
405             Pars => q(a(n); indx [o] b()),
406             Doc => <<'EOF',
407             =for ref
408              
409             Find the number of bad elements along the 1st dimension.
410              
411             This function reduces the dimensionality of an ndarray by one by finding the
412             number of bad elements along the 1st dimension. In this sense it shares
413             much in common with the functions defined in L. In particular,
414             by using L and similar dimension rearranging methods,
415             it is possible to perform this calculation over I dimension.
416             EOF
417             BadDoc => <<'EOF',
418             nbadover processes input values that are bad. The output ndarray will not have
419             any bad values, but the bad flag will be set if the input ndarray had its bad
420             flag set.
421             EOF
422             HandleBad => 1,
423             Code => q{
424             PDL_Indx cnt = 0;
425             PDL_IF_BAD(loop(n) %{ if ( $ISBAD(a()) ) { cnt++; } %},)
426             $b() = cnt;
427             },
428             GenericTypes => $A,
429             );
430              
431             pp_def('ngoodover',
432             Pars => q(a(n); indx [o] b()),
433             Doc => <<'EOF',
434             =for ref
435              
436             Find the number of good elements along the 1st dimension.
437              
438             This function reduces the dimensionality of an ndarray
439             by one by finding the number of good elements
440             along the 1st dimension.
441              
442             By using L etc. it is possible to use
443             I dimension.
444             EOF
445             BadDoc => <<'EOF',
446             ngoodover processes input values that are bad. The output ndarray will not have
447             any bad values, but the bad flag will be set if the input ndarray had its bad
448             flag set.
449             EOF
450             HandleBad => 1,
451             Code =>
452             'PDL_Indx cnt = PDL_IF_BAD(0,$SIZE(n));
453             PDL_IF_BAD(loop(n) %{ if ( $ISGOOD(a()) ) { cnt++; } %},)
454             $b() = cnt;',
455             GenericTypes => $A,
456             );
457              
458             # Generate small ops functions to do entire array
459             foreach my $op (
460             ['nbad','nbadover'],
461             ['ngood','ngoodover'],
462             ) {
463             pp_addpm(<<"EOD");
464              
465 5     5 0 13 *$op->[0] = \\&PDL::$op->[0];
  5         9  
466 5     3 0 19 sub PDL::$op->[0] {
  3         9  
  3         5  
467 5         30 my(\$x) = \@_; my \$tmp;
  3         12  
468 3         98 \$x->flat->$op->[1](\$tmp=PDL->nullcreate(\$x) );
469             return \$tmp;
470             }
471             EOD
472              
473             } # for $op
474              
475             pp_addpm(<<'!NO!SUBS!');
476              
477             =head2 nbad
478              
479             =for ref
480              
481             Returns the number of bad values in an ndarray
482              
483             =for bad
484              
485             Accepts good and bad input ndarrays; output is an ndarray
486             and is always good.
487              
488             =head2 ngood
489              
490             =for ref
491              
492             Returns the number of good values in an ndarray
493              
494             =for usage
495              
496             $x = ngood($data);
497              
498             =for bad
499              
500             Accepts good and bad input ndarrays; output is an ndarray
501             and is always good.
502              
503             =head2 setbadat
504              
505             =for ref
506              
507             Set the value to bad at a given position.
508              
509             =for usage
510              
511             setbadat $ndarray, @position
512              
513             C<@position> is a coordinate list, of size equal to the
514             number of dimensions in the ndarray.
515             This is a wrapper around L and is
516             probably mainly useful in test scripts!
517              
518             =for example
519              
520             pdl> $x = sequence 3,4
521             pdl> $x->setbadat 2,1
522             pdl> p $x
523             [
524             [ 0 1 2]
525             [ 3 4 BAD]
526             [ 6 7 8]
527             [ 9 10 11]
528             ]
529              
530             =for bad
531              
532             This method can be called on ndarrays that have bad values.
533             The remainder of the arguments should be Perl scalars indicating
534             the position to set as bad. The output ndarray will have bad values
535             and will have its badflag turned on.
536              
537             =cut
538              
539             *setbadat = \&PDL::setbadat;
540 23 50   23 0 191 sub PDL::setbadat {
541 23         46 barf 'Usage: setbadat($pdl, $x, $y, ...)' if $#_<1;
542 23         99 my $self = shift;
543 23         194 PDL::Core::set_c ($self, [@_], $self->badvalue);
544 23         52 $self->badflag(1);
545             return $self;
546             }
547              
548             !NO!SUBS!
549              
550             # NOTE: the Code section uses SETBAD
551             #
552             # have removed inplace stuff because:
553             # $x->inplace->setbadif( $x % 2 )
554             # actually sets the badflag in a for ($x % 2) - this is
555             # done inplace, and the flag cleared. Hence the setbadif()
556             # call is NOT done inplace.
557             #
558             # Don't want to play around with inplace-type code to
559             # try and fix this (doubt will be easy)
560             #
561             my %setbadif_extra = ( );
562             if ( 0 ) {
563             ## ie if fix inplace issues
564             $setbadif_extra{Inplace} = [ 'a' ];
565             } else {
566             }
567             # always make sure the output is "bad"
568              
569             # note: have made the mask be an integer
570             pp_def('setbadif',
571             Pars => q(a(); int mask(); [o]b()),
572             Doc => <<'EOF',
573             =for ref
574              
575             Set elements bad based on the supplied mask, otherwise
576             copy across the data.
577              
578             =for example
579              
580             pdl> $x = sequence(5,5)
581             pdl> $x = $x->setbadif( $x % 2 )
582             pdl> p "a badflag: ", $x->badflag, "\n"
583             a badflag: 1
584             pdl> p "a is\n$x"
585             [
586             [ 0 BAD 2 BAD 4]
587             [BAD 6 BAD 8 BAD]
588             [ 10 BAD 12 BAD 14]
589             [BAD 16 BAD 18 BAD]
590             [ 20 BAD 22 BAD 24]
591             ]
592              
593             Unfortunately, this routine can I be run inplace, since the
594             current implementation can not handle the same ndarray used as
595             C and C (eg C<< $x->inplace->setbadif($x%2) >> fails).
596             Even more unfortunate: we can't catch this error and tell you.
597             EOF
598             BadDoc => <<'EOF',
599             The output always has its bad flag set, even if it does not contain
600             any bad values (use L to check
601             whether there are any bad values in the output).
602             The input ndarray can have bad values: any bad values in the input ndarrays
603             are copied across to the output ndarray.
604              
605             Also see L and L.
606             EOF
607             HandleBad => 1,
608             %setbadif_extra,
609             Code => '
610             broadcastloop %{
611             /* if the bad value == 0 then all points are going to be selected ... */
612             if ( PDL_IF_BAD($ISBAD(mask()) ||,) $mask() ) {
613             $SETBAD(b());
614             } else {
615             $b() = $a();
616             }
617             %}
618             $PDLSTATESETBAD(b);
619             ',
620             GenericTypes => $A,
621             );
622              
623             # this is useful because $x->setbadif( $x == 23 )
624             # is common and that can't be done inplace
625             pp_def('setvaltobad',
626             Pars => q(a(); [o]b()),
627             OtherPars => q(double value),
628             Doc => <<'EOF',
629             =for ref
630              
631             Set bad all those elements which equal the supplied value.
632              
633             =for example
634              
635             $x = sequence(10) % 3;
636             $x->inplace->setvaltobad( 0 );
637             print "$x\n";
638             [BAD 1 2 BAD 1 2 BAD 1 2 BAD]
639              
640             This is a simpler version of L, but this
641             function can be done inplace. See L
642             if you want to convert NaN to the bad value.
643             EOF
644             BadDoc => <<'EOF',
645             The output always has its bad flag set, even if it does not contain
646             any bad values (use L to check
647             whether there are any bad values in the output).
648             Any bad values in the input ndarrays are copied across to the output ndarray.
649             EOF
650             HandleBad => 1,
651             Inplace => 1,
652             Code => q[
653             broadcastloop %{
654             if ( $a() == ($GENERIC(a)) $COMP(value) ) {
655             $SETBAD(b());
656             } else {
657             $b() = $a();
658             }
659             %}
660             $PDLSTATESETBAD(b);
661             ],
662             GenericTypes => $A,
663             );
664              
665             pp_def('setnantobad',
666             Pars => q(a(); [o]b()),
667             Doc => <<'EOF',
668             =for ref
669              
670             Sets NaN values (for complex, where either is NaN) in the input ndarray bad
671             (only relevant for floating-point ndarrays).
672             EOF
673             BadDoc => <<'EOF',
674             This method can process ndarrays with bad values: those bad values
675             are propagated into the output ndarray. Any value that is not a number
676             (before version 2.040 the test was for "not finite")
677             is also set to bad in the output ndarray. If all values from the input
678             ndarray are good, the output ndarray will B have its
679             bad flag set.
680             EOF
681             HandleBad => 1,
682             GenericTypes => $AF,
683             Inplace => 1,
684             Code => q[
685             int flag = 0;
686             broadcastloop %{
687             if ( PDL_ISNAN_$PPSYM()($a()) ) {
688             $SETBAD(b());
689             flag = 1;
690             } else {
691             $b() = $a();
692             }
693             %}
694             if ( flag ) $PDLSTATESETBAD(b);
695             ],
696             );
697              
698             pp_def('setinftobad',
699             Pars => q(a(); [o]b()),
700             Doc => <<'EOF',
701             =for ref
702              
703             Sets non-finite values (for complex, where either is non-finite) in
704             the input ndarray bad (only relevant for floating-point ndarrays).
705             EOF
706             BadDoc => <<'EOF',
707             This method can process ndarrays with bad values: those bad values
708             are propagated into the output ndarray. Any value that is not finite
709             is also set to bad in the output ndarray. If all values from the input
710             ndarray are finite, the output ndarray will B have its
711             bad flag set.
712             EOF
713             HandleBad => 1,
714             GenericTypes => $AF,
715             Inplace => 1,
716             Code => q[
717             int flag = 0;
718             broadcastloop %{
719             if ( !PDL_ISFINITE_$PPSYM()($a()) && !PDL_ISNAN_$PPSYM()($a()) ) {
720             $SETBAD(b());
721             flag = 1;
722             }
723             else {
724             $b() = $a();
725             }
726             %}
727             if ( flag ) $PDLSTATESETBAD(b);
728             ],
729             );
730              
731             pp_def('setnonfinitetobad',
732             Pars => q(a(); [o]b()),
733             Doc => <<'EOF',
734             =for ref
735              
736             Sets non-finite values (for complex, where either is non-finite) in
737             the input ndarray bad (only relevant for floating-point ndarrays).
738             EOF
739             BadDoc => <<'EOF',
740             This method can process ndarrays with bad values: those bad values
741             are propagated into the output ndarray. Any value that is not finite
742             is also set to bad in the output ndarray. If all values from the input
743             ndarray are finite, the output ndarray will B have its
744             bad flag set.
745             EOF
746             HandleBad => 1,
747             GenericTypes => $AF,
748             Inplace => 1,
749             Code => q[
750             int flag = 0;
751             broadcastloop %{
752             if ( !PDL_ISFINITE_$PPSYM()($a()) ) {
753             $SETBAD(b());
754             flag = 1;
755             } else {
756             $b() = $a();
757             }
758             %}
759             if ( flag ) $PDLSTATESETBAD(b);
760             ],
761             );
762              
763             pp_def('setbadtonan',
764             Pars => q(a(); [o] b();),
765             Doc => <<'EOF',
766             =for ref
767              
768             Sets Bad values to NaN
769              
770             This is only relevant for floating-point ndarrays. The input ndarray can be
771             of any type, but if done inplace, the input must be floating point.
772             EOF
773             BadDoc => <<'EOF',
774             This method processes input ndarrays with bad values. The output ndarrays will
775             not contain bad values (insofar as NaN is not Bad as far as PDL is concerned)
776             and the output ndarray does not have its bad flag set. As an inplace
777             operation, it clears the bad flag.
778             EOF
779             HandleBad => 1,
780             GenericTypes => $AF,
781             Inplace => 1,
782             Code => q{
783             broadcastloop %{
784             if ( $ISBAD(a()) ) {
785             $b() = $TFDEGCH(NAN,NAN,NAN,NAN+I*NAN,NAN+I*NAN,NAN+I*NAN);
786             } else {
787             $b() = $a();
788             }
789             %}
790             $PDLSTATESETGOOD(b);
791             },
792             );
793              
794             pp_def('setbadtoval',
795             Pars => q(a(); [o]b()),
796             OtherPars => q(double newval),
797             Doc => <<'EOF',
798             =for ref
799              
800             Replace any bad values by a (non-bad) value.
801              
802             Also see L.
803              
804             =for example
805              
806             $x->inplace->setbadtoval(23);
807             print "a badflag: ", $x->badflag, "\n";
808             a badflag: 0
809             EOF
810             BadDoc => <<'EOF',
811             The output always has its bad flag cleared.
812             If the input ndarray does not have its bad flag set, then
813             values are copied with no replacement.
814             EOF
815             HandleBad => 1,
816             Inplace => 1,
817             Code => q{
818             PDL_IF_BAD($GENERIC(b) replace = ($GENERIC(b)) $COMP(newval);,)
819             broadcastloop %{
820             $GENERIC(b) a_val = $a();
821             $b() = PDL_IF_BAD($ISBADVAR(a_val,a) ? replace : ,) a_val;
822             %}
823             $PDLSTATESETGOOD(b); /* always make sure the output is "good" */
824             },
825             GenericTypes => $A,
826             );
827              
828             pp_def('badmask',
829             Pars => 'a(); b(); [o]c();',
830             Inplace => [ 'a' ],
831             HandleBad => 1,
832             Code => '
833             broadcastloop %{
834             $c() = ( isfinite((double) $a()) PDL_IF_BAD(&& $ISGOOD(a()),) ) ? $a() : $b();
835             %}
836             $PDLSTATESETGOOD(c);
837             ',
838             Doc => <<'EOF',
839             =for ref
840              
841             Clears all C and C in C<$a> to the corresponding value in C<$b>.
842             EOF
843             BadDoc => <<'EOF',
844             If bad values are present, these are also cleared.
845             EOF
846             );
847              
848             pp_def('copybad',
849             Pars => q(a(); mask(); [o]b()),
850             Doc => <<'EOF',
851             =for ref
852              
853             Copies values from one ndarray to another, setting them
854             bad if they are bad in the supplied mask.
855              
856             =for example
857              
858             $x = byte( [0,1,3] );
859             $mask = byte( [0,0,0] );
860             $mask->badflag(1);
861             set($mask,1,$mask->badvalue);
862             $x->inplace->copybad( $mask );
863             p $x;
864             [0 BAD 3]
865              
866             It is equivalent to:
867              
868             $c = $x + $mask * 0
869             EOF
870             BadDoc => <<'EOF',
871             This handles input ndarrays that are bad. If either C<$x>
872             or C<$mask> have bad values, those values will be marked
873             as bad in the output ndarray and the output ndarray will have
874             its bad value flag set to true.
875             EOF
876             HandleBad => 1,
877             Inplace => [ 'a' ],
878             Code => q{
879             char anybad = 0;
880             broadcastloop %{
881             PDL_IF_BAD(if ( $ISBAD(mask()) ) {
882             $SETBAD(b());
883             anybad = 1;
884             } else,) {
885             $b() = $a();
886             }
887             %}
888             if (anybad) $PDLSTATESETBAD(b);
889             },
890             GenericTypes => $A,
891             );
892              
893             pp_def('locf',
894             Pars => 'a(n); [o]b(n);',
895             HandleBad => 1,
896             GenericTypes => $A,
897             Doc => <<'EOF',
898             =for ref
899              
900             Last Observation Carried Forward - replace
901             every BAD value with the most recent non-BAD value prior to it.
902             Any leading BADs will be set to 0.
903             EOF
904             Code => q{
905             $GENERIC() tmp = 0;
906             loop(n) %{
907             if ( $ISGOOD(a()) ) tmp = $a();
908             $b() = tmp;
909             %}
910             },
911             );
912              
913             #########################################################
914              
915             pp_addpm({At=>'Bot'},<<'!WITHOUT!SUBS!');
916              
917             =head1 AUTHOR
918              
919             Doug Burke (djburke@cpan.org), 2000, 2001, 2003, 2006.
920              
921             The per-ndarray bad value support is by Heiko Klein (2006).
922              
923             CPAN documentation fixes by David Mertens (2010, 2013).
924              
925             All rights reserved. There is no warranty. You are allowed to
926             redistribute this software / documentation under certain conditions. For
927             details, see the file COPYING in the PDL distribution. If this file is
928             separated from the PDL distribution, the copyright notice should be
929             included in the file.
930              
931             =cut
932              
933             !WITHOUT!SUBS!
934              
935             ## End
936             pp_done();