2
0
mirror of https://github.com/boostorg/math.git synced 2026-01-28 07:22:12 +00:00

Version that passes new tests for both default and signed_zero flag set based on modifications by KR Walker.

BUT had to suppress MSVC warning "C4244 conversion wchar_t* to char* may cause data loss." 

[SVN r77268]
This commit is contained in:
Paul A. Bristow
2012-03-08 18:12:28 +00:00
parent 5e2156688e
commit fec1f2407e

View File

@@ -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 <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.
# 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<CharType> 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<CharType, OutputIterator>::do_put(
it, iosb, fill, val);
default: // Normal non-zero finite value.
it = std::num_put<CharType, OutputIterator>::do_put(it, iosb, fill, val);
break;
}
}
template<class ValType>
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<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(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<CharType, OutputIterator>::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<std::streamsize>(width); i > 0; --i)
*it = fill;
}
@@ -540,4 +591,5 @@ namespace boost {
# pragma warning(pop)
#endif
#endif
#endif // BOOST_MATH_NONFINITE_NUM_FACETS_HPP