0

I recently started learning C++ from the starting and am currently studying from Bjarne Stroustrup's "Programming Principles and Practice using C++". There is an exercise to try to find the larger of two numbers inputted by the user and if they are less than 0.01 apart output "The numbers are almost equal". However the < operation I used in my if statement is working like <= for an unknown reason.

        if(num1<num2)
    {
        diff=num2-num1;
        std::cout<<"\nThe smaller value is: "<<num1;
        std::cout<<"\nThe larger value is: "<<num2;
        if(diff<0.01)
        {
            std::cout<<"\nThe numbers are almost equal";
        }
    }

If i input the numbers as 5 and 5.01 the inner if statement is triggered. But the weirder thing I noticed is that the if statement is not triggered if 64 and 64.01 are enetered. This is the case for all numbers from 64 to 127.99 after which the same error comes back.

I'm totally clueless as to what is causing this.

  • So, you know floating point on computers is in binary, right? Binary can only record in binary fractions like 1/2, 1/4th, 1/8th, etc. Notice that 0.1 is not a binary fraction. It cannot be stored as an exact number. That means your 64.01 is *probably* stored as something like 64.0100000000054 or something similar (I didn't look). – Zan Lynx Apr 24 '20 at 15:50
  • https://stackoverflow.com/questions/10334688/how-dangerous-is-it-to-compare-floating-point-values – Zan Lynx Apr 24 '20 at 15:55

1 Answers1

0

The following program with hexfloat can show you the details.

Oops, sorry, the hexfloat iomanip would look like cout << hexfloat << diff; but when you use the format flags it is the combination ios::scientific | ios::fixed.

current                       diff                          
0x0.p+0                       0x1.47ae147ae147bp-7          <-- target
0x1.47ae147ae147bp-7          0x1.47ae147ae147bp-7          
0x1.47ae147ae147bp-6          0x1.47ae147ae147bp-7          
0x1.eb851eb851eb8p-6          0x1.47ae147ae147ap-7          similar

Look at how the hexfloat output for target and the next two lines ends in b. Then the next one ends in a which is different enough to be less than target and outputs similar.

Anyway save this as cpp-double-compare.cpp and run:

make cpp-double-compare && echo 0.01 0.02 0.03 1.011 1.02 1.023 1.6 1.5 64.001 64.01 64 65 66 | ./cpp-double-compare

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

using namespace std;

int main() {
  double current = 0.0, last = 0.0;
  constexpr int width = 30;
  constexpr double target = 0.01;
  constexpr ios::fmtflags fmt =
      ios::scientific | ios::fixed | ios::left | ios::showbase | ios::showpoint;

  cout << setw(width) << left << "current";
  cout << setw(width) << left << "diff";
  cout << endl;

  cout.setf(fmt);
  cout << setw(width) << 0.0;
  cout << setw(width) << target << setw(0) << "<-- target";
  cout << endl;

  while (cin >> current) {
    double diff = fabs(current - last);
    cout << setw(width) << current;
    cout << setw(width) << diff;
    if (diff < target) {
      cout << setw(0) << "similar";
    }
    cout << endl;
    last = current;
  }
  return 0;
}
Zan Lynx
  • 53,022
  • 10
  • 79
  • 131