Проблемный вывод 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
может представлять. Помимо прочего, это означает меньший диапазон интегральных значений, которые могут быть точно представлены.
Обычное предложение не делать такие вещи. Если вы можете выполнять необходимые операции, используя целочисленные операции (например, %
) тогда сделай так. И, если вы используете с плавающей запятой, вам необходимо учитывать и управлять потерей точности, связанной с использованием с плавающей запятой.