vnl_na.cxx
Go to the documentation of this file.
1 // This is core/vnl/vnl_na.cxx
2 //:
3 // \file
4 
5 #include <istream>
6 #include <sstream>
7 #include <cctype>
8 #include "vnl_na.h"
9 
10 #include <vxl_config.h>
11 #include <vnl/vnl_math.h>
12 
13 //: A particular qNaN to indicate not available.
14 // This returns the bit pattern 0x7ff00000000007a2, as used by Octave and R
15 // Don't assume that any VXL functions will treat the value as NA rather than NaN, unless
16 // explicitly documented.
17 double vnl_na(double)
18 {
19  double a;
20 
21 #if VXL_HAS_INT_64
22  *reinterpret_cast<vxl_uint_64*>(&a) = 0x7ff00000000007a2LL;
23 #else
24 # if VXL_BIG_ENDIAN
25 # define hw 0
26 # define lw 1
27 # else // VXL_LITTLE_ENDIAN
28 # define hw 1
29 # define lw 0
30 # endif
31  reinterpret_cast<vxl_uint_32*>(&a)[hw]=0x7ff00000;
32  reinterpret_cast<vxl_uint_32*>(&a)[lw]=0x000007a2;
33 #endif
34 
35  return a;
36 }
37 
38 
39 //: A particular qNaN to indicate not available.
40 // This returns the bit pattern 0x7f8007a2
41 // Don't assume that any VXL functions will treat the value as NA rather than NaN, unless
42 // explicitly documented.
43 float vnl_na(float)
44 {
45  float a;
46 
47  *reinterpret_cast<vxl_uint_32*>(&a) = 0x7f8007a2L;
48 
49  return a;
50 }
51 
52 //: True if parameter is specific NA qNaN.
53 // Tests for bit pattern 0x7ff00000000007a2, as used by Octave and R
54 bool vnl_na_isna(double x)
55 {
56 #if VXL_HAS_INT_64
57  return ((*reinterpret_cast<vxl_uint_64*>(&x))&0xfff7ffffffffffffLL) // ignore signalling bit
58  == 0x7ff00000000007a2LL;
59 #else
60  return ((reinterpret_cast<vxl_int_32*>(&x)[hw]) & 0xfff7ffff) == 0x7ff00000 &&
61  reinterpret_cast<vxl_int_32*>(&x)[lw] == 0x000007a2;
62 #endif
63 }
64 
65 //: True if parameter is specific NA qNaN.
66 // Tests for bit pattern 0x7F8007a2
67 bool vnl_na_isna(float x)
68 {
69  return ((*reinterpret_cast<vxl_uint_32*>(&x))&0xffbfffffL) // ignore signalling bit
70  == 0x7f8007a2L;
71 }
72 
73 
74 //: Replace NaNs with NA, leave other values alone.
75 double vnl_na_nan_to_na(double v)
76 {
77  return vnl_math::isnan(v) ? vnl_na(double()) : v;
78 }
79 
80 //: Replace NaNs with NA, leave other values alone.
81 float vnl_na_nan_to_na(float v)
82 {
83  return vnl_math::isnan(v) ? vnl_na(float()) : v;
84 }
85 
86 //: Read a floating point number or "NA" from a stream.
87 template <class T> inline void vnl_na_extract_type(std::istream &is, T& value)
88 {
89  if (!is) return;
90  std::stringstream oneToken("");
91  unsigned int char_processed_count = 0;
92  bool period_found = false;
93  bool current_location_is_delimiter = false;
94 
95  while (!is.eof()) {
96  std::stringstream::char_type c;
97  std::istream::int_type p = is.peek();
98  if ( char_processed_count == 0 ) { //The first character is the start of the token of interest.
99  if (std::isspace(p)) {
100  is.get(c); // Gobble up the peeked at character
101  continue; //Gobble up preceeding white space
102  }
103  if ( p == 'N' || p == 'n' ) {
104  is.get(c);// Gobble up the N
105  p = is.peek();
106  if (p == 'A' || p == 'a') {
107  is.get(c); // Gobble up the A
108  value = vnl_na(T());
109  return;
110  }
111  else
112  {
113  std::string checkForNAString;
114  is >> checkForNAString; //Gobble up the rest of the token, whatever that is
115  value = 999.999; // Invalid parsing occured
116  return;
117  }
118  }
119  }
120  // Find if character is candidate for float values
121  if (std::isdigit(p) || p == '-' || p == '+' || p == '.') {
122  // After the first character, sign character is delimiter
123  if ((char_processed_count != 0) && ((p == '-') || (p == '+'))) {
124  current_location_is_delimiter = true;
125  }
126  if (p == '.') {
127  if (period_found) //Second period encountered is a delimiter
128  {
129  current_location_is_delimiter = true;
130  }
131  period_found = true;
132  }
133  }
134  else // All other characters are delimiters
135  {
136  current_location_is_delimiter = true;
137  }
138  if ( current_location_is_delimiter) {
139  break;
140  }
141  else {
142  std::stringstream::char_type pp=' ';
143  is.get(pp); //Gobble up peeked character
144  oneToken << pp;
145  }
146  ++char_processed_count;
147  }
148  oneToken >> value;
149 }
150 
151 void vnl_na_extract(std::istream &is, double& x) { vnl_na_extract_type(is, x); }
152 void vnl_na_extract(std::istream &is, float& x) { vnl_na_extract_type(is, x); }
153 
154 //: Write a floating point number or "NA" to a stream.
155 void vnl_na_insert(std::ostream &os, double x)
156 {
157  if (vnl_na_isna(x))
158  os << "NA";
159  else
160  os << x;
161 }
162 
163 //: Write a floating point number or "NA" to a stream.
164 void vnl_na_insert(std::ostream &os, float x)
165 {
166  if (vnl_na_isna(x))
167  os << "NA";
168  else
169  os << x;
170 }
171 //----------------------------------------------------------------------
void vnl_na_extract(std::istream &is, double &x)
Definition: vnl_na.cxx:151
void vnl_na_insert(std::ostream &os, double x)
Write a floating point number or "NA" to a stream.
Definition: vnl_na.cxx:155
Namespace with standard math functions.
NA (Not Available) is a particular double (or single-precision) NaN to represent missing data.
#define v
Definition: vnl_vector.h:42
bool isnan(vnl_bignum const &)
Definition: vnl_bignum.h:435
double vnl_na_nan_to_na(double v)
Replace NaNs with NA, leave other values alone.
Definition: vnl_na.cxx:75
bool vnl_na_isna(double x)
True if parameter is specific NA qNaN.
Definition: vnl_na.cxx:54
void vnl_na_extract_type(std::istream &is, T &value)
Read a floating point number or "NA" from a stream.
Definition: vnl_na.cxx:87
double vnl_na(double)
A particular qNaN to indicate not available.
Definition: vnl_na.cxx:17