string to double conversion - atof() vs istringstream

S

sharmaharish

I need a conversion function that converts values from string to a
particular type. For this I have a template function that looks like
this ...

template<class T>
T value(const string& s)
{
istringstream(s);
T val;
is >> val;
return val;
}

Now for double type the lowest positive value is 2.22507-308 and I get
different answers when I use this function vs atof() function. I am not
getting the reason here. Interestingly, if I reduce the exponent value
from -308 to -307, I get similar results.

Regards,
Harry.
 
S

sharmaharish

Forgot to mention this before. atof() behaviour is expected for -308
exp and that of istringstream is wrong.

Regards,
Harry.
 
M

mlimber

I need a conversion function that converts values from string to a
particular type. For this I have a template function that looks like
this ...

template<class T>
T value(const string& s)
{
istringstream(s);
T val;
is >> val;
return val;
}

Now for double type the lowest positive value is 2.22507-308 and I get
different answers when I use this function vs atof() function. I am not
getting the reason here. Interestingly, if I reduce the exponent value
from -308 to -307, I get similar results.

How different are the results? Floating point numbers are notoriously
tricky. See, e.g., these FAQs:

http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.16
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18

Cheers! --M
 
R

Roland Pibinger

I need a conversion function that converts values from string to a
particular type. For this I have a template function that looks like
this ...

template<class T>
T value(const string& s)
{
istringstream(s);
T val;
is >> val;
return val;
}

You don't check any return or error value in that function. Moreover,
I would prefer an explicit stringToDoulble() function to a template.
Now for double type the lowest positive value is 2.22507-308 and I get
different answers when I use this function vs atof() function. I am not
getting the reason here. Interestingly, if I reduce the exponent value
from -308 to -307, I get similar results.

