summaryrefslogtreecommitdiff
path: root/libs/math/example/nonfinite_facet_simple.cpp
blob: 3df314a77b67a9e22a773f388670833d42523605 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
/** nonfinite_num_facet.cpp
*
* Copyright (c) 2011 Paul A. Bristow
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt
* or copy at http://www.boost.org/LICENSE_1_0.txt)
*
* This very simple program illustrates how to use the
* `boost/math/nonfinite_num_facets.hpp' to obtain C99
* representation of infinity and NaN.
* (from the original
* Floating Point  Utilities contribution by Johan Rade.
* Floating Point Utility library has been accepted into Boost,
* but the utilities are incorporated into Boost.Math library.
*
\file

\brief A very simple example of using non_finite_num facet for
C99 standard output of infinity and NaN.

\detail Provided infinity and nan are supported,
this example shows how to create a C99 non-finite locale,
and imbue input and output streams with the non_finite_num put and get facets.
This allow output and input of infinity and NaN in a Standard portable way,
This permits 'loop-back' of output back into input (and portably across different system too).
This is particularly useful when used with Boost.Seralization so that non-finite NaNs and infinity
values in text and xml archives can be handled correctly and portably.

*/

#ifdef _MSC_VER
#  pragma warning (disable : 4127)  // conditional expression is constant.
#endif

#include <iostream>
using std::cout;
using std::endl;
using std::cerr;

#include <iomanip>
using std::setw;
using std::left;
using std::right;
using std::internal;

#include <string>
using std::string;

#include <sstream>
using std::istringstream;

#include <limits>
using std::numeric_limits;

#include <locale>
using std::locale;

#include <boost/math/special_functions/nonfinite_num_facets.hpp>
// from Johan Rade Floating Point Utilities.

int main ()
{
  std::cout << "Nonfinite_num_facet very simple example." << std::endl;

  if((std::numeric_limits<double>::has_infinity == 0) || (std::numeric_limits<double>::infinity() == 0))
  {
    std::cout << "Infinity not supported on this platform." << std::endl;
    return 0;
  }

  if((std::numeric_limits<double>::has_quiet_NaN == 0) || (std::numeric_limits<double>::quiet_NaN() == 0))
  {
    std::cout << "NaN not supported on this platform." << std::endl;
    return 0;
  }

  std::locale default_locale (std::locale::classic ()); // Note the currrent (default C) locale.

  // Create plus and minus infinity.
  double plus_infinity = +std::numeric_limits<double>::infinity();
  double minus_infinity = -std::numeric_limits<double>::infinity();

  // and create a NaN (NotANumber)
  double NaN = +std::numeric_limits<double>::quiet_NaN ();

  double negated_NaN = (boost::math::changesign)(std::numeric_limits<double>::quiet_NaN ());


  // Output the nonfinite values using the current (default C) locale.
  // The default representations differ from system to system,
  // for example, using Microsoft compilers, 1.#INF, -1.#INF, and 1.#QNAN.
  cout << "Using C locale" << endl;
  cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl;
  cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl;
  cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl;

  // Display negated NaN.
  cout << "negated NaN " << negated_NaN << endl; // "-1.IND"
  
  // Create a new output locale, and add the nonfinite_num_put facet
  std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>);
  // and imbue the cout stream with the new locale.
  cout.imbue (C99_out_locale);

  // Or for the same effect more concisely:
  cout.imbue (locale(locale(), new boost::math::nonfinite_num_put<char>));

  // Output using the new locale
  cout << "Using C99_out_locale " << endl;
  cout << "+std::numeric_limits<double>::infinity() = " << plus_infinity << endl;
  cout << "-std::numeric_limits<double>::infinity() = " << minus_infinity << endl;
  cout << "+std::numeric_limits<double>::quiet_NaN () = " << NaN << endl;

  // Display negated NaN.
  cout << "negated NaN " << negated_NaN << endl; // -nan

  // Create a string with the expected C99 representation of plus infinity.
  std::string inf = "inf";
  { // Try to read an infinity value using the default C locale.
    // Create an input stream which will provide "inf"
    std::istringstream iss (inf);

     // Create a double ready to take the input,
    double infinity;
    // and read "inf" from the stringstream:
    iss >> infinity; 

    // This will not work on all platforms!
    if (! iss)
    { // Reading infinity went wrong!
      std::cerr << "C locale input format error!" << std::endl;
    }
  } // Using default C locale.

  { // Now retry using C99 facets.
  // Create a new input locale and add the nonfinite_num_get facet.
  std::locale C99_in_locale (default_locale, new boost::math::nonfinite_num_get<char>);

  // Create an input stream which will provide "inf".
  std::istringstream iss (inf);
  // Imbue the stream with the C99 input locale.
  iss.imbue (C99_in_locale);

  // Create a double ready to take the input,
  double infinity;
  // and read from the stringstream:
  iss >> infinity; 

  if (! iss)
  { // Reading infinity went wrong!
    std::cout << "C99 input format error!" << std::endl;
  }
  // Expect to get an infinity, which will display still using the C99 locale as "inf"
  cout << "infinity in C99 representation is " << infinity << endl; 

  // To check, we can switch back to the default C locale.
  cout.imbue (default_locale);
  cout <<  "infinity in default C representation is " << infinity << endl; 
  } // using C99 locale.

  {
    // A 'loop-back example, output to a stringstream, and reading it back in.
    // Create C99 input and output locales. 
    std::locale C99_out_locale (default_locale, new boost::math::nonfinite_num_put<char>);
    std::locale C99_in_locale (default_locale, new boost::math::nonfinite_num_get<char>);

    std::ostringstream oss;
    oss.imbue(C99_out_locale);
    oss << plus_infinity;

    std::istringstream iss(oss.str()); // So stream contains "inf".
    iss.imbue (C99_in_locale);

    std::string s;

    iss >> s;

    cout.imbue(C99_out_locale);
    if (oss.str() != s)
    {
      cout << plus_infinity << " != " << s << " loopback failed!" << endl;
    }
    else
    {
      cout << plus_infinity << " == " << s << " as expected." << endl;
    }
  }


  // Example varying the width and position of the nonfinite representations.
  // With the nonfinite_num_put and _get facets, the width of the output is constant.

  #ifdef BOOST_NO_NUMERIC_LIMITS_LOWEST
  cout << "BOOST_NO_NUMERIC_LIMITS_LOWEST is defined, so no max_digits10 available." << endl;
  std::streamsize  max_digits10 = 2 + std::numeric_limits<double>::digits * 30103UL / 100000UL;
#else
  // Can use new C++0X max_digits10 (the maximum potentially significant digits).
  std::streamsize  max_digits10 = std::numeric_limits<double>::max_digits10;
#endif
  cout << "std::numeric_limits<double>::max_digits10 is " << max_digits10 << endl;
  cout.precision(max_digits10);

  double pi = 3.141592653589793238462643383279502884197169399375105820974944;
  // Expect 17 (probably) decimal digits (regardless of locale).
  // cout has the default locale.
  cout << "pi = " << pi << endl; // pi = 3.1415926535897931
  cout.imbue (C99_out_locale); // Use cout with the C99 locale
  // (expect the same output for a double).
  cout << "pi = " << pi << endl; // pi = 3.1415926535897931

  cout << "infinity in C99 representation is " << plus_infinity << endl; 

  //int width = 2; // Check effect if width too small is OK.
  // (There was a disturbed layout on older MSVC?).
  int width = 20;

  // Similarly if we can switch back to the default C locale.
  cout.imbue (default_locale);
  cout <<  "infinity in default C representation is " << plus_infinity << endl; 
  cout <<  "infinity in default C representation (setw(" << width << ") is |" << setw(width) << plus_infinity <<'|' << endl; 
  cout <<  "infinity in default C representation (setw(" << width << ") is |" << left << setw(width) << plus_infinity <<'|' << endl; 
  cout <<  "infinity in default C representation (setw(" << width << ") is |" << internal << setw(width) << plus_infinity <<'|' << endl; 

  cout.imbue (C99_out_locale);
  cout << "infinity in C99 representation (setw(" << width << ") is |" << right << setw(width) << plus_infinity <<'|'<< endl; 
  cout << "infinity in C99 representation (setw(" << width << ") is |" << left << setw(width) << plus_infinity <<'|'<< endl; 
  cout << "infinity in C99 representation (setw(" << width << ") is |" << internal << setw(width) << plus_infinity <<'|'<< endl; 

  return 0;
} // int main()

// end of test_nonfinite_num_facets.cpp

/*

Output:

simple_nonfinite_facet.vcxproj -> J:\Cpp\MathToolkit\test\Math_test\Release\nonfinite_facet_simple.exe
  Nonfinite_num_facet very simple example.
  Using C locale
  +std::numeric_limits<double>::infinity() = 1.#INF
  -std::numeric_limits<double>::infinity() = -1.#INF
  +std::numeric_limits<double>::quiet_NaN () = 1.#QNAN
  Using C99_out_locale 
  +std::numeric_limits<double>::infinity() = inf
  -std::numeric_limits<double>::infinity() = -inf
  +std::numeric_limits<double>::quiet_NaN () = nan
  infinity in C99 representation is inf
  infinity in default C representation is 1.#INF
  3
  3
  inf == inf as expected.
  std::numeric_limits<double>::max_digits10 is 17
  pi = 3.1415926535897931
  C locale input format error!
  pi = 3.1415926535897931
  infinity in C99 representation is inf
  infinity in default C representation is 1.#INF
  infinity in default C representation (setw(20) is               1.#INF|
  infinity in default C representation (setw(20) is 1.#INF              |
  infinity in default C representation (setw(20) is               1.#INF|
  infinity in C99 representation (setw(20) is                  inf|
  infinity in C99 representation (setw(20) is inf                 |
  infinity in C99 representation (setw(20) is                  inf|

*/