std::stringstream and floating point accuracy

M

Mr Fish

Is it possible for me to record floats in a std::stringstream with
100% accuracy? If so how?

Here's a little prog that demonstrates how the default ss loses
accuracy

//-----------------------------------------------------------------------------
#include <sstream>
#include <iostream>
using namespace std;

int main()
{

stringstream ss;

float fOriginal = 0.00000011920928955078125f;

ss << fOriginal;

float fRestored;
ss >> fRestored;

cout << endl << fOriginal;
cout << endl << fRestored;

cout << endl << endl << (fOriginal == fRestored); //should be
equal but are not
cout << endl << fOriginal - fRestored; //there's a diff!


return 0;
}

//-----------------------------------------------------------------------------
 
K

Kristo

Mr said:
Is it possible for me to record floats in a std::stringstream with
100% accuracy? If so how?

Assuming you want to store a decimal number with a fixed number of
places (i.e., a non-repeating rational number), the only way to ensure
100% accuracy is to store it as a string.
Here's a little prog that demonstrates how the default ss loses
accuracy

[snip code example]

The problem is that representing decimals in a computer is inaccurate.
It's not the stringstream's fault. Here's a good essay to read that
will explain why:

http://docs.sun.com/source/806-3568/ncg_goldberg.html

Kristo
 
K

Karl Heinz Buchegger

Mr said:
Is it possible for me to record floats in a std::stringstream with
100% accuracy? If so how?

Here's a little prog that demonstrates how the default ss loses
accuracy

//-----------------------------------------------------------------------------
#include <sstream>
#include <iostream>
using namespace std;

int main()
{

stringstream ss;

float fOriginal = 0.00000011920928955078125f;

In most implementations I am aware of, float is capable of holding
5 to 6 digits. Apply that to your number, and you get:

1.19209 E -7

everything else in your number is already lost. Even the 9 in the
last digit is already a questionable one. Things get worse if you
do sme arithmetic with that number.

As a minimum: forget 'float' and start using 'double'.
Unless you know what you do and are willing to do it and have the
knowledge to do it and have a very, very, very good reason: never
use float.
 
A

Alvaro Segura

I tried the followind (in C) to test how much was lost when storing in a
float:

float x=0.00000011920928955078125f;
printf("%.25f\n", x);

The output is exactly:

0.0000001192092895507812500

Wow!!
For some reason, Mr Fish chose a number which is exactly representable as a
float var.

Anyway, with arbitrary numbers like 0.00000012268758375648363f, the output
is 0.0000001226875809834382400. You get 8 correct significant digits. But
the correct digits is not the important thing, but the precision of the
stored value, or the error of the representation.

The error in that case is around -2.77e-15. If the original number
represented a length of 12.2 cm (approx. the diameter of a CD) expressed in
strange units like thousands of km [:)], the error would be equivalent to 3
millionths of a millimeter, or around 30 times the diameter of a hydrogen
atom. Is it that bad?

Let's not just look at the written digits (in decimal), counting how many
are right. Let's look at the accuracy of the values for a particular
application. Decimal is just a representation, which can be as bad as
binary, it's just a different one. We should not see a decimal
representation as the perfect one.

float is not that bad for many, many tasks, but double is sure more suitable
for many others.
 
K

Kai-Uwe Bux

Mr said:
Is it possible for me to record floats in a std::stringstream with
100% accuracy? If so how?

Maybe you find something useful in the following snippet:

#include <iostream>
#include <limits>
#include <cmath>
#include <iomanip>

template < typename Float >
struct precision {

static unsigned int digits ( unsigned int base ) {
return( -
std::log( std::numeric_limits<Float>::epsilon() )
/
std::log( base ) );
}

};

template < typename Float >
unsigned int sig_digits ( Float const & ) {
return( precision<Float>::digits(10) );
}

int main ( void ) {
std::cout << precision<float>::digits( 10 )
<< " "
<< precision<double>::digits( 10 )
<< '\n';
float x = 2.3345467334234;
double y = 12.230912093719823691836;
std::cout << std::setprecision( sig_digits(x) ) << x << '\n';
std::cout << std::setprecision( sig_digits(y) ) << y << '\n';
}



Best

Kai-Uwe Bux
 
K

Karl Heinz Buchegger

Alvaro said:
I tried the followind (in C) to test how much was lost when storing in a
float:

float x=0.00000011920928955078125f;
printf("%.25f\n", x);

The output is exactly:

0.0000001192092895507812500

Wow!!
For some reason, Mr Fish chose a number which is exactly representable as a
float var.

Anyway, with arbitrary numbers like 0.00000012268758375648363f, the output
is 0.0000001226875809834382400. You get 8 correct significant digits. But
the correct digits is not the important thing, but the precision of the
stored value, or the error of the representation.

The error in that case is around -2.77e-15.

That is the absolute error.
Completely unimportant. Important is the relative error (the error in relation
to the number)

Add 1.0f to the number above and see what is left from your -2.77e-15

I suggest you try the same thing with the number
1.2268758375648363f (That's the same number, just a different exponent)
and see if your figures also hold.

float is not that bad for many, many tasks, but double is sure more suitable
for many others.

up to now you have only shown that storing some numbers in float variables
is not that bad if all you do, is printing them.
But that is not the usual thing you do with float, isn't it?
Usually one does some arithmetic with numbers. The more arithmetic you
do, the more things get worse.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top