Use strtod
(http://www.opengroup.org/onlinepubs/000095399/functions/strtod.html)
and check endptr, errno and return value.

Best wishes,
Roland Pibinger
 
S

sharmaharish

Roland,
stringToDouble() is definitely something that will resolve the issue,
but that is not I am looking for. I was interested in minimizing the
no. of specialized functions that I write. Moreover, I am using this
only for the intrinsic types. As for the error checking, I don't know
how I can add that with the template types without specializing it for
a certain type.

Regards,
Harish Sharma
 
S

sharmaharish

mlimber,
The difference in the values is quite large to be neglected for a
rounding error as the faq says. And anyways I am not interested in
comparing any double type no.s here. The result that I get while using
this func is 2.64167e-308 while atof() returns 2.22507e-308. I
understand that atof() has minimal functionality and that too is type
specific, whereas the istringstream (or istream) has be generic.
However, I think the precision of default 6 digits is lost somewhere
while extracting the value from the string.

Regards,
Harish Sharma
 
M

mlimber

Roland said:
You don't check any return or error value in that function.

That is a good point. Are you sure the conversion didn't abort
prematurely? Please post a *complete* but *minimal* program (see FAQ
5.8) that demonstrates your problem so we can reproduce it.

Cheers! --M
 
S

sharmaharish

#include <iostream>
#include <sstream>
#include <cstdlib>

using namespace std;

template<class T>
T value(string s)
{
istringstream(s);
T val; is >> val;
return val;
}

int
main()
{
cout << "\natof(2.22507e-308) ->" << atof("2.22507e-308");
cout << "\nvalue<double>(2.22507e-308) ->" <<
value<double>("2.22507e-308");
return 0;
}

Above is the complete demo program illustrating the problem. Actually
the value displayed by the template function is not consistent across
compilation and is sorta random (atleast I didn't see any pattern or
consistent values with every compilation). I checked the output with
MSVC as well as with GCC compiler. They give different values but
neither gives the right output.

Regards,
Harish Sharma
 
M

mlimber

#include <iostream>
#include <sstream>
#include <cstdlib>

using namespace std;

template<class T>
T value(string s)
{
istringstream(s);
T val; is >> val;
return val;
}

Try this instead:

class MyException {};

template<class T>
T value(const string& s)
{
istringstream is(s);
T val;
if( !(is >> val) || !(is >> ws).eof() )
{
throw MyException();
}
return val;
}

Or better, use boost::lexical_cast, which does basically the same thing
'cept better. I get the same answer for both with the above code:

atof(2.22507e-308) ->2.22507e-308
value said:
int
main()
{
cout << "\natof(2.22507e-308) ->" << atof("2.22507e-308");
cout << "\nvalue<double>(2.22507e-308) ->" <<
value<double>("2.22507e-308");
return 0;
}

Above is the complete demo program illustrating the problem. Actually
the value displayed by the template function is not consistent across
compilation and is sorta random (atleast I didn't see any pattern or
consistent values with every compilation). I checked the output with
MSVC as well as with GCC compiler. They give different values but
neither gives the right output.

That's probably because you forgot the variable name for the string
stream (it's using 's', which means you can't access the string that
was passed in and you have a global 'is' somewhere). GIGO.

Cheers! --M
 
S

sharmaharish

mlimber,

I tried compiling the same program with a later ver of MS C/C++
compiler, which is ...
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42
for 80x86

With this compiler the test program gives expected results. But the GCC
compiler that I am using is gcc version 3.3.1 (mingw special
20030804-1), and it still gives out garbage. And by the way I believe,
there is no garbage i/p in the test program and hence there is no
question of GIGO. Moreover, I don't think there is any need of
exception handling in the test code with the given valid input and I
don't understand how that extra piece of error checking will help. If
your compiler/lib gives you expected results with the given input, it
should behave the same without that as well.

Another simple test to confirm the problem is,

int main() { double d; cin >> d; cout << d; return 0; }

Just enter the value 2.22507-308 after compiling with your compiler and
it should show the expected result. But if you try this with the GCC
compiler version that I have mentioned, it gives out garbage. This
piece of code behaves similar to the earlier test program with both the
compilers that I used.

Lastly I tried your changes with GCC and it generates exception and
that tells me that there is some definite issue in the related version
of c++ lib that it is using.

Regards,
Harish Sharma
 
S

sharmaharish

if your compiler/lib gives you expected results with the given input, it
should behave the same without that as well.

I actually meant, if your compiler/lib gives you expected results with
the give input AND THE ERROR HANDLING CODE, it should behave the same
without that (error handling code) as well.

Regards,
Harish Sharma
 
M

mlimber

mlimber,

I tried compiling the same program with a later ver of MS C/C++
compiler, which is ...
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.42
for 80x86

With this compiler the test program gives expected results. But the GCC
compiler that I am using is gcc version 3.3.1 (mingw special
20030804-1), and it still gives out garbage. And by the way I believe,
there is no garbage i/p in the test program and hence there is no
question of GIGO.

I used g++ 3.4.4 (cygming special) to build and run this program:

#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>

using namespace std;

class MyException {};

template<class T>
T value(const string& s)
{
istringstream is(s);
T val;
if( !(is >> val) || !(is >> ws).eof() )
{
throw MyException();
}
return val;
}

int main()
{
cout << "atof(2.22507e-308) -> "
<< atof("2.22507e-308") << '\n';
try
{
cout << "value<double>(2.22507e-308) ->"
<< value<double>("2.22507e-308");
}
catch( ... )
{
cout << "Caught exception.";
}
cout << endl;
}

It gives me the expected result. If it does not for you, then it is
likely a compiler/library problem, which you should ask about on
gnu.g++.help or similar.
Moreover, I don't think there is any need of
exception handling in the test code with the given valid input and I
don't understand how that extra piece of error checking will help. If
your compiler/lib gives you expected results with the given input, it
should behave the same without that as well.

Lastly I tried your changes with GCC and it generates exception and
that tells me that there is some definite issue in the related version
of c++ lib that it is using.

The exception handling is an alternate way of handling unexpected
errors to checking return values (cf.
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.1). In
this case, exceptions provide a way to indicate a failure without
having some sort of potentially invalid value (e.g., return FLOAT_MIN
on error or a std::pair<float,bool> where the flag indicates validity)
being returned to the client, and the client can catch and handle such
an error at whatever level is appropriate. Anyway, the fact that you
get an exception seems to indicate that there was in fact an unexpected
error of some kind, so I think your claim that this sort of error
checking is unnecessary is self-defeating.

Cheers! --M
 
S

sharmaharish

Anyway, the fact that you
get an exception seems to indicate that there was in fact an unexpected
error of some kind, so I think your claim that this sort of error
checking is unnecessary is self-defeating.

*self-defeating* ?

My comment on exception handling was not general and was specific to
the test code with the given *valid* input to the program.

Regards,
Harish Sharma
 
O

Old Wolf

I need a conversion function that converts values from string to a
particular type. For this I have a template function that looks like
this ...

template<class T>
T value(const string& s)
{
istringstream(s);
T val;
is >> val;
return val;
}

Now for double type the lowest positive value is 2.22507-308 and I get
different answers when I use this function vs atof() function. I am not
getting the reason here. Interestingly, if I reduce the exponent value
from -308 to -307, I get similar results.

atof() causes undefined behaviour if the result isn't representable
as a double. Change to strtod() instead of atof(), and see if you
still get the same problem.
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,051
Latest member
CarleyMcCr

Latest Threads

Top