Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

different values of std::floor function for arguments with same value but different types

Tags:

c++

logging

floor

Consider the following:

#include <iostream>
#include <cmath>
int main()
{
  using std::cout;
  using std::endl;

  const long double be2 = std::log(2);
  cout << std::log(8.0) / be2 << ", " << std::floor(std::log(8.0) / be2)
      << endl;

  cout << std::log(8.0L) / be2 << ", " << std::floor(std::log(8.0L) / be2)
      << endl;
}

Outputs

  3, 2
  3, 3

Why does the output differ? What am I missing here?

Also here is the link to codepad: http://codepad.org/baLtYrmy

And I'm using gcc 4.5 on linux, if that's important.

like image 664
user803563 Avatar asked Aug 11 '11 19:08

user803563


3 Answers

When I add this:

cout.precision(40);

I get this output:

2.999999999999999839754918906642444653698, 2
3.00000000000000010039712117215771058909, 3

You're printing two values that are very close to, but not exactly equal to, 3.0. It's the nature of std::floor that its results can differ for values that are very close together (mathematically, it's a discontinuous function).

like image 98
Keith Thompson Avatar answered Sep 26 '22 19:09

Keith Thompson


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

int main()
{
  using std::cout;
  using std::endl;

  const long double be2 = std::log(2);

  cout << setprecision (50)<<std::log(8.0)<<"\n";
  cout << setprecision (50)<<std::log(8.0L)<<"\n";
  cout << setprecision (50)<<std::log(8.0) / be2 << ", " << std::floor(std::log(8.0) / be2)
       << endl;
  cout << setprecision (50)<< std::log(8.0L) / be2 << ", " << std::floor(std::log(8.0L) / be2)
       << endl;

  return 0;
}

The output is:

2.0794415416798357476579894864698871970176696777344
2.0794415416798359282860714225549259026593063026667
2.9999999999999998397549189066424446536984760314226, 2
3.0000000000000001003971211721577105890901293605566, 3

If you check the output here, you will notice that there is a slight difference in the precision of the two outputs. These roundoff errors usually kick in on operations on float & double here while performing floor() and the results that appear are not what one feels they should be.

It is important to remember two attributes Precision & Rounding when you are working with float or double numbers.

You might want to read more about it in my answer here, the same reasoning applies here as well.

like image 21
Alok Save Avatar answered Sep 26 '22 19:09

Alok Save


To expand on what Als is saying-

In the first case you are dividing an 8-byte double precision value by a 16-byte long double. In the second case you are dividing a 16-byte long double by a 16-byte long double. This results in a very small roundoff error which can be seen here:

cout << std::setprecision(20) << (std::log(8.0) / be2) << std::endl;
cout << std::setprecision(20) << (std::log(8.0L) / be2) << std::endl;

which yields:

2.9999999999999998398
3.0000000000000001004

Edit to say: in this case, sizeof is your friend (To see the difference in precision):

sizeof(std::log(8.0));  // 8
sizeof(std::log(8.0L)); // 16
sizeof(be2);            // 16
like image 31
MarkD Avatar answered Sep 23 '22 19:09

MarkD