]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Distributed under the Boost Software License, Version 1.0. |
2 | // (See accompanying file LICENSE_1_0.txt | |
3 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
4 | ||
5 | // Copyright (c) 2006 Johan Rade | |
6 | // Copyright (c) 2011 Paul A. Bristow comments | |
7 | // Copyright (c) 2011 John Maddock | |
8 | /*! | |
9 | \file | |
10 | \brief Basic tests of the nonfinite num facets. | |
11 | ||
12 | \detail If has_infinity and has_nan, then | |
13 | basic_test outputs using nonfinite_num_put facet | |
14 | and reads back in using nonfinite_num_ facet, | |
15 | and checks loopback OK. | |
16 | ||
17 | Also checks that output of infinity, -infinity and NaN are as expected, | |
18 | using C99 specification "nan -nan nan -nan" and "inf -inf". | |
19 | Also includes a few combinations of display manipulators | |
20 | (left, right, internal, showpos) | |
21 | and checks that can input C99 infinity and NaN too. | |
22 | ||
23 | */ | |
24 | ||
25 | #ifdef _MSC_VER | |
26 | # pragma warning(disable : 4702) // Unreachable code. | |
27 | #endif | |
28 | ||
29 | #include <iomanip> | |
30 | #include <locale> | |
31 | #include <sstream> | |
32 | ||
33 | #define BOOST_TEST_MAIN | |
34 | ||
92f5a8d4 | 35 | #include <boost/test/unit_test.hpp> |
7c673cae FG |
36 | |
37 | #include "almost_equal.ipp" | |
38 | #include "s_.ipp" | |
39 | ||
40 | #include <boost/math/special_functions/nonfinite_num_facets.hpp> | |
41 | ||
42 | namespace | |
43 | { // The anonymous namespace resolves ambiguities on | |
44 | // platforms with fpclassify etc functions at global scope. | |
45 | ||
46 | using namespace boost::math; | |
47 | using boost::math::signbit; | |
48 | using boost::math::changesign; | |
49 | using boost::math::isnan; | |
50 | ||
51 | //------------------------------------------------------------------------------ | |
52 | ||
53 | void basic_test_finite(); | |
54 | void basic_test_inf(); | |
55 | void basic_test_nan(); | |
56 | void basic_test_format(); | |
57 | ||
58 | BOOST_AUTO_TEST_CASE(basic_test) | |
59 | { | |
60 | basic_test_finite(); | |
61 | basic_test_inf(); | |
62 | basic_test_nan(); | |
63 | basic_test_format(); | |
64 | } | |
65 | ||
66 | //------------------------------------------------------------------------------ | |
67 | ||
68 | template<class CharType, class ValType> void basic_test_finite_impl(); | |
69 | ||
70 | void basic_test_finite() | |
71 | { | |
72 | basic_test_finite_impl<char, float>(); | |
73 | basic_test_finite_impl<char, double>(); | |
74 | basic_test_finite_impl<char, long double>(); | |
75 | basic_test_finite_impl<wchar_t, float>(); | |
76 | basic_test_finite_impl<wchar_t, double>(); | |
77 | basic_test_finite_impl<wchar_t, long double>(); | |
78 | } | |
79 | ||
80 | template<class CharType, class ValType> void basic_test_finite_impl() | |
81 | { | |
82 | if((std::numeric_limits<ValType>::has_infinity == 0) || (std::numeric_limits<ValType>::infinity() == 0)) | |
83 | return; | |
84 | ||
85 | std::locale old_locale; | |
86 | std::locale tmp_locale(old_locale, new nonfinite_num_put<CharType>); | |
87 | std::locale new_locale(tmp_locale, new nonfinite_num_get<CharType>); | |
88 | ||
89 | std::basic_stringstream<CharType> ss; | |
90 | ss.imbue(new_locale); | |
91 | ||
92 | ValType a1 = (ValType)1.2; | |
93 | ValType a2 = (ValType)-3.5; | |
94 | ValType a3 = (std::numeric_limits<ValType>::max)(); | |
95 | ValType a4 = -(std::numeric_limits<ValType>::max)(); | |
96 | ss << a1 << ' ' << a2 << ' ' << a3 << ' ' << a4; | |
97 | ||
98 | ValType b1, b2, b3, b4; | |
99 | ss >> b1 >> b2 >> b3 >> b4; | |
100 | ||
101 | BOOST_CHECK(almost_equal(b1, a1)); | |
102 | BOOST_CHECK(almost_equal(b2, a2)); | |
103 | BOOST_CHECK(almost_equal(b3, a3)); | |
104 | BOOST_CHECK(almost_equal(b4, a4)); | |
105 | BOOST_CHECK(b3 != std::numeric_limits<ValType>::infinity()); | |
106 | BOOST_CHECK(b4 != -std::numeric_limits<ValType>::infinity()); | |
107 | BOOST_CHECK(ss.rdstate() == std::ios_base::eofbit); | |
108 | ||
109 | ss.clear(); | |
110 | ss.str(S_("")); | |
111 | ||
112 | ss << "++5"; | |
113 | ValType b5; | |
114 | ss >> b5; | |
115 | BOOST_CHECK(ss.rdstate() == std::ios_base::failbit); | |
116 | } | |
117 | ||
118 | //------------------------------------------------------------------------------ | |
119 | ||
120 | template<class CharType, class ValType> void basic_test_inf_impl(); | |
121 | ||
122 | void basic_test_inf() | |
123 | { | |
124 | basic_test_inf_impl<char, float>(); | |
125 | basic_test_inf_impl<char, double>(); | |
126 | basic_test_inf_impl<char, long double>(); | |
127 | basic_test_inf_impl<wchar_t, float>(); | |
128 | basic_test_inf_impl<wchar_t, double>(); | |
129 | basic_test_inf_impl<wchar_t, long double>(); | |
130 | } | |
131 | ||
132 | template<class CharType, class ValType> void basic_test_inf_impl() | |
133 | { | |
134 | if((std::numeric_limits<ValType>::has_infinity == 0) || (std::numeric_limits<ValType>::infinity() == 0)) | |
135 | return; | |
136 | ||
137 | std::locale old_locale; | |
138 | std::locale tmp_locale(old_locale, new nonfinite_num_put<CharType>); | |
139 | std::locale new_locale(tmp_locale, new nonfinite_num_get<CharType>); | |
140 | ||
141 | std::basic_stringstream<CharType> ss; | |
142 | ss.imbue(new_locale); | |
143 | ||
144 | ValType a1 = std::numeric_limits<ValType>::infinity(); | |
145 | ValType a2 = -std::numeric_limits<ValType>::infinity(); | |
146 | ||
147 | BOOST_CHECK((boost::math::isinf)(a1)); | |
148 | BOOST_CHECK((boost::math::isinf)(a2)); | |
149 | ||
150 | ss << a1 << ' ' << a2; | |
151 | ||
152 | std::basic_string<CharType> s = S_("inf -inf"); | |
153 | BOOST_CHECK(ss.str() == s); | |
154 | ||
155 | ss << " infinity"; // Alternative C99 representation of infinity. | |
156 | ||
157 | ValType b1, b2, b3; | |
158 | ss >> b1; | |
159 | ss >> b2; | |
160 | ss >> b3; | |
161 | ||
162 | BOOST_CHECK(b1 == a1); | |
163 | BOOST_CHECK(b2 == a2); | |
164 | BOOST_CHECK(b3 == std::numeric_limits<ValType>::infinity()); | |
165 | BOOST_CHECK(ss.rdstate() == std::ios_base::eofbit); | |
166 | } | |
167 | ||
168 | //------------------------------------------------------------------------------ | |
169 | ||
170 | template<class CharType, class ValType> void basic_test_nan_impl(); | |
171 | ||
172 | void basic_test_nan() | |
173 | { | |
174 | basic_test_nan_impl<char, float>(); | |
175 | basic_test_nan_impl<char, double>(); | |
176 | basic_test_nan_impl<char, long double>(); | |
177 | basic_test_nan_impl<wchar_t, float>(); | |
178 | basic_test_nan_impl<wchar_t, double>(); | |
179 | basic_test_nan_impl<wchar_t, long double>(); | |
180 | } | |
181 | ||
182 | template<class CharType, class ValType> void basic_test_nan_impl() | |
183 | { | |
184 | if((std::numeric_limits<ValType>::has_quiet_NaN == 0) || (std::numeric_limits<ValType>::quiet_NaN() == 0)) | |
185 | return; | |
186 | ||
187 | std::locale old_locale; | |
188 | std::locale tmp_locale(old_locale, new nonfinite_num_put<CharType>); | |
189 | std::locale new_locale(tmp_locale, new nonfinite_num_get<CharType>); | |
190 | ||
191 | std::basic_stringstream<CharType> ss; | |
192 | ss.imbue(new_locale); | |
193 | ||
194 | ValType a1 = std::numeric_limits<ValType>::quiet_NaN(); | |
195 | ValType a2 = (boost::math::changesign)(std::numeric_limits<ValType>::quiet_NaN()); | |
196 | ValType a3 = std::numeric_limits<ValType>::signaling_NaN(); | |
197 | ValType a4 = (boost::math::changesign)(std::numeric_limits<ValType>::signaling_NaN()); | |
198 | ss << a1 << ' ' << a2 << ' ' << a3 << ' ' << a4; | |
199 | ||
200 | BOOST_CHECK((boost::math::isnan)(a1) && (boost::math::isnan)(a2) && (boost::math::isnan)(a3) && (boost::math::isnan)(a4)); | |
201 | ||
202 | std::basic_string<CharType> s = S_("nan -nan nan -nan"); | |
203 | BOOST_CHECK(ss.str() == s); | |
204 | ||
205 | // Alternative C99 representation of NaN. | |
206 | ss << " nan(foo)"; | |
207 | ||
208 | ValType b1, b2, b3, b4, b5; | |
209 | ss >> b1 >> b2 >> b3 >> b4 >> b5; | |
210 | ||
211 | BOOST_CHECK((isnan)(b1)); | |
212 | BOOST_CHECK((isnan)(b2)); | |
213 | BOOST_CHECK((isnan)(b3)); | |
214 | BOOST_CHECK((isnan)(b4)); | |
215 | BOOST_CHECK((isnan)(b5)); | |
216 | ||
217 | BOOST_CHECK(!(signbit)(b1)); | |
218 | BOOST_CHECK((signbit)(b2)); | |
219 | BOOST_CHECK(!(signbit)(b3)); | |
220 | BOOST_CHECK((signbit)(b4)); | |
221 | BOOST_CHECK(!(signbit)(b5)); | |
222 | ||
223 | BOOST_CHECK(ss.rdstate() == std::ios_base::eofbit); | |
224 | } | |
225 | ||
226 | //------------------------------------------------------------------------------ | |
227 | ||
228 | template<class CharType, class ValType> void basic_test_format_impl(); | |
229 | ||
230 | void basic_test_format() | |
231 | { | |
232 | basic_test_format_impl<char, float>(); | |
233 | basic_test_format_impl<char, double>(); | |
234 | basic_test_format_impl<char, long double>(); | |
235 | basic_test_format_impl<wchar_t, float>(); | |
236 | basic_test_format_impl<wchar_t, double>(); | |
237 | basic_test_format_impl<wchar_t, long double>(); | |
238 | } | |
239 | ||
240 | template<class CharType, class ValType> void basic_test_format_impl() | |
241 | { | |
242 | if((std::numeric_limits<ValType>::has_infinity == 0) || (std::numeric_limits<ValType>::infinity() == 0)) | |
243 | return; | |
244 | ||
245 | std::locale old_locale; | |
246 | std::locale tmp_locale(old_locale, new nonfinite_num_put<CharType>); | |
247 | std::locale new_locale(tmp_locale, new nonfinite_num_get<CharType>); | |
248 | ||
249 | std::basic_stringstream<CharType> ss; | |
250 | ss.imbue(new_locale); | |
251 | ||
252 | ValType a = std::numeric_limits<ValType>::infinity(); | |
253 | ||
254 | BOOST_CHECK((boost::math::isinf)(a)); | |
255 | ||
256 | ss << std::setw(6) << a; // Expect right justified in field of six, so 3 leading spaces. | |
257 | ss << '|'; | |
258 | ss << std::setw(2) << a; // Too narrow for "inf", but should still be "inf". | |
259 | ss << '|'; | |
260 | ss << std::left << std::setw(5) << a; // 5 - 3 leaves two trailing spaces. | |
261 | ss << '|'; | |
262 | ss << std::showpos << std::internal << std::setw(7) << a; // 3 internal spaces between + and "inf". | |
263 | ss << '|'; | |
264 | ss << std::uppercase << std::right << std::setw(6) << a; // still showpos, so "space, space, +INF". | |
265 | ||
266 | std::basic_string<CharType> s = S_(" inf|inf|inf |+ inf| +INF"); | |
267 | BOOST_CHECK(ss.str() == s); | |
268 | } | |
269 | ||
270 | //------------------------------------------------------------------------------ | |
271 | ||
272 | } // anonymous namespace |