Как вы печатаете двойной поток, чтобы при чтении в нем вы не теряли точность?Печать двойная без потери точности
Я пробовал:
std::stringstream ss;
double v = 0.1 * 0.1;
ss << std::setprecision(std::numeric_limits<T>::digits10) << v << " ";
double u;
ss >> u;
std::cout << "precision " << ((u == v) ? "retained" : "lost") << std::endl;
Это не работает, как я ожидал.
Но я могу увеличить точность (что меня удивило, так как я считал, что цифры должны быть максимально требуемыми).
ss << std::setprecision(std::numeric_limits<T>::digits10 + 2) << v << " ";
// ^^^^^^ +2
Это связано с количеством значащих цифр, а первые два не учитываются (0,01).
Так кто-нибудь посмотрел на то, что представляли числа с плавающей запятой точно? Какое точное магическое заклинание в потоке мне нужно сделать?
После нескольких экспериментов:
Проблема была с моей оригинальной версии. В десятичной строке после десятичной точки были записаны несущественные цифры, которые влияли на точность.
Таким образом, чтобы компенсировать это, мы можем использовать научные обозначения для компенсации:
ss << std::scientific
<< std::setprecision(std::numeric_limits<double>::digits10 + 1)
<< v;
Это еще не объясняет необходимость +1, хотя.
Также, если я распечатаю номер с большей точностью, я получаю более точную распечатку!
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10) << v << "\n";
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits10 + 1) << v << "\n";
std::cout << std::scientific << std::setprecision(std::numeric_limits<double>::digits) << v << "\n";
Это приводит к:
1.000000000000000e-02
1.0000000000000002e-02
1.00000000000000019428902930940239457413554200000000000e-02
на основе @Stephen Canon ответ ниже:
Мы можем напечатать точно с помощью форматировщик Е(), "% с" или «% А». Для достижения этой цели в C++ мы должны использовать фиксированные и научные манипулятор (см N3225: 22.4.2.2.2p5 Таблицы 88)
std::cout.flags(std::ios_base::fixed | std::ios_base::scientific);
std::cout << v;
Сейчас я определил:
template<typename T>
std::ostream& precise(std::ostream& stream)
{
std::cout.flags(std::ios_base::fixed | std::ios_base::scientific);
return stream;
}
std::ostream& preciselngd(std::ostream& stream){ return precise<long double>(stream);}
std::ostream& precisedbl(std::ostream& stream) { return precise<double>(stream);}
std::ostream& preciseflt(std::ostream& stream) { return precise<float>(stream);}
Далее: Как сделать мы обрабатываем NaN/Inf?
Почему вы включаете пробел после 'v' при выводе на' ss'? – chrisaycock
@chrisaycock: Нет причин. Вырезать и вставить ошибку. –
Всегда будет потеря точности, за исключением тех значений, которые имеют двоичный деноменант. Вопрос должен быть * Сколько точности должно быть сохранено? * –