Проблемный вывод fmod (long double, long double)

Проблемный вывод fmod (long double, long double)

Похоже, что вывод fmod (long double, long double) в этом тесте является проблематичным. Какие-либо предложения?

g ++ - версия g ++ (GCC) 4.9.2

uname -srvmpio CYGWIN_NT-6.1 1.7.34 (0.285 / 5/3) 2015-02-04 12:12 i686 неизвестно неизвестно Cygwin

g ++ test1.cpp // Нет ошибок, нет предупреждений

./a.exe

l1 = 4294967296

l2 = 72057594037927934

l3 = 4294967294

d1 = 4294967296

d2 = 72057594037927934

d3 = 0 // Ожидается 4294967294

// -------- Program test1. cpp --------
#include <iostream>
#include <iomanip>
#include <cmath>

int main (int argc, char** argv)
{

  long long l1 = 4294967296;
  long long l2 = 72057594037927934;
  long long l3 = l2 % l1;

  long double d1 = static_cast<long double>(l1);
  long double d2 = static_cast<long double>(l2);
  long double d3 = fmod (d2, d1);

  std::cout << "l1 = " << l1 << std::endl;
  std::cout << "l2 = " << l2 << std::endl;
  std::cout << "l3 = " << l3 << std::endl;

  std::cout << std::endl;
  std::cout << "d1 = " << std::setprecision(18) << d1 << std::endl;
  std::cout << "d2 = " << std::setprecision(18) << d2 << std::endl;
  std::cout << "d3 = " << std::setprecision(18) << d3 << std::endl;

  return 0;

}
// -----------------------

1 ответ

Типы с плавающей точкой, в том числе long double не может представлять все интегральные значения в их диапазоне. На практике они с меньшей вероятностью будут точно поддерживать большие значения.

Следствием является то, что преобразование больших интегральных значений в long double (или любой тип с плавающей запятой) не обязательно сохраняет значение - преобразованное значение является только наиболее близким приближением, возможным с учетом ограничений типа с плавающей запятой.

Оттуда, если ваши два преобразования дали разные значения, было бы очень повезло, если бы результат fmod() было именно то значение, которое вы ищете.

fmod() также не перегружен, чтобы принять long double аргументы. Что означает ваш long double значения будут преобразованы в double, Набор значений double может представлять собой подмножество набора, который long double может представлять. Помимо прочего, это означает меньший диапазон интегральных значений, которые могут быть точно представлены.

Обычное предложение не делать такие вещи. Если вы можете выполнять необходимые операции, используя целочисленные операции (например, %) тогда сделай так. И, если вы используете с плавающей запятой, вам необходимо учитывать и управлять потерей точности, связанной с использованием с плавающей запятой.

Другие вопросы по тегам