• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** nonfinite_num_facet.cpp
2 *
3 * Copyright (c) 2011 Paul A. Bristow
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE_1_0.txt
7 * or copy at http://www.boost.org/LICENSE_1_0.txt)
8 *
9 * This very simple program illustrates how to use the
10 * `boost/math/nonfinite_num_facets.hpp' to obtain C99
11 * representation of infinity and NaN.
12 * (from the original
13 * Floating Point  Utilities contribution by Johan Rade.
14 * Floating Point Utility library has been accepted into Boost,
15 * but the utilities are incorporated into Boost.Math library.
16 *
17 \file
18 
19 \brief A very simple example of using non_finite_num facet for
20 C99 standard output of infinity and NaN.
21 
22 \detail Provided infinity and nan are supported,
23 this example shows how to create a C99 non-finite locale,
24 and imbue input and output streams with the non_finite_num put and get facets.
25 This allow output and input of infinity and NaN in a Standard portable way,
26 This permits 'loop-back' of output back into input (and portably across different system too).
27 This is particularly useful when used with Boost.Serialization so that non-finite NaNs and infinity
28 values in text and xml archives can be handled correctly and portably.
29 
30 */
31 
32 #ifdef _MSC_VER
33 #  pragma warning (disable : 4127)  // conditional expression is constant.
34 #endif
35 
36 #include <iostream>
37 using std::cout;
38 using std::endl;
39 using std::cerr;
40 
41 #include <iomanip>
42 using std::setw;
43 using std::left;
44 using std::right;
45 using std::internal;
46 
47 #include <string>
48 using std::string;
49 
50 #include <sstream>
51 using std::istringstream;
52 
53 #include <limits>
54 using std::numeric_limits;
55 
56 #include <locale>
57 using std::locale;
58 
59 #include <boost/math/special_functions/nonfinite_num_facets.hpp>
60 // from Johan Rade Floating Point Utilities.
61 
main()62 int main ()
63 {
64   std::cout << "Nonfinite_num_facet very simple example." << std::endl;
65 
66   if((std::numeric_limits<double>::has_infinity == 0) || (std::numeric_limits<double>::infinity() == 0))
67   {
68     std::cout << "Infinity not supported on this platform." << std::endl;
69     return 0;
70   }
71 
72   if((std::numeric_limits<double>::has_quiet_NaN == 0) || (std::numeric_limits<double>::quiet_NaN() == 0))
73   {
74     std::cout << "NaN not supported on this platform." << std::endl;
75     return 0;
76   }
77 
78   std::locale default_locale (std::locale::classic ()); // Note the current (default C) locale.
79 
80   // Create plus and minus infinity.
81   double plus_infinity = +std::numeric_limits<double>::infinity();
82   double minus_infinity = -std::numeric_limits<double>::infinity();
83 
84   // and create a NaN (NotANumber)
85   double NaN = +std::numeric_limits<double>::quiet_NaN ();
86 
87   double negated_NaN = (boost::math::changesign)(std::numeric_limits<double>::quiet_NaN ());
88 
89 
90   // Output the nonfinite values using the current (default C) locale.
91   // The default representations differ from system to system,
92   // for example, using Microsoft compilers, 1.#INF, -1.#INF, and 1.#QNAN,
93   // Linux "inf", "-inf", "nan"
94   cout << "Using C locale" << endl;
95   cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl;
96   cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl;
97   cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl;
98 
99   // Display negated NaN.
100   cout << "negated NaN " << negated_NaN << endl; // "-1.IND" or "-nan".
101 
102   // Create a new output locale, and add the nonfinite_num_put facet
103   std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>);
104   // and imbue the cout stream with the new locale.
105   cout.imbue (C99_out_locale);
106 
107   // Or for the same effect more concisely:
108   cout.imbue (locale(locale(), new boost::math::nonfinite_num_put<char>));
109 
110   // Output using the new locale:
111   cout << "Using C99_out_locale " << endl;
112   cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl;
113   cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl;
114   cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl;
115   // Expect "inf", "-inf", "nan".
116 
117   // Display negated NaN.
118   cout << "negated NaN " << negated_NaN << endl; // Expect "-nan".
119 
120   // Create a string with the expected C99 representation of plus infinity.
121   std::string inf = "inf";
122   { // Try to read an infinity value using the default C locale.
123     // Create an input stream which will provide "inf"
124     std::istringstream iss (inf);
125 
126      // Create a double ready to take the input,
127     double infinity;
128     // and read "inf" from the stringstream:
129     iss >> infinity;
130 
131     // This will not work on all platforms!  (Intel-Linux-13.0.1 fails EXIT STATUS: 139)
132     if (! iss)
133     { // Reading infinity went wrong!
134       std::cerr << "C locale input format error!" << std::endl;
135     }
136   } // Using default C locale.
137 
138   { // Now retry using C99 facets.
139   // Create a new input locale and add the nonfinite_num_get facet.
140   std::locale C99_in_locale (default_locale, new boost::math::nonfinite_num_get<char>);
141 
142   // Create an input stream which will provide "inf".
143   std::istringstream iss (inf);
144   // Imbue the stream with the C99 input locale.
145   iss.imbue (C99_in_locale);
146 
147   // Create a double ready to take the input,
148   double infinity;
149   // and read from the stringstream:
150   iss >> infinity;
151 
152   if (! iss)
153   { // Reading infinity went wrong!
154     std::cout << "C99 input format error!" << std::endl;
155   }
156   // Expect to get an infinity, which will display still using the C99 locale as "inf"
157   cout << "infinity in C99 representation is " << infinity << endl;
158 
159   // To check, we can switch back to the default C locale.
160   cout.imbue (default_locale);
161   cout <<  "infinity in default C representation is " << infinity << endl;
162   } // using C99 locale.
163 
164   {
165     // A 'loop-back example, output to a stringstream, and reading it back in.
166     // Create C99 input and output locales.
167     std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>);
168     std::locale C99_in_locale (default_locale, new boost::math::nonfinite_num_get<char>);
169 
170     std::ostringstream oss;
171     oss.imbue(C99_out_locale);
172     oss << plus_infinity;
173 
174     std::istringstream iss(oss.str()); // So stream contains "inf".
175     iss.imbue (C99_in_locale);
176 
177     std::string s;
178 
179     iss >> s;
180 
181     cout.imbue(C99_out_locale);
182     if (oss.str() != s)
183     {
184       cout << plus_infinity << " != " << s << " loopback failed!" << endl;
185     }
186     else
187     {
188       cout << plus_infinity << " == " << s << " as expected." << endl;
189     }
190   }
191 
192 
193   // Example varying the width and position of the nonfinite representations.
194   // With the nonfinite_num_put and _get facets, the width of the output is constant.
195 
196   #ifdef BOOST_NO_CXX11_NUMERIC_LIMITS
197   cout << "BOOST_NO_CXX11_NUMERIC_LIMITS is defined, so no max_digits10 available." << endl;
198   std::streamsize  max_digits10 = 2 + std::numeric_limits<double>::digits * 30103UL / 100000UL;
199 #else
200   // Can use new C++0X max_digits10 (the maximum potentially significant digits).
201   std::streamsize  max_digits10 = std::numeric_limits<double>::max_digits10;
202 #endif
203   cout << "std::numeric_limits<double>::max_digits10 is " << max_digits10 << endl;
204   cout.precision(max_digits10);
205 
206   double pi = 3.141592653589793238462643383279502884197169399375105820974944;
207   // Expect 17 (probably) decimal digits (regardless of locale).
208   // cout has the default locale.
209   cout << "pi = " << pi << endl; // pi = 3.1415926535897931
210   cout.imbue (C99_out_locale); // Use cout with the C99 locale
211   // (expect the same output for a double).
212   cout << "pi = " << pi << endl; // pi = 3.1415926535897931
213 
214   cout << "infinity in C99 representation is " << plus_infinity << endl;
215 
216   //int width = 2; // Check effect if width too small is OK.
217   // (There was a disturbed layout on older MSVC?).
218   int width = 20;
219 
220   // Similarly if we can switch back to the default C locale.
221   cout.imbue (default_locale);
222   cout <<  "infinity in default C representation is " << plus_infinity << endl;
223   cout <<  "infinity in default C representation (setw(" << width << ") is |" << setw(width) << plus_infinity <<'|' << endl;
224   cout <<  "infinity in default C representation (setw(" << width << ") is |" << left << setw(width) << plus_infinity <<'|' << endl;
225   cout <<  "infinity in default C representation (setw(" << width << ") is |" << internal << setw(width) << plus_infinity <<'|' << endl;
226 
227   cout.imbue (C99_out_locale);
228   cout << "infinity in C99 representation (setw(" << width << ") is |" << right << setw(width) << plus_infinity <<'|'<< endl;
229   cout << "infinity in C99 representation (setw(" << width << ") is |" << left << setw(width) << plus_infinity <<'|'<< endl;
230   cout << "infinity in C99 representation (setw(" << width << ") is |" << internal << setw(width) << plus_infinity <<'|'<< endl;
231 
232   return 0;
233 } // int main()
234 
235 // end of test_nonfinite_num_facets.cpp
236 
237 /*
238 
239 Output:
240 
241 simple_nonfinite_facet.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\nonfinite_facet_simple.exe
242   Nonfinite_num_facet very simple example.
243   Using C locale
244   +std::numeric_limits<double>::infinity() = 1.#INF
245   -std::numeric_limits<double>::infinity() = -1.#INF
246   +std::numeric_limits<double>::quiet_NaN () = 1.#QNAN
247   Using C99_out_locale
248   +std::numeric_limits<double>::infinity() = inf
249   -std::numeric_limits<double>::infinity() = -inf
250   +std::numeric_limits<double>::quiet_NaN () = nan
251   infinity in C99 representation is inf
252   infinity in default C representation is 1.#INF
253   3
254   3
255   inf == inf as expected.
256   std::numeric_limits<double>::max_digits10 is 17
257   pi = 3.1415926535897931
258   C locale input format error!
259   pi = 3.1415926535897931
260   infinity in C99 representation is inf
261   infinity in default C representation is 1.#INF
262   infinity in default C representation (setw(20) is               1.#INF|
263   infinity in default C representation (setw(20) is 1.#INF              |
264   infinity in default C representation (setw(20) is               1.#INF|
265   infinity in C99 representation (setw(20) is                  inf|
266   infinity in C99 representation (setw(20) is inf                 |
267   infinity in C99 representation (setw(20) is                  inf|
268 
269 */
270