Re: Precision print doubles manipulator

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



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
.



Relevant Pages

  • Precision print doubles manipulator
    ... I've just created a stream manipulator that "precision formats" doubles. ... write doubles with up to 6 decimals: ...
    (microsoft.public.vc.language)
  • Re: Precision
    ... Whether one does the subsequent calculations in internal ie integer format ... I have always used external format with Precision 4 since my ... floating point calcs which are done in binary have around 3% error albeit at ... positions it is IMPOSIBLE to have a result of 4 decimals with the 2 ...
    (comp.databases.pick)
  • Re: Precision
    ... It's the same if we use Precision, floating point, or ... positions it is IMPOSIBLE to have a result of 4 decimals with the 2 ... May be something wrong in the floating ... remember what the associated actuarial calculations were. ...
    (comp.databases.pick)
  • Re: D3/Linux and Flash Basic
    ... with precision or decimals, it's the D3 F option that causes BASIC to ... use floating point calculations. ... My blog helped to explain how BASIC works with different ...
    (comp.databases.pick)
  • Re: D3/Linux and Flash Basic
    ... The problem Joseba describes isn't ... with precision or decimals, it's the D3 F option that causes BASIC to ... use floating point calculations. ...
    (comp.databases.pick)