nobs
nobs

Reputation: 730

double > string > double conversion

To transport data over the network I convert a double to string , send it and on the receiver side convert it back to double. so far so good. But I stumbled over some weird behaviour which I'm not able to explain

The whole example code can be found here. what i do: Write a double to string via ostringstream, afterwards read it in with istringstream the value changes But if i use the function "strtod(...) " it works. (with the same outstring)

Example (the whole code can be found here):

double d0 = 0.0070000000000000001;
out << d0;

std::istringstream in (out.str());
in.precision(Prec);
double d0X_ = strtod(test1.c_str(),NULL);

in >> d0_;
assert(d0 == d0X_); // this is ok
assert(d0 == d0_);   //this fails 

I wonder why this happens.

The question is: "Why is 'istream >>' leading to another resulst as 'strtod'" Please don't answer the question why IEEE 754 is no exact.

Upvotes: 1

Views: 456

Answers (1)

Mooing Duck
Mooing Duck

Reputation: 66922

Why are they might be different:
http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.16

Floating point is an approximation...

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

The reason floating point will surprise you is that float and double values are normally represented using a finite precision binary format. In other words, floating point numbers are not real numbers. For example, in your machine's floating point format it might be impossible to exactly represent the number 0.1. By way of analogy, it's impossible to exactly represent the number one third in decimal format (unless you use an infinite number of digits).... The message is that some floating point numbers cannot always be represented exactly, so comparisons don't always do what you'd like them to do. In other words, if the computer actually multiplies 10.0 by 1.0/10.0, it might not exactly get 1.0 back.

How to compare floating point:
http://c-faq.com/fp/strangefp.html

...some machines have more precision available in floating-point computation registers than in double values stored in memory, which can lead to floating-point inequalities when it would seem that two values just have to be equal.

http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17
Here's the wrong way to do it:

 void dubious(double x, double y)
 {
   ...
   if (x == y)  // Dubious!
     foo();
   ...
 }

If what you really want is to make sure they're "very close" to each other (e.g., if variable a contains the value 1.0 / 10.0 and you want to see if (10*a == 1)), you'll probably want to do something fancier than the above:

 void smarter(double x, double y)
 {
   ...
   if (isEqual(x, y))  // Smarter!
     foo();
   ...
 }

There are many ways to define the isEqual() function, including:

 #include <cmath>  /* for std::abs(double) */

 inline bool isEqual(double x, double y)
 {
   const double epsilon = /* some small number such as 1e-5 */;
   return std::abs(x - y) <= epsilon * std::abs(x);
   // see Knuth section 4.2.2 pages 217-218
 }

Note: the above solution is not completely symmetric, meaning it is possible for isEqual(x,y) != isEqual(y,x). From a practical standpoint, does not usually occur when the magnitudes of x and y are significantly larger than epsilon, but your mileage may vary.

Upvotes: 2

Related Questions