|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r71371 - trunk/boost/math/special_functions
From: pbristow_at_[hidden]
Date: 2011-04-18 12:19:49
Author: pbristow
Date: 2011-04-18 12:19:48 EDT (Mon, 18 Apr 2011)
New Revision: 71371
URL: http://svn.boost.org/trac/boost/changeset/71371
Log:
nonfinite facets
Added:
trunk/boost/math/special_functions/nonfinite_num_facets.hpp (contents, props changed)
Added: trunk/boost/math/special_functions/nonfinite_num_facets.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/math/special_functions/nonfinite_num_facets.hpp 2011-04-18 12:19:48 EDT (Mon, 18 Apr 2011)
@@ -0,0 +1,540 @@
+#ifndef BOOST_MATH_NONFINITE_NUM_FACETS_HPP
+#define BOOST_MATH_NONFINITE_NUM_FACETS_HPP
+
+// Copyright (c) 2006 Johan Rade
+// Copyright 2011 Paul A. Bristow (comments)
+
+// 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)
+
+/*
+\file
+
+\brief non_finite_num facets for C99 standard output of infinity and NaN.
+
+\details See fuller documentation at Boost.Math Facets
+ for Floating-Point Infinities and NaNs.
+*/
+
+#include <cstring>
+#include <ios>
+#include <limits>
+#include <locale>
+
+#include <boost/version.hpp>
+
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/sign.hpp>
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4127) // conditional expression is constant.
+# pragma warning(disable : 4706) // assignment within conditional expression.
+# pragma warning(disable : 4224) // formal parameter 'version' was previously defined as a type.
+#endif
+
+namespace boost {
+ namespace math {
+
+ // flags (enums can be ORed together) -----------------------------------
+
+ const int legacy = 0x1; //!< get facet will recognize most string representations of infinity and NaN.
+ const int signed_zero = 0x2; //!< put facet will distinguish between positive and negative zero.
+ const int trap_infinity = 0x4; /*!< put facet will throw an exception of type std::ios_base::failure
+ when an attempt is made to format positive or negative infinity.
+ get will set the fail bit of the stream when an attempt is made
+ to parse a string that represents positive or negative sign infinity.
+ */
+ const int trap_nan = 0x8; /*!< put facet will throw an exception of type std::ios_base::failure
+ when an attempt is made to format positive or negative NaN.
+ get will set the fail bit of the stream when an attempt is made
+ to parse a string that represents positive or negative sign infinity.
+ */
+
+ // class nonfinite_num_put -----------------------------------------------------
+
+ template<
+ class CharType,
+ class OutputIterator = std::ostreambuf_iterator<CharType>
+ >
+ class nonfinite_num_put : public std::num_put<CharType, OutputIterator>
+ {
+ public:
+ explicit nonfinite_num_put(int flags = 0) : flags_(flags) {}
+
+ protected:
+ virtual OutputIterator do_put(
+ OutputIterator it, std::ios_base& iosb,
+ CharType fill, double val) const
+ {
+ put_and_reset_width(it, iosb, fill, val);
+ return it;
+ }
+
+ virtual OutputIterator do_put(
+ OutputIterator it, std::ios_base& iosb,
+ CharType fill, long double val) const
+ {
+ put_and_reset_width(it, iosb, fill, val);
+ return it;
+ }
+
+ private:
+ template<class ValType> void put_and_reset_width(
+ OutputIterator& it, std::ios_base& iosb,
+ CharType fill, ValType val) const
+ {
+ put_impl(it, iosb, fill, val);
+ iosb.width(0);
+ }
+
+ template<class ValType> void put_impl(
+ OutputIterator& it, std::ios_base& iosb,
+ CharType fill, ValType val) const
+ {
+ switch((boost::math::fpclassify)(val)) {
+
+ case FP_INFINITE:
+ if(flags_ & trap_infinity)
+ throw std::ios_base::failure("Infinity");
+ else if((boost::math::signbit)(val))
+ put_num_and_fill(it, iosb, "-", "inf", fill);
+ else if(iosb.flags() & std::ios_base::showpos)
+ put_num_and_fill(it, iosb, "+", "inf", fill);
+ else
+ put_num_and_fill(it, iosb, "", "inf", fill);
+ break;
+
+ case FP_NAN:
+ if(flags_ & trap_nan)
+ throw std::ios_base::failure("NaN");
+ else if((boost::math::signbit)(val))
+ put_num_and_fill(it, iosb, "-", "nan", fill);
+ else if(iosb.flags() & std::ios_base::showpos)
+ put_num_and_fill(it, iosb, "+", "nan", fill);
+ else
+ put_num_and_fill(it, iosb, "", "nan", fill);
+ break;
+
+ case FP_ZERO:
+ if(flags_ & signed_zero) {
+ if((boost::math::signbit)(val))
+ put_num_and_fill(it, iosb, "-", "0", fill);
+ else if(iosb.flags() & std::ios_base::showpos)
+ put_num_and_fill(it, iosb, "+", "0", fill);
+ else
+ put_num_and_fill(it, iosb, "", "0", fill);
+ }
+ else
+ put_num_and_fill(it, iosb, "", "0", fill);
+ break;
+
+ default:
+ it = std::num_put<CharType, OutputIterator>::do_put(
+ it, iosb, fill, val);
+ break;
+ }
+ }
+
+ void put_num_and_fill(
+ OutputIterator& it, std::ios_base& iosb, const char* prefix,
+ const char* body, CharType fill) const
+ {
+ int width = (int)strlen(prefix) + (int)strlen(body);
+ std::ios_base::fmtflags adjust
+ = iosb.flags() & std::ios_base::adjustfield;
+ const std::ctype<CharType>& ct
+ = std::use_facet<std::ctype<CharType> >(iosb.getloc());
+
+ if(adjust != std::ios_base::internal && adjust != std::ios_base::left)
+ put_fill(it, iosb, fill, width);
+
+ while(*prefix)
+ *it = ct.widen(*(prefix++));
+
+ if(adjust == std::ios_base::internal)
+ put_fill(it, iosb, fill, width);
+
+ if(iosb.flags() & std::ios_base::uppercase) {
+ while(*body)
+ *it = ct.toupper(ct.widen(*(body++)));
+ }
+ else {
+ while(*body)
+ *it = ct.widen(*(body++));
+ }
+
+ if(adjust == std::ios_base::left)
+ put_fill(it, iosb, fill, width);
+ }
+
+ void put_fill(
+ OutputIterator& it, std::ios_base& iosb,
+ CharType fill, int width) const
+ {
+ for(std::streamsize i = iosb.width() - static_cast<std::streamsize>(width); i > 0; --i)
+ *it = fill;
+ }
+
+ private:
+ const int flags_;
+ };
+
+
+ // class nonfinite_num_get ------------------------------------------------------
+
+ template<
+ class CharType,
+ class InputIterator = std::istreambuf_iterator<CharType>
+ >
+ class nonfinite_num_get : public std::num_get<CharType, InputIterator>
+ {
+
+ public:
+ explicit nonfinite_num_get(int flags = 0) : flags_(flags)
+ {}
+
+ protected:
+ virtual InputIterator do_get(
+ InputIterator it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, float& val) const
+ {
+ get_and_check_eof(it, end, iosb, state, val);
+ return it;
+ }
+
+ virtual InputIterator do_get(
+ InputIterator it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, double& val) const
+ {
+ get_and_check_eof(it, end, iosb, state, val);
+ return it;
+ }
+
+ virtual InputIterator do_get(
+ InputIterator it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, long double& val) const
+ {
+ get_and_check_eof(it, end, iosb, state, val);
+ return it;
+ }
+
+ //..............................................................................
+
+ private:
+ template<class ValType> static ValType positive_nan()
+ {
+ // On some platforms quiet_NaN() may be negative.
+ return (boost::math::copysign)(
+ std::numeric_limits<ValType>::quiet_NaN(), static_cast<ValType>(1)
+ );
+ // static_cast<ValType>(1) added Paul A. Bristow 5 Apr 11
+ }
+
+ template<class ValType> void get_and_check_eof
+ (
+ InputIterator& it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ get_signed(it, end, iosb, state, val);
+ if(it == end)
+ state |= std::ios_base::eofbit;
+ }
+
+ template<class ValType> void get_signed
+ (
+ InputIterator& it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ const std::ctype<CharType>& ct
+ = std::use_facet<std::ctype<CharType> >(iosb.getloc());
+
+ char c = peek_char(it, end, ct);
+
+ bool negative = (c == '-');
+
+ if(negative || c == '+')
+ {
+ ++it;
+ c = peek_char(it, end, ct);
+ if(c == '-' || c == '+')
+ { // Without this check, "++5" etc would be accepted.
+ state |= std::ios_base::failbit;
+ return;
+ }
+ }
+
+ get_unsigned(it, end, iosb, ct, state, val);
+
+ if(negative)
+ {
+ val = (boost::math::changesign)(val);
+ }
+ } // void get_signed
+
+ template<class ValType> void get_unsigned
+ ( // get an unsigned value into val
+ InputIterator& it, InputIterator end, std::ios_base& iosb,
+ const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ switch(peek_char(it, end, ct))
+ {
+ case 'i':
+ get_i(it, end, ct, state, val);
+ break;
+
+ case 'n':
+ get_n(it, end, ct, state, val);
+ break;
+
+ case 'q':
+ case 's':
+ get_q(it, end, ct, state, val);
+ break;
+
+ default:
+ it = std::num_get<CharType, InputIterator>::do_get(
+ it, end, iosb, state, val);
+ if((flags_ & legacy) && val == static_cast<ValType>(1)
+ && peek_char(it, end, ct) == '#')
+ get_one_hash(it, end, ct, state, val);
+ break;
+ }
+ } // get_unsigned
+
+ //..........................................................................
+
+ template<class ValType> void get_i
+ ( // Get the rest of all strings starting with 'i', expect "inf", "infinity".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ if(!std::numeric_limits<ValType>::has_infinity
+ || (flags_ & trap_infinity))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "nf"))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ if(peek_char(it, end, ct) != 'i')
+ {
+ val = std::numeric_limits<ValType>::infinity(); // "inf"
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "nity"))
+ { // Expected "infinity"
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ val = std::numeric_limits<ValType>::infinity(); // "infinity"
+ } // void get_i
+
+ template<class ValType> void get_n
+ ( // Get expected strings after 'n', "nan", "nanq", "nans", "nan(...)"
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ if(!std::numeric_limits<ValType>::has_quiet_NaN
+ || (flags_ & trap_nan)) {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "an"))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ switch(peek_char(it, end, ct)) {
+ case 'q':
+ case 's':
+ if(flags_ && legacy)
+ ++it;
+ break; // "nanq", "nans"
+
+ case '(': // Optional payload field in (...) follows.
+ {
+ ++it;
+ char c;
+ while((c = peek_char(it, end, ct))
+ && c != ')' && c != ' ' && c != '\n' && c != '\t')
+ ++it;
+ if(c != ')')
+ { // Optional payload field terminator missing!
+ state |= std::ios_base::failbit;
+ return;
+ }
+ ++it;
+ break; // "nan(...)"
+ }
+
+ default:
+ break; // "nan"
+ }
+
+ val = positive_nan<ValType>();
+ } // void get_n
+
+ template<class ValType> void get_q
+ ( // Get expected rest of string starting with 'q': "qnan".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ if(!std::numeric_limits<ValType>::has_quiet_NaN
+ || (flags_ & trap_nan) || !(flags_ & legacy))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "nan"))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ val = positive_nan<ValType>(); // "QNAN"
+ } // void get_q
+
+ template<class ValType> void get_one_hash
+ ( // Get expected string after having read "1.#": "1.#IND", "1.#QNAN", "1.#SNAN".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+
+ ++it;
+ switch(peek_char(it, end, ct))
+ {
+ case 'i': // from IND (indeterminate), considered same a QNAN.
+ get_one_hash_i(it, end, ct, state, val); // "1.#IND"
+ return;
+
+ case 'q': // from QNAN
+ case 's': // from SNAN - treated the same as QNAN.
+ if(std::numeric_limits<ValType>::has_quiet_NaN
+ && !(flags_ & trap_nan))
+ {
+ ++it;
+ if(match_string(it, end, ct, "nan"))
+ { // "1.#QNAN", "1.#SNAN"
+ // ++it; // removed as caused assert() cannot increment iterator).
+// (match_string consumes string, so not needed?).
+// https://svn.boost.org/trac/boost/ticket/5467
+// Change in nonfinite_num_facet.hpp Paul A. Bristow 11 Apr 11 makes legacy_test.cpp work OK.
+ val = positive_nan<ValType>(); // "1.#QNAN"
+ return;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ state |= std::ios_base::failbit;
+ } // void get_one_hash
+
+ template<class ValType> void get_one_hash_i
+ ( // Get expected strings after 'i', "1.#INF", 1.#IND".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ ++it;
+
+ if(peek_char(it, end, ct) == 'n')
+ {
+ ++it;
+ switch(peek_char(it, end, ct))
+ {
+ case 'f': // "1.#INF"
+ if(std::numeric_limits<ValType>::has_infinity
+ && !(flags_ & trap_infinity))
+ {
+ ++it;
+ val = std::numeric_limits<ValType>::infinity();
+ return;
+ }
+ break;
+
+ case 'd': // 1.#IND"
+ if(std::numeric_limits<ValType>::has_quiet_NaN
+ && !(flags_ & trap_nan))
+ {
+ ++it;
+ val = positive_nan<ValType>();
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ state |= std::ios_base::failbit;
+ } // void get_one_hash_i
+
+ //..........................................................................
+
+ char peek_char
+ ( // Return next char (from input buffer).
+ InputIterator& it, InputIterator end,
+ const std::ctype<CharType>& ct
+ ) const
+ {
+ if(it == end) return 0;
+ return ct.narrow(ct.tolower(*it), 0); // Always tolower to ensure case insensitive.
+ }
+
+ bool match_string
+ ( // Match remaining chars to expected string (case insensitive).
+ InputIterator& it, InputIterator end,
+ const std::ctype<CharType>& ct,
+ const char* s
+ ) const
+ {
+ while(it != end && *s && *s == ct.narrow(ct.tolower(*it), 0))
+ {
+ ++s;
+ ++it;
+ }
+ return !*s;
+ } // char peek_char
+
+ private:
+ const int flags_;
+ }; //
+
+ //------------------------------------------------------------------------------
+
+ } // namespace math
+} // namespace boost
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+#endif
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk