bottus
bottus

Reputation: 903

why my comparison between double fails c++

i'm working on a project and to finish it i need to do some comparison with double, float ... the problem is when i compare two double which are respectively the biggest value for a double and the biggest value for a double + 1, the comparison fail ... i do

if (std::max(d_max + 1.1, (d_max)) == d_max)
  std::cout << "bad" << std::endl;

the answer of the function max is d_max and "bad" is displayed ... is anyone having an idea or a solution to get a good precision with my comparison ? i checked on google but i found out more explanations than real solution to my problem ... thanks so much !

Upvotes: 0

Views: 935

Answers (2)

Joseph Mansfield
Joseph Mansfield

Reputation: 110658

All objects in C++ have a type. The type of d_max is double. The type of d_max + 1.1 is still double. If d_max is the maximum value for a double, then d_max + 1.1 is not representable and the closest representable value will be used, which is d_max (however, if you add a significantly larger value, the closest representable value is considered to be positive infinity). So your std::max call is equivalent to:

std::max(d_max, d_max)

To demonstrate:

double d_max = std::numeric_limits<double>::max();
bool b = (d_max == (d_max + 1.1));
std::cout << std::boolalpha << b << std::endl;

This gives true as output.


In response to your comment, I assume you are doing something like this:

double d_max = std::numeric_limits<double>::max();
long double ld = d_max + 1;
std::cout << (d_max == ld) << std::endl;

And strangely you find that apparently d_max and ld are equal. Why? Well d_max is a double. When you do d_max + 1, the result of the operation is also a double - the value of d_max + 1 can't be represented in a double though, as described before, so the closest representable value (d_max) is chosen. This value is then assigned to ld.

Note that this isn't likely to be fixed by just making sure the operator results in a long double (perhaps with d_max + 1.0L). At such huge numbers (around 10^308 with an IEEE 754 representation), adding 1 will not move you along to the next representable value in a long double. With my implementation, I have to add 10289 (that's 1 followed by 289 zeros) to actually cause a change in value:

double d_max = std::numeric_limits<double>::max();
long double ld = d_max + 1E289L;
std::cout << (d_max == ld) << std::endl;

Also, there is no guarantee that long double has more precision than double. The only guarantee is that it doesn't have less precision.

Upvotes: 7

leftaroundabout
leftaroundabout

Reputation: 120711

Let's pretend doubles are represented as decimal floating-point numbers, scientific notation. Then, d_max would be something like

9.999999999999999999 ⋅ 10⁹⁹

Now let's add 1.1 to that:

9.999999999999999999 ⋅ 10⁹⁹ + 1.1
= 999999999999999999900000000...000 + 1.1
= 999999999999999999900000000...001.1

round that to 20, or even 40 significant figures (which you have to as those types, even long double, have only finite information capacity) and you get...? well, d_max again.


Note that the same applies to subtraction as well, so

int main() {
  long double d_max = std::numeric_limits<double>::max();
  if(d_max == d_max - 1.1)
    std::cout << "   d_max       = " << d_max
            << "\n== d_max - 1.1 = " << d_max + 1.1 << std::endl;
  return 0;
}

outputs

   d_max       = 1.79769e+308
== d_max - 1.1 = 1.79769e+308

i.e. this really hasn't anything to do with d_max being the largest value available, but with it being so much larger than what you add to it.

Upvotes: 1

Related Questions