diff --git a/include/boost/math/special_functions/nonfinite_num_facets.hpp b/include/boost/math/special_functions/nonfinite_num_facets.hpp index 9fa61481b..0deb1e089 100644 --- a/include/boost/math/special_functions/nonfinite_num_facets.hpp +++ b/include/boost/math/special_functions/nonfinite_num_facets.hpp @@ -1,8 +1,9 @@ #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) +// Copyright 2006 Johan Rade +// Copyright 2012 K R Walker +// Copyright 2011, 2012 Paul A. Bristow // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt @@ -28,10 +29,10 @@ #include #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. +# pragma warning(push) +# pragma warning(disable : 4127) // conditional expression is constant. +# pragma warning(disable : 4706) // assignment within conditional expression. +# pragma warning(disable : 4244) // TODO? // Needs to be CharType version. #endif namespace boost { @@ -65,16 +66,14 @@ namespace boost { protected: virtual OutputIterator do_put( - OutputIterator it, std::ios_base& iosb, - CharType fill, double val) const + 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 + OutputIterator it, std::ios_base& iosb, CharType fill, long double val) const { put_and_reset_width(it, iosb, fill, val); return it; @@ -93,86 +92,138 @@ namespace boost { OutputIterator& it, std::ios_base& iosb, CharType fill, ValType val) const { - switch((boost::math::fpclassify)(val)) { + 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); + { // negative infinity. + put_num_and_fill(it, iosb, "-", "inf", fill, val); + } else if(iosb.flags() & std::ios_base::showpos) - put_num_and_fill(it, iosb, "+", "inf", fill); + { // Explicit "+inf" wanted. + put_num_and_fill(it, iosb, "+", "inf", fill, val); + } else - put_num_and_fill(it, iosb, "", "inf", fill); + { // just "inf" wanted. + put_num_and_fill(it, iosb, "", "inf", fill, val); + } 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); + { // negative so "-nan". + put_num_and_fill(it, iosb, "-", "nan", fill, val); + } else if(iosb.flags() & std::ios_base::showpos) - put_num_and_fill(it, iosb, "+", "nan", fill); + { // explicit "+nan" wanted. + put_num_and_fill(it, iosb, "+", "nan", fill, val); + } else - put_num_and_fill(it, iosb, "", "nan", fill); + { // Just "nan". + put_num_and_fill(it, iosb, "", "nan", fill, val); + } 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); + if((flags_ & signed_zero) && ((boost::math::signbit)(val))) + { // Flag set to distinguish between positive and negative zero. + // But string "0" should have stuff after decimal point if setprecision and/or exp format. + + //std::basic_ostringstream zeros; // Needs to be CharType version. + + std::ostringstream zeros; + + //std::cout << "iosb.flags() = " << std::hex << iosb.flags() << std::endl; + //std::cout << "iosb.precision() = " << std::hex << iosb.precision() << std::endl; + //std::cout << "iosb.width() = " << std::hex << iosb.width() << std::endl; + // Copy flags, fill, width and precision. + zeros.flags(iosb.flags()); + zeros.unsetf(std::ios::showpos); // Ignore showpos because must be negative. + zeros.precision(iosb.precision()); + //zeros.width is set by put_num_and_fill + zeros.fill(fill); + zeros << ValType(0); + // std::cout << "zeros.str() = "<< zeros.str() << std::endl; + // put_num_and_fill(it, iosb, "-", zeros.str().c_str(), fill, val); + + put_num_and_fill(it, iosb, "-", zeros.str().c_str(), fill, val); } else - put_num_and_fill(it, iosb, "", "0", fill); + { // Output the platform default for positive and negative zero. + put_num_and_fill(it, iosb, 0, 0, fill, val); + } break; - default: - it = std::num_put::do_put( - it, iosb, fill, val); + default: // Normal non-zero finite value. + it = std::num_put::do_put(it, iosb, fill, val); break; } } + template void put_num_and_fill( OutputIterator& it, std::ios_base& iosb, const char* prefix, - const char* body, CharType fill) const + const char* body, CharType fill, ValType val) const { - int width = (int)std::strlen(prefix) + (int)std::strlen(body); - std::ios_base::fmtflags adjust - = iosb.flags() & std::ios_base::adjustfield; + int prefix_length = prefix ? (int)std::strlen(prefix) : 0; + int body_length = body ? (int)std::strlen(body) : 0; + int width = prefix_length + body_length; + std::ios_base::fmtflags adjust = iosb.flags() & std::ios_base::adjustfield; const std::ctype& ct = std::use_facet >(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(body || prefix) + { // adjust == std::ios_base::right, so leading fill needed. + if(adjust != std::ios_base::internal && adjust != std::ios_base::left) + put_fill(it, iosb, fill, width); } - if(adjust == std::ios_base::left) - put_fill(it, iosb, fill, width); + if(prefix) + { // Adjust width for prefix. + while(*prefix) + *it = ct.widen(*(prefix++)); + iosb.width( iosb.width() - prefix_length ); + width -= prefix_length; + } + + if(body) + { // + if(adjust == std::ios_base::internal) + { // Put fill between sign and digits. + 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); + } + else + { + it = std::num_put::do_put(it, iosb, fill, val); + } } void put_fill( - OutputIterator& it, std::ios_base& iosb, - CharType fill, int width) const - { + OutputIterator& it, std::ios_base& iosb, CharType fill, int width) const + { // Insert fill chars. for(std::streamsize i = iosb.width() - static_cast(width); i > 0; --i) *it = fill; } @@ -540,4 +591,5 @@ namespace boost { # pragma warning(pop) #endif -#endif +#endif // BOOST_MATH_NONFINITE_NUM_FACETS_HPP +