разные значения функции std :: floor для аргументов с одинаковым значением, но разных типов - PullRequest
5 голосов
/ 11 августа 2011

Рассмотрим следующее:

#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;
}

Выходы

  3, 2
  3, 3

Почему выход отличается? Что мне здесь не хватает?

Также вот ссылка на кодовую панель: http://codepad.org/baLtYrmy

И я использую gcc 4.5 в Linux, если это важно.

Ответы [ 3 ]

4 голосов
/ 11 августа 2011

Когда я добавляю это:

cout.precision(40);

Я получаю этот вывод:

2.999999999999999839754918906642444653698, 2
3.00000000000000010039712117215771058909, 3

Вы печатаете два значения, которые очень близки, но не совсем равны, 3,0,Природа std::floor заключается в том, что ее результаты могут различаться для значений, которые очень близки друг к другу (математически это прерывистая функция).

2 голосов
/ 11 августа 2011

Чтобы расширить то, что говорит Алс -

В первом случае вы делите 8-байтовое значение двойной точности на 16-байтовое значение double. Во втором случае вы делите 16-байтовый двойной дубль на 16-байтовый двойной. Это приводит к очень маленькой ошибке округления, которую можно увидеть здесь:

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

, что дает:

2.9999999999999998398
3.0000000000000001004

Изменить, чтобы сказать: в этом случае sizeof - ваш друг (Чтобы увидеть разницу в точности):

sizeof(std::log(8.0));  // 8
sizeof(std::log(8.0L)); // 16
sizeof(be2);            // 16
2 голосов
/ 11 августа 2011
#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;
}

Вывод:

2.0794415416798357476579894864698871970176696777344
2.0794415416798359282860714225549259026593063026667
2.9999999999999998397549189066424446536984760314226, 2
3.0000000000000001003971211721577105890901293605566, 3

Если вы проверите вывод здесь , вы заметите, что есть небольшая разница в точностииз двух выходов.Эти ошибки округления обычно включаются при операциях на float & double здесь при выполнении floor(), и результаты, которые появляются, не такие, какими, по их мнению, они должны быть.

Важно запомнить два атрибута Precision & Округление при работе с числами с плавающей запятой или двойными числами.

Возможно, вы захотите узнать больше об этом в моем ответе здесь , то же самое рассуждение применимо и здесь.

...