Re: Precision print doubles manipulator
- From: "Tom Widmer [VC++ MVP]" <tom_usenet@xxxxxxxxxxx>
- Date: Thu, 14 Jun 2007 15:01:54 +0100
Daniel Lidström wrote:
Hello!
I've just created a stream manipulator that "precision formats" doubles. I
wanted a way to write doubles so that the number of decimals is of a
minimum precision. For example, I want all doubles to be written with up to
6 digits, if necessary, but less digits if possible. So the value 5 is
written as 5 and 0.9999999 as 1. Let me demonstrate with some examples that
write doubles with up to 6 decimals:
std::cout << precision_fmt<6>(5.) << std::endl;
std::cout << precision_fmt<6>(40.873918842465351) << std::endl;
In an ideal world, I'd expect to write:
std::cout << precision_fmt(6) << 40.873918842465351 << std::endl;
though I think that would be impossible to implement without writing your own num_put locale facets. More comments below.
template<std::streamsize N>
struct precision_fmt : public manip_base<precision_fmt>
{
double m_d;
precision_fmt(double d)
: m_d(d)
{}
static double RoundDouble(double doValue, std::size_t nPrecision)
{
static const double doBase = 10.0;
double doComplete5, doComplete5i;
doComplete5 = doValue * pow(doBase, (double) (nPrecision + 1));
if(doValue < 0.0)
doComplete5 -= 5.0;
else
doComplete5 += 5.0;
doComplete5 /= doBase;
modf(doComplete5, &doComplete5i);
return doComplete5i / pow(doBase, (double) nPrecision);
}
std::streamsize decimals = 0;
for( std::streamsize i=N; i>0; i-- )
{
if( RoundDouble(m_d, i-1)!=RoundDouble(m_d, i) )
{
decimals = i;
break;
}
}
I'm not convinced that the above is guaranteed to work - it makes assuptions about floating point calculations that I don't think are guaranteed, and which might break down in the face of an aggressive optimizer. In particular I think your code assumes something like
x / y == (x * 10) / (y * 10)
which I don't think necessarily holds for floating point numbers, particularly when you throw in pow calculations. You're probably ok on IEEE compliant machines.
stream.setf(std::ios_base::fixed);
stream.precision(decimals);
stream << m_d;
return stream;
}
};
Hopefully somebody will also find this useful. Any comments?
I'd use a different algorithm for determining the precision. The simplest way is to convert to a string using the max precision (N), and then lop off the all trailing 0s before outputting to the stream. Another way would be to compare your two RoundDouble results using an epsilon calculated from i, such as pow(10, -(i + 1)) or something (I can't think exactly what you need here).
Tom
.
- References:
- Precision print doubles manipulator
- From: Daniel Lidström
- Precision print doubles manipulator
- Prev by Date: Get license related information in Windows Vista
- Next by Date: Re: how to compress
- Previous by thread: Precision print doubles manipulator
- Next by thread: Get license related information in Windows Vista
- Index(es):
Relevant Pages
